From 97d4a2fe193a66f5f96d7b813bed96b35b5abf15 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 16 Sep 2023 14:47:50 -0700 Subject: [PATCH] wip: migrate to bun --- .commitlintrc.js | 29 + .eslintignore | 5 + .eslintrc | 98 + .eslintrc.js | 125 - .gitattributes | 1 + .gitignore | 5 +- .husky/.gitignore | 1 + .husky/commit-msg | 4 + .husky/pre-commit | 4 + .prettierignore | 5 + .prettierrc | 6 + README.md | 18 +- bunfig.toml | 2 + debounce.js | 213 -- each.js | 1 - eachRight.js | 1 - first.js | 1 - hasPath.js | 53 - hasPathIn.js | 50 - isBuffer.js | 35 - isEmpty.js | 69 - isError.js | 30 - package-lock.json | 1697 --------- package.json | 53 +- repeat.js | 40 - sampleSize.js | 40 - shuffle.js | 33 - size.js | 43 - split.js | 42 - src/.eslintrc.cjs | 18 + .internal/Hash.js => src/.internal/Hash.ts | 0 .../.internal/ListCache.ts | 0 .../MapCache.js => src/.internal/MapCache.ts | 0 .../SetCache.js => src/.internal/SetCache.ts | 0 .internal/Stack.js => src/.internal/Stack.ts | 0 .../.internal/addMapEntry.ts | 0 .../.internal/addSetEntry.ts | 0 .../.internal/arrayEach.ts | 0 .../.internal/arrayEachRight.ts | 0 .../.internal/arrayIncludes.ts | 0 .../.internal/arrayIncludesWith.ts | 0 .../.internal/arrayLikeKeys.ts | 0 .../.internal/arrayReduce.ts | 0 .../.internal/arrayReduceRight.ts | 0 .../.internal/asciiSize.ts | 0 .../.internal/asciiToArray.ts | 0 .../.internal/assignMergeValue.ts | 0 .../.internal/assignValue.ts | 0 .../.internal/assocIndexOf.ts | 0 .../.internal/baseAssignValue.ts | 0 .../baseAt.js => src/.internal/baseAt.ts | 0 .../.internal/baseClone.ts | 0 .../.internal/baseConforms.ts | 0 .../.internal/baseConformsTo.ts | 0 .../.internal/baseDifference.ts | 0 .../baseEach.js => src/.internal/baseEach.ts | 0 .../.internal/baseEachRight.ts | 0 .../.internal/baseFindIndex.ts | 0 .../.internal/baseFindKey.ts | 0 .../.internal/baseFlatten.ts | 0 .../baseFor.js => src/.internal/baseFor.ts | 0 .../.internal/baseForOwn.ts | 0 .../.internal/baseForOwnRight.ts | 0 .../.internal/baseForRight.ts | 0 .../baseGet.js => src/.internal/baseGet.ts | 0 .../.internal/baseInRange.ts | 0 .../.internal/baseIndexOf.ts | 0 .../.internal/baseIndexOfWith.ts | 0 .../.internal/baseIntersection.ts | 0 .../.internal/baseIsEqual.ts | 0 .../.internal/baseIsEqualDeep.ts | 0 .../.internal/baseIsMatch.ts | 0 .../.internal/baseIsNaN.ts | 0 .../.internal/baseMatches.ts | 0 .../.internal/baseMatchesProperty.ts | 0 .../.internal/baseMerge.ts | 0 .../.internal/baseMergeDeep.ts | 0 .../.internal/baseOrderBy.ts | 0 .../basePick.js => src/.internal/basePick.ts | 0 .../.internal/basePickBy.ts | 0 .../.internal/baseProperty.ts | 0 .../.internal/basePropertyDeep.ts | 0 .../.internal/basePropertyOf.ts | 0 .../.internal/basePullAll.ts | 0 .../.internal/basePullAt.ts | 0 .../.internal/baseRange.ts | 0 .../.internal/baseReduce.ts | 0 .../baseSet.js => src/.internal/baseSet.ts | 0 .../.internal/baseSortBy.ts | 0 .../.internal/baseSortedIndex.ts | 0 .../.internal/baseSortedIndexBy.ts | 0 .../.internal/baseSortedUniq.ts | 0 .../baseSum.js => src/.internal/baseSum.ts | 0 .../.internal/baseToNumber.ts | 0 .../.internal/baseToString.ts | 0 .../baseUniq.js => src/.internal/baseUniq.ts | 0 .../.internal/baseUnset.ts | 0 .../.internal/baseUpdate.ts | 0 .../.internal/baseValues.ts | 0 .../.internal/baseWhile.ts | 0 .../baseXor.js => src/.internal/baseXor.ts | 0 .../.internal/baseZipObject.ts | 0 .../cacheHas.js => src/.internal/cacheHas.ts | 0 .../.internal/castArrayLikeObject.ts | 0 .../castPath.js => src/.internal/castPath.ts | 0 .../.internal/castSlice.ts | 0 .../.internal/charsEndIndex.ts | 0 .../.internal/charsStartIndex.ts | 0 .../.internal/cloneArrayBuffer.ts | 0 .../.internal/cloneBuffer.ts | 0 .../.internal/cloneDataView.ts | 0 .../.internal/cloneRegExp.ts | 0 .../.internal/cloneSymbol.ts | 0 .../.internal/cloneTypedArray.ts | 0 .../.internal/compareAscending.ts | 0 .../.internal/compareMultiple.ts | 0 .../.internal/composeArgs.ts | 0 .../.internal/composeArgsRight.ts | 0 .../.internal/copyArray.ts | 0 .../.internal/copyObject.ts | 0 .../.internal/copySymbols.ts | 0 .../.internal/copySymbolsIn.ts | 0 .../.internal/createAssigner.ts | 0 .../.internal/createCaseFirst.ts | 0 .../.internal/createMathOperation.ts | 0 .../.internal/createPadding.ts | 0 .../.internal/createRange.ts | 0 .../.internal/createRound.ts | 0 .../.internal/createSet.ts | 0 .../.internal/customDefaultsMerge.ts | 0 .../.internal/deburrLetter.ts | 0 .../.internal/equalArrays.ts | 0 .../.internal/equalByTag.ts | 0 .../.internal/equalObjects.ts | 0 .../.internal/freeGlobal.ts | 0 .../.internal/getAllKeys.ts | 0 .../.internal/getAllKeysIn.ts | 0 .../.internal/getHolder.ts | 0 .../.internal/getMatchData.ts | 0 .../.internal/getSymbols.ts | 0 .../.internal/getSymbolsIn.ts | 0 .../getTag.js => src/.internal/getTag.ts | 0 .../.internal/hasUnicode.ts | 0 .../.internal/initCloneObject.ts | 0 .../.internal/isFlattenable.ts | 0 .../isIndex.js => src/.internal/isIndex.ts | 0 .../.internal/isIterateeCall.ts | 0 .internal/isKey.js => src/.internal/isKey.ts | 0 .../.internal/isPrototype.ts | 0 .../.internal/isStrictComparable.ts | 0 .../.internal/iteratorToArray.ts | 0 .../.internal/mapToArray.ts | 0 .../.internal/matchesStrictComparable.ts | 0 .../.internal/memoizeCapped.ts | 0 .../metaMap.js => src/.internal/metaMap.ts | 0 .../.internal/nodeTypes.ts | 0 .../parent.js => src/.internal/parent.ts | 0 .../reEscape.js => src/.internal/reEscape.ts | 0 .../.internal/reEvaluate.ts | 0 .../.internal/reInterpolate.ts | 0 .internal/root.js => src/.internal/root.ts | 0 .../.internal/setToArray.ts | 0 .../.internal/setToPairs.ts | 0 .../.internal/setToString.ts | 0 .../.internal/strictIndexOf.ts | 0 .../.internal/strictLastIndexOf.ts | 0 .../.internal/stringSize.ts | 0 .../.internal/stringToArray.ts | 0 .../.internal/stringToPath.ts | 0 .internal/toKey.js => src/.internal/toKey.ts | 0 .../.internal/unicodeSize.ts | 0 .../.internal/unicodeToArray.ts | 0 .../.internal/unicodeWords.ts | 0 add.js => src/add.ts | 6 +- after.js => src/after.ts | 18 +- at.js => src/at.ts | 8 +- attempt.js => src/attempt.ts | 14 +- before.js => src/before.ts | 26 +- camelCase.js => src/camelCase.ts | 19 +- capitalize.js => src/capitalize.ts | 9 +- castArray.js => src/castArray.ts | 13 +- ceil.js => src/ceil.ts | 6 +- chunk.js => src/chunk.ts | 30 +- clamp.js => src/clamp.ts | 22 +- clone.js => src/clone.ts | 8 +- cloneDeep.js => src/cloneDeep.ts | 10 +- cloneDeepWith.js => src/cloneDeepWith.ts | 12 +- cloneWith.js => src/cloneWith.ts | 10 +- compact.js => src/compact.ts | 24 +- cond.js => src/cond.ts | 34 +- conforms.js => src/conforms.ts | 10 +- conformsTo.js => src/conformsTo.ts | 8 +- countBy.js => src/countBy.ts | 30 +- create.js => src/create.ts | 8 +- src/debounce.ts | 210 ++ deburr.js => src/deburr.ts | 29 +- defaultTo.js => src/defaultTo.ts | 4 +- defaultToAny.js => src/defaultToAny.ts | 8 +- defaults.js => src/defaults.ts | 36 +- defaultsDeep.js => src/defaultsDeep.ts | 10 +- defer.js => src/defer.ts | 10 +- delay.js => src/delay.ts | 10 +- difference.js => src/difference.ts | 14 +- differenceBy.js => src/differenceBy.ts | 24 +- differenceWith.js => src/differenceWith.ts | 29 +- divide.js => src/divide.ts | 6 +- drop.js => src/drop.ts | 14 +- dropRight.js => src/dropRight.ts | 14 +- dropRightWhile.js => src/dropRightWhile.ts | 8 +- dropWhile.js => src/dropWhile.ts | 8 +- src/each.ts | 1 + src/eachRight.ts | 1 + endsWith.js => src/endsWith.ts | 23 +- eq.js => src/eq.ts | 4 +- eqDeep.js => src/eqDeep.ts | 6 +- escape.js => src/escape.ts | 24 +- escapeRegExp.js => src/escapeRegExp.ts | 12 +- every.js => src/every.ts | 16 +- everyValue.js => src/everyValue.ts | 16 +- filter.js => src/filter.ts | 22 +- filterObject.js => src/filterObject.ts | 20 +- findKey.js => src/findKey.ts | 24 +- findLast.js => src/findLast.ts | 24 +- findLastIndex.js => src/findLastIndex.ts | 28 +- findLastKey.js => src/findLastKey.ts | 8 +- src/first.ts | 1 + flatMap.js => src/flatMap.ts | 8 +- flatMapDeep.js => src/flatMapDeep.ts | 10 +- flatMapDepth.js => src/flatMapDepth.ts | 10 +- flatten.js => src/flatten.ts | 8 +- flattenDeep.js => src/flattenDeep.ts | 10 +- flattenDepth.js => src/flattenDepth.ts | 16 +- flip.js => src/flip.ts | 14 +- floor.js => src/floor.ts | 6 +- flow.js => src/flow.ts | 30 +- flowRight.js => src/flowRight.ts | 6 +- forEach.js => src/forEach.ts | 10 +- forEachRight.js => src/forEachRight.ts | 10 +- forOwn.js => src/forOwn.ts | 6 +- forOwnRight.js => src/forOwnRight.ts | 18 +- fromEntries.js => src/fromEntries.ts | 18 +- functions.js => src/functions.ts | 10 +- get.js => src/get.ts | 8 +- groupBy.js => src/groupBy.ts | 30 +- gt.js => src/gt.ts | 12 +- gte.js => src/gte.ts | 12 +- has.js => src/has.ts | 6 +- hasIn.js => src/hasIn.ts | 4 +- src/hasPath.ts | 57 + src/hasPathIn.ts | 54 + head.js => src/head.ts | 6 +- inRange.js => src/inRange.ts | 14 +- indexOf.js => src/indexOf.ts | 24 +- initial.js => src/initial.ts | 8 +- intersection.js => src/intersection.ts | 14 +- intersectionBy.js => src/intersectionBy.ts | 28 +- .../intersectionWith.ts | 28 +- invert.js => src/invert.ts | 22 +- invertBy.js => src/invertBy.ts | 24 +- invoke.js => src/invoke.ts | 18 +- invokeMap.js => src/invokeMap.ts | 22 +- isArguments.js => src/isArguments.ts | 8 +- isArrayBuffer.js => src/isArrayBuffer.ts | 14 +- isArrayLike.js => src/isArrayLike.ts | 6 +- .../isArrayLikeObject.ts | 8 +- isBoolean.js => src/isBoolean.ts | 13 +- src/isBuffer.ts | 23 + isDate.js => src/isDate.ts | 14 +- isElement.js => src/isElement.ts | 8 +- src/isEmpty.ts | 75 + isEqualWith.js => src/isEqualWith.ts | 10 +- src/isError.ts | 35 + isFunction.js => src/isFunction.ts | 4 +- isLength.js => src/isLength.ts | 7 +- isMap.js => src/isMap.ts | 14 +- isMatch.js => src/isMatch.ts | 8 +- isMatchWith.js => src/isMatchWith.ts | 10 +- isNative.js => src/isNative.ts | 19 +- isNil.js => src/isNil.ts | 4 +- isNull.js => src/isNull.ts | 4 +- isNumber.js => src/isNumber.ts | 9 +- isObject.js => src/isObject.ts | 6 +- isObjectLike.js => src/isObjectLike.ts | 4 +- isPlainObject.js => src/isPlainObject.ts | 28 +- isRegExp.js => src/isRegExp.ts | 14 +- isSet.js => src/isSet.ts | 14 +- isString.js => src/isString.ts | 14 +- isSymbol.js => src/isSymbol.ts | 11 +- isTypedArray.js => src/isTypedArray.ts | 16 +- isUndefined.js => src/isUndefined.ts | 4 +- isWeakMap.js => src/isWeakMap.ts | 8 +- isWeakSet.js => src/isWeakSet.ts | 8 +- kebabCase.js => src/kebabCase.ts | 16 +- keyBy.js => src/keyBy.ts | 14 +- keys.js => src/keys.ts | 10 +- keysIn.js => src/keysIn.ts | 13 +- last.js => src/last.ts | 6 +- lastIndexOf.js => src/lastIndexOf.ts | 34 +- lowerCase.js => src/lowerCase.ts | 18 +- lowerFirst.js => src/lowerFirst.ts | 6 +- lt.js => src/lt.ts | 12 +- lte.js => src/lte.ts | 12 +- map.js => src/map.ts | 16 +- mapKey.js => src/mapKey.ts | 16 +- mapObject.js => src/mapObject.ts | 14 +- mapValue.js => src/mapValue.ts | 14 +- matches.js => src/matches.ts | 10 +- matchesProperty.js => src/matchesProperty.ts | 10 +- maxBy.js => src/maxBy.ts | 38 +- mean.js => src/mean.ts | 6 +- meanBy.js => src/meanBy.ts | 10 +- memoize.js => src/memoize.ts | 34 +- merge.js => src/merge.ts | 10 +- mergeWith.js => src/mergeWith.ts | 10 +- method.js => src/method.ts | 6 +- methodOf.js => src/methodOf.ts | 6 +- minBy.js => src/minBy.ts | 38 +- multiply.js => src/multiply.ts | 6 +- negate.js => src/negate.ts | 14 +- nth.js => src/nth.ts | 16 +- nthArg.js => src/nthArg.ts | 6 +- once.js => src/once.ts | 6 +- orderBy.js => src/orderBy.ts | 24 +- over.js => src/over.ts | 10 +- overArgs.js => src/overArgs.ts | 21 +- overEvery.js => src/overEvery.ts | 10 +- overSome.js => src/overSome.ts | 10 +- pad.js => src/pad.ts | 22 +- padEnd.js => src/padEnd.ts | 14 +- padStart.js => src/padStart.ts | 14 +- parseInt.js => src/parseInt.ts | 20 +- partition.js => src/partition.ts | 12 +- pick.js => src/pick.ts | 6 +- pickBy.js => src/pickBy.ts | 18 +- property.js => src/property.ts | 12 +- propertyOf.js => src/propertyOf.ts | 6 +- pull.js => src/pull.ts | 6 +- pullAll.js => src/pullAll.ts | 10 +- pullAllBy.js => src/pullAllBy.ts | 10 +- pullAllWith.js => src/pullAllWith.ts | 10 +- pullAt.js => src/pullAt.ts | 23 +- random.js => src/random.ts | 66 +- range.js => src/range.ts | 6 +- rangeRight.js => src/rangeRight.ts | 6 +- reduce.js => src/reduce.ts | 14 +- reduceRight.js => src/reduceRight.ts | 14 +- reject.js => src/reject.ts | 12 +- remove.js => src/remove.ts | 36 +- src/repeat.ts | 40 + replace.js => src/replace.ts | 6 +- result.js => src/result.ts | 38 +- round.js => src/round.ts | 6 +- sample.js => src/sample.ts | 6 +- src/sampleSize.ts | 40 + set.js => src/set.ts | 6 +- setWith.js => src/setWith.ts | 8 +- src/shuffle.ts | 33 + src/size.ts | 43 + slice.js => src/slice.ts | 44 +- snakeCase.js => src/snakeCase.ts | 16 +- some.js => src/some.ts | 16 +- someValue.js => src/someValue.ts | 16 +- sortedIndex.js => src/sortedIndex.ts | 6 +- sortedIndexBy.js => src/sortedIndexBy.ts | 6 +- sortedIndexOf.js => src/sortedIndexOf.ts | 20 +- sortedLastIndex.js => src/sortedLastIndex.ts | 6 +- .../sortedLastIndexBy.ts | 6 +- .../sortedLastIndexOf.ts | 20 +- sortedUniq.js => src/sortedUniq.ts | 8 +- sortedUniqBy.js => src/sortedUniqBy.ts | 8 +- src/split.ts | 39 + startCase.js => src/startCase.ts | 16 +- startsWith.js => src/startsWith.ts | 21 +- subtract.js => src/subtract.ts | 6 +- sum.js => src/sum.ts | 8 +- sumBy.js => src/sumBy.ts | 8 +- tail.js => src/tail.ts | 14 +- take.js => src/take.ts | 14 +- takeRight.js => src/takeRight.ts | 18 +- takeRightWhile.js => src/takeRightWhile.ts | 8 +- takeWhile.js => src/takeWhile.ts | 8 +- throttle.js => src/throttle.ts | 34 +- times.js => src/times.ts | 36 +- src/toArray.ts | 55 + toFinite.js => src/toFinite.ts | 26 +- toInteger.js => src/toInteger.ts | 10 +- toLength.js => src/toLength.ts | 28 +- src/toNumber.ts | 67 + src/toPath.ts | 29 + toPlainObject.js => src/toPlainObject.ts | 14 +- toSafeInteger.js => src/toSafeInteger.ts | 28 +- src/toString.ts | 44 + transform.js => src/transform.ts | 46 +- src/trim.ts | 38 + src/trimEnd.ts | 36 + src/trimStart.ts | 36 + src/truncate.ts | 111 + unescape.js => src/unescape.ts | 24 +- union.js => src/union.ts | 10 +- unionBy.js => src/unionBy.ts | 20 +- unionWith.js => src/unionWith.ts | 16 +- uniq.js => src/uniq.ts | 8 +- uniqBy.js => src/uniqBy.ts | 8 +- uniqWith.js => src/uniqWith.ts | 10 +- uniqueId.js => src/uniqueId.ts | 22 +- unset.js => src/unset.ts | 6 +- src/unzip.ts | 43 + unzipWith.js => src/unzipWith.ts | 16 +- update.js => src/update.ts | 6 +- updateWith.js => src/updateWith.ts | 8 +- upperCase.js => src/upperCase.ts | 16 +- upperFirst.js => src/upperFirst.ts | 6 +- values.js => src/values.ts | 8 +- without.js => src/without.ts | 8 +- words.js => src/words.ts | 22 +- xor.js => src/xor.ts | 8 +- xorBy.js => src/xorBy.ts | 18 +- xorWith.js => src/xorWith.ts | 14 +- zip.js => src/zip.ts | 6 +- zipObject.js => src/zipObject.ts | 8 +- zipObjectDeep.js => src/zipObjectDeep.ts | 8 +- zipWith.js => src/zipWith.ts | 12 +- test/.eslintrc.cjs | 22 + test/Arrays-category-methods.js | 97 - test/Arrays-category-methods.spec.ts | 123 + test/Strings-category-methods.spec.ts | 81 + test/Strings-category-methods.test.js | 83 - test/__proto__-property-bugs.js | 87 - test/__proto__-property-bugs.spec.ts | 81 + test/add.spec.ts | 15 + test/add.test.js | 15 - test/after.spec.ts | 46 + test/after.test.js | 31 - test/ary.js | 91 - test/ary.spec.ts | 89 + test/assign-and-assignIn.js | 88 - test/assign-and-assignIn.spec.ts | 106 + test/assignIn.js | 9 - test/assignIn.spec.ts | 9 + test/assignInWith.js | 9 - test/assignInWith.spec.ts | 9 + test/assignWith-and-assignInWith.js | 22 - test/assignWith-and-assignInWith.spec.ts | 22 + test/at.spec.ts | 131 + test/at.test.js | 124 - test/attempt.spec.ts | 73 + test/attempt.test.js | 55 - test/basename.js | 151 - test/basename.spec.ts | 147 + test/before.js | 31 - test/before.spec.ts | 46 + test/bind.js | 231 -- test/bind.spec.ts | 256 ++ test/bindAll.js | 74 - test/bindAll.spec.ts | 80 + test/bindKey.js | 66 - test/bindKey.spec.ts | 66 + test/camelCase.spec.ts | 28 + test/camelCase.test.js | 28 - test/capitalize.spec.ts | 10 + test/capitalize.test.js | 10 - test/case-methods.spec.ts | 133 + test/case-methods.test.js | 105 - test/castArray.spec.ts | 23 + test/castArray.test.js | 23 - test/chain.js | 74 - test/chain.spec.ts | 93 + test/chunk.spec.ts | 49 + test/chunk.test.js | 45 - test/clamp.js | 58 - test/clamp.spec.ts | 58 + test/clone-methods.js | 429 --- test/clone-methods.spec.ts | 446 +++ test/compact.js | 42 - test/compact.spec.ts | 44 + test/concat.js | 65 - test/concat.spec.ts | 57 + test/cond.js | 65 - test/cond.spec.ts | 81 + test/conforms-methods.js | 153 - test/conforms-methods.spec.ts | 172 + test/conforms.js | 15 - test/conforms.spec.ts | 21 + test/constant.js | 40 - test/constant.spec.ts | 38 + test/countBy.js | 66 - test/countBy.spec.ts | 68 + test/create.spec.ts | 100 + test/create.test.js | 99 - test/curry-methods.js | 52 - test/curry-methods.spec.ts | 53 + test/curry.js | 135 - test/curry.spec.ts | 133 + test/curryRight.js | 136 - test/curryRight.spec.ts | 134 + test/custom-_.iteratee-methods.js | 270 -- test/custom-_.iteratee-methods.spec.ts | 270 ++ test/debounce-and-throttle.js | 167 - test/debounce-and-throttle.spec.ts | 174 + test/debounce.spec.ts | 294 ++ test/debounce.test.js | 250 -- test/deburr.spec.ts | 26 + test/deburr.test.js | 28 - test/defaultTo.spec.ts | 16 + test/defaultTo.test.js | 18 - test/defaults.spec.ts | 66 + test/defaults.test.js | 66 - test/defaultsDeep.js | 101 - test/defaultsDeep.spec.ts | 101 + test/defer.spec.ts | 48 + test/defer.test.js | 40 - test/delay.js | 67 - test/delay.spec.ts | 82 + test/difference-methods.js | 85 - test/difference-methods.spec.ts | 86 + test/differenceBy.js | 23 - test/differenceBy.spec.ts | 23 + test/differenceWith.spec.ts | 29 + test/differenceWith.test.js | 26 - test/divide.spec.ts | 15 + test/divide.test.js | 15 - test/drop.spec.ts | 66 + test/drop.test.js | 62 - test/dropRight.spec.ts | 73 + test/dropRight.test.js | 62 - test/dropRightWhile.js | 52 - test/dropRightWhile.spec.ts | 48 + test/dropWhile.js | 67 - test/dropWhile.spec.ts | 67 + test/endsWith.spec.ts | 47 + test/endsWith.test.js | 49 - test/eq.spec.ts | 21 + test/eq.test.js | 21 - test/escape.spec.ts | 30 + test/escape.test.js | 30 - test/escapeRegExp.spec.ts | 28 + test/escapeRegExp.test.js | 28 - test/every.js | 74 - test/every.spec.ts | 83 + test/exit-early.js | 37 - test/exit-early.spec.ts | 51 + test/extremum-methods.js | 64 - test/extremum-methods.spec.ts | 60 + test/fill.js | 128 - test/fill.spec.ts | 139 + test/filter-methods.js | 100 - test/filter-methods.spec.ts | 123 + test/filter.spec.ts | 11 + test/filter.test.js | 11 - test/find-and-findLast.js | 22 - test/find-and-findLast.spec.ts | 28 + test/find-and-includes.js | 103 - test/find-and-includes.spec.ts | 103 + test/find-methods.js | 139 - test/find-methods.spec.ts | 151 + test/findLast.spec.ts | 92 + test/findLast.test.js | 99 - test/findLastIndex-and-lastIndexOf.spec.ts | 69 + test/findLastIndex-and-lastIndexOf.test.js | 72 - test/flatMap-methods.js | 72 - test/flatMap-methods.spec.ts | 75 + test/flatMapDepth.js | 33 - test/flatMapDepth.spec.ts | 33 + test/flatten-methods.js | 106 - test/flatten-methods.spec.ts | 104 + test/flattenDepth.js | 21 - test/flattenDepth.spec.ts | 21 + test/flip.spec.ts | 14 + test/flip.test.js | 14 - test/flow-methods.spec.ts | 51 + test/flow-methods.test.js | 53 - test/forEach.spec.ts | 9 + test/forEach.test.js | 9 - test/forEachRight.spec.ts | 9 + test/forEachRight.test.js | 9 - test/forIn-methods.js | 20 - test/forIn-methods.spec.ts | 22 + test/forOwn-methods.js | 17 - test/forOwn-methods.spec.ts | 19 + test/fromPairs.js | 47 - test/fromPairs.spec.ts | 48 + test/functions.spec.ts | 22 + test/functions.test.js | 22 - test/get-and-result.js | 148 - test/get-and-result.spec.ts | 153 + test/groupBy.js | 68 - test/groupBy.spec.ts | 90 + test/gt.spec.ts | 16 + test/gt.test.js | 16 - test/gte.spec.ts | 16 + test/gte.test.js | 16 - test/has-methods.js | 205 -- test/has-methods.spec.ts | 200 + test/head.js | 62 - test/head.spec.ts | 66 + test/identity.js | 9 - test/identity.spec.ts | 9 + test/inRange.js | 54 - test/inRange.spec.ts | 54 + test/includes.js | 95 - test/includes.spec.ts | 95 + test/indexOf-methods.js | 63 - test/indexOf-methods.spec.ts | 63 + test/indexOf.spec.ts | 54 + test/indexOf.test.js | 60 - test/initial.js | 61 - test/initial.spec.ts | 72 + test/intersection-methods.js | 91 - test/intersection-methods.spec.ts | 94 + test/intersectionBy.js | 23 - test/intersectionBy.spec.ts | 23 + test/intersectionWith.spec.ts | 36 + test/intersectionWith.test.js | 27 - test/invert.spec.ts | 30 + test/invert.test.js | 30 - test/invertBy.js | 42 - test/invertBy.spec.ts | 43 + test/invoke.js | 71 - test/invoke.spec.ts | 86 + test/invokeMap.js | 105 - test/invokeMap.spec.ts | 125 + test/isArguments.spec.ts | 38 + test/isArguments.test.js | 39 - test/isArray.js | 38 - test/isArray.spec.ts | 37 + test/isArrayBuffer.spec.ts | 40 + test/isArrayBuffer.test.js | 41 - test/isArrayLike.spec.ts | 45 + test/isArrayLike.test.js | 48 - test/isBoolean.spec.ts | 40 + test/isBoolean.test.js | 43 - test/isBuffer.spec.ts | 41 + test/isBuffer.test.js | 41 - test/isDate.spec.ts | 37 + test/isDate.test.js | 38 - test/isElement.spec.ts | 57 + test/isElement.test.js | 58 - test/isEmpty.js | 119 - test/isEmpty.spec.ts | 119 + test/isEqual.js | 700 ---- test/isEqual.spec.ts | 822 +++++ test/isEqualWith.js | 128 - test/isEqualWith.spec.ts | 134 + test/isError.spec.ts | 65 + test/isError.test.js | 70 - test/isFinite.js | 48 - test/isFinite.spec.ts | 48 + test/isFunction.js | 83 - test/isFunction.spec.ts | 81 + test/isIndex.spec.ts | 30 + test/isIndex.test.js | 34 - test/isInteger-methods.js | 55 - test/isInteger-methods.spec.ts | 49 + test/isIterateeCall.js | 47 - test/isIterateeCall.spec.ts | 47 + test/isLength.spec.ts | 22 + test/isLength.test.js | 22 - test/isMap.spec.ts | 48 + test/isMap.test.js | 53 - test/isMatchWith.js | 137 - test/isMatchWith.spec.ts | 140 + test/isNaN.js | 43 - test/isNaN.spec.ts | 38 + test/isNative.js | 92 - test/isNative.spec.ts | 101 + test/isNil.spec.ts | 42 + test/isNil.test.js | 47 - test/isNull.spec.ts | 38 + test/isNull.test.js | 41 - test/isNumber.spec.ts | 39 + test/isNumber.test.js | 42 - test/isObject.spec.ts | 52 + test/isObject.test.js | 53 - test/isObjectLike.spec.ts | 40 + test/isObjectLike.test.js | 40 - test/isPlainObject.js | 114 - test/isPlainObject.spec.ts | 114 + test/isRegExp.spec.ts | 38 + test/isRegExp.test.js | 39 - test/isSet.spec.ts | 48 + test/isSet.test.js | 53 - test/isString.spec.ts | 38 + test/isString.test.js | 41 - test/isSymbol.spec.ts | 40 + test/isSymbol.test.js | 41 - test/isType-checks.js | 39 - test/isType-checks.spec.ts | 69 + test/isTypedArray.js | 59 - test/isTypedArray.spec.ts | 54 + test/isUndefined.spec.ts | 42 + test/isUndefined.test.js | 45 - test/isWeakMap.spec.ts | 50 + test/isWeakMap.test.js | 53 - test/isWeakSet.spec.ts | 41 + test/isWeakSet.test.js | 42 - test/iteratee.js | 164 - test/iteratee.spec.ts | 161 + test/iteration-methods.js | 340 -- test/iteration-methods.spec.ts | 359 ++ test/join.js | 20 - test/join.spec.ts | 20 + test/keyBy.js | 76 - test/keyBy.spec.ts | 76 + test/keys-methods.js | 183 - test/keys-methods.spec.ts | 192 + test/last.js | 51 - test/last.spec.ts | 55 + ...-methods-that-return-new-wrapped-values.js | 45 - ...ods-that-return-new-wrapped-values.spec.ts | 45 + ...-that-return-the-wrapped-modified-array.js | 22 - ...-return-the-wrapped-modified-array.spec.ts | 17 + ....)-methods-that-return-unwrapped-values.js | 112 - ...thods-that-return-unwrapped-values.spec.ts | 112 + test/lodash(...).commit.js | 21 - test/lodash(...).commit.spec.ts | 21 + test/lodash(...).next.js | 74 - test/lodash(...).next.spec.ts | 93 + test/lodash(...).plant.js | 39 - test/lodash(...).plant.spec.ts | 39 + test/lodash(...).pop.js | 31 - test/lodash(...).pop.spec.ts | 31 + test/lodash(...).push.js | 27 - test/lodash(...).push.spec.ts | 27 + test/lodash(...).shift.js | 31 - test/lodash(...).shift.spec.ts | 31 + test/lodash(...).sort.js | 27 - test/lodash(...).sort.spec.ts | 27 + test/lodash(...).splice.js | 31 - test/lodash(...).splice.spec.ts | 31 + test/lodash(...).unshift.js | 27 - test/lodash(...).unshift.spec.ts | 27 + test/lodash(...).value.js | 33 - test/lodash(...).value.spec.ts | 33 + test/lodash-constructor.js | 39 - test/lodash-constructor.spec.ts | 39 + test/lodash-methods.js | 194 - test/lodash-methods.spec.ts | 218 ++ test/lodash.methodName.js | 75 - test/lodash.methodName.spec.ts | 86 + test/lowerCase.spec.ts | 10 + test/lowerCase.test.js | 10 - test/lowerFirst.spec.ts | 10 + test/lowerFirst.test.js | 10 - test/lt.spec.ts | 16 + test/lt.test.js | 16 - test/lte.spec.ts | 17 + test/lte.test.js | 17 - test/map-caches.js | 63 - test/map-caches.spec.ts | 61 + test/map.js | 122 - test/map.spec.ts | 141 + test/mapKeys-and-mapValues.js | 36 - test/mapKeys-and-mapValues.spec.ts | 36 + test/mapKeys.js | 35 - test/mapKeys.spec.ts | 35 + test/mapValues.js | 36 - test/mapValues.spec.ts | 36 + test/matches-methods.js | 294 -- test/matches-methods.spec.ts | 311 ++ test/matches.js | 32 - test/matches.spec.ts | 28 + test/matchesProperty.js | 368 -- test/matchesProperty.spec.ts | 395 ++ test/math-operator-methods.js | 56 - test/math-operator-methods.spec.ts | 63 + test/max.js | 27 - test/max.spec.ts | 27 + test/mean.spec.ts | 18 + test/mean.test.js | 18 - test/meanBy.js | 31 - test/meanBy.spec.ts | 29 + test/memoize.spec.ts | 176 + test/memoize.test.js | 178 - test/memoizeCapped.spec.ts | 21 + test/memoizeCapped.test.js | 21 - test/merge.spec.ts | 354 ++ test/merge.test.js | 350 -- test/mergeWith.js | 64 - test/mergeWith.spec.ts | 61 + test/method.js | 132 - test/method.spec.ts | 147 + test/methodOf.js | 131 - test/methodOf.spec.ts | 146 + test/methods-using-createWrapper.js | 198 - test/methods-using-createWrapper.spec.ts | 210 ++ test/min.js | 27 - test/min.spec.ts | 27 + test/mixin.js | 189 - test/mixin.spec.ts | 193 + test/multiply.spec.ts | 15 + test/multiply.test.js | 15 - test/negate.js | 39 - test/negate.spec.ts | 50 + test/noConflict.js | 33 - test/noConflict.spec.ts | 33 + test/now.js | 26 - test/now.spec.ts | 26 + test/nth.js | 69 - test/nth.spec.ts | 59 + test/nthArg.js | 65 - test/nthArg.spec.ts | 65 + test/number-coercion-methods.js | 248 -- test/number-coercion-methods.spec.ts | 261 ++ test/object-assignments.js | 180 - test/object-assignments.spec.ts | 209 ++ test/omit-methods.js | 114 - test/omit-methods.spec.ts | 112 + test/omit.js | 69 - test/omit.spec.ts | 69 + test/omitBy.js | 14 - test/omitBy.spec.ts | 12 + test/once.spec.ts | 36 + test/once.test.js | 36 - test/orderBy.js | 61 - test/orderBy.spec.ts | 69 + test/over.js | 58 - test/over.spec.ts | 68 + test/overArgs.js | 82 - test/overArgs.spec.ts | 90 + test/overEvery.js | 87 - test/overEvery.spec.ts | 103 + test/overSome.js | 98 - test/overSome.spec.ts | 123 + test/pad-methods.js | 51 - test/pad-methods.spec.ts | 49 + test/pad.js | 35 - test/pad.spec.ts | 33 + test/padEnd.js | 34 - test/padEnd.spec.ts | 32 + test/padStart.js | 34 - test/padStart.spec.ts | 32 + test/parseInt.js | 81 - test/parseInt.spec.ts | 73 + test/partial-methods.js | 113 - test/partial-methods.spec.ts | 125 + test/partialRight.js | 18 - test/partialRight.spec.ts | 18 + test/partition.js | 48 - test/partition.spec.ts | 48 + test/pick-methods.js | 85 - test/pick-methods.spec.ts | 83 + test/pick.js | 52 - test/pick.spec.ts | 52 + test/pickBy.spec.ts | 20 + test/pickBy.test.js | 22 - test/property.spec.ts | 125 + test/property.test.js | 122 - test/propertyOf.spec.ts | 125 + test/propertyOf.test.js | 122 - test/pull-methods.js | 49 - test/pull-methods.spec.ts | 47 + test/pullAll.spec.ts | 11 + test/pullAll.test.js | 11 - test/pullAllBy.spec.ts | 24 + test/pullAllBy.test.js | 26 - test/pullAllWith.spec.ts | 17 + test/pullAllWith.test.js | 13 - test/pullAt.js | 122 - test/pullAt.spec.ts | 126 + test/random.js | 104 - test/random.spec.ts | 101 + test/range-methods.js | 82 - test/range-methods.spec.ts | 76 + test/rearg.js | 70 - test/rearg.spec.ts | 70 + test/reduce-methods.js | 68 - test/reduce-methods.spec.ts | 66 + test/reduce.js | 57 - test/reduce.spec.ts | 61 + test/reduceRight.js | 56 - test/reduceRight.spec.ts | 60 + test/reject.spec.ts | 11 + test/reject.test.js | 11 - test/remove.js | 80 - test/remove.spec.ts | 84 + test/repeat.js | 46 - test/repeat.spec.ts | 44 + test/replace.spec.ts | 10 + test/replace.test.js | 10 - test/rest.js | 49 - test/rest.spec.ts | 49 + test/result.spec.ts | 40 + test/result.test.js | 33 - test/reverse.js | 94 - test/reverse.spec.ts | 100 + test/round-methods.js | 82 - test/round-methods.spec.ts | 86 + test/runInContext.js | 29 - test/runInContext.spec.ts | 33 + test/sample.js | 32 - test/sample.spec.ts | 32 + test/sampleSize.js | 76 - test/sampleSize.spec.ts | 74 + test/set-methods.js | 172 - test/set-methods.spec.ts | 185 + test/setWith.js | 19 - test/setWith.spec.ts | 19 + test/shuffle.js | 29 - test/shuffle.spec.ts | 30 + test/size.spec.ts | 75 + test/size.test.js | 75 - test/slice-and-toArray.js | 43 - test/slice-and-toArray.spec.ts | 43 + test/slice.js | 133 - test/slice.spec.ts | 133 + test/some.js | 76 - test/some.spec.ts | 85 + test/sortBy-methods.js | 87 - test/sortBy-methods.spec.ts | 112 + test/sortBy.js | 75 - test/sortBy.spec.ts | 100 + test/sortedIndex-methods.js | 84 - test/sortedIndex-methods.spec.ts | 85 + test/sortedIndexBy-methods.js | 59 - test/sortedIndexBy-methods.spec.ts | 61 + test/sortedIndexOf-methods.js | 15 - test/sortedIndexOf-methods.spec.ts | 15 + test/sortedUniq.spec.ts | 20 + test/sortedUniq.test.js | 13 - test/split.js | 35 - test/split.spec.ts | 33 + test/spread.js | 58 - test/spread.spec.ts | 58 + test/startCase.spec.ts | 10 + test/startCase.test.js | 10 - test/startsWith-and-endsWith.js | 38 - test/startsWith-and-endsWith.spec.ts | 39 + test/startsWith.js | 47 - test/startsWith.spec.ts | 45 + test/strict-mode-checks.js | 22 - test/strict-mode-checks.spec.ts | 27 + test/stub-methods.js | 32 - test/stub-methods.spec.ts | 35 + test/subtract.spec.ts | 15 + test/subtract.test.js | 15 - test/sum-methods.js | 36 - test/sum-methods.spec.ts | 34 + test/sumBy.js | 32 - test/sumBy.spec.ts | 30 + test/tail.js | 77 - test/tail.spec.ts | 90 + test/take.js | 65 - test/take.spec.ts | 83 + test/takeRight.js | 65 - test/takeRight.spec.ts | 71 + test/takeRightWhile.js | 96 - test/takeRightWhile.spec.ts | 115 + test/takeWhile.js | 102 - test/takeWhile.spec.ts | 121 + test/tap.js | 30 - test/tap.spec.ts | 30 + test/template.js | 451 --- test/template.spec.ts | 465 +++ test/throttle.js | 227 -- test/throttle.spec.ts | 261 ++ test/times.js | 62 - test/times.spec.ts | 59 + test/toArray.spec.ts | 51 + test/toArray.test.js | 48 - test/toInteger-methods.js | 25 - test/toInteger-methods.spec.ts | 25 + test/toLength.spec.ts | 22 + test/toLength.test.js | 22 - test/toLower.js | 10 - test/toLower.spec.ts | 10 + test/toPairs-methods.js | 61 - test/toPairs-methods.spec.ts | 84 + test/toPairs.js | 9 - test/toPairs.spec.ts | 9 + test/toPairsIn.js | 9 - test/toPairsIn.spec.ts | 9 + test/toPath.js | 66 - test/toPath.spec.ts | 66 + test/toPlainObject.js | 30 - test/toPlainObject.spec.ts | 30 + test/toString.spec.ts | 43 + test/toString.test.js | 43 - test/toUpper.js | 10 - test/toUpper.spec.ts | 10 + test/transform.js | 205 -- test/transform.spec.ts | 206 ++ test/trim-methods.js | 83 - test/trim-methods.spec.ts | 83 + test/truncate.js | 64 - test/truncate.spec.ts | 85 + test/unary.js | 27 - test/unary.spec.ts | 29 + test/uncommon-symbols.js | 170 - test/uncommon-symbols.spec.ts | 184 + test/unescape.js | 40 - test/unescape.spec.ts | 40 + test/union-methods.js | 31 - test/union-methods.spec.ts | 31 + test/unionBy.js | 28 - test/unionBy.spec.ts | 28 + test/unionWith.spec.ts | 28 + test/unionWith.test.js | 24 - test/uniq-methods.js | 123 - test/uniq-methods.spec.ts | 131 + test/uniq.js | 11 - test/uniq.spec.ts | 17 + test/uniqBy-methods.js | 74 - test/uniqBy-methods.spec.ts | 72 + test/uniqWith.spec.ts | 32 + test/uniqWith.test.js | 28 - test/uniqueId.spec.ts | 20 + test/uniqueId.test.js | 22 - test/unset.js | 119 - test/unset.spec.ts | 124 + test/unzip-and-zip.js | 72 - test/unzip-and-zip.spec.ts | 93 + test/unzipWith.js | 39 - test/unzipWith.spec.ts | 50 + test/update-methods.js | 25 - test/update-methods.spec.ts | 25 + test/updateWith.js | 19 - test/updateWith.spec.ts | 19 + test/upperCase.spec.ts | 10 + test/upperCase.test.js | 10 - test/upperFirst.spec.ts | 10 + test/upperFirst.test.js | 10 - test/utils.js | 799 ---- test/utils.ts | 1357 +++++++ test/values-methods.js | 47 - test/values-methods.spec.ts | 47 + test/without.spec.ts | 23 + test/without.test.js | 23 - test/words.spec.ts | 127 + test/words.test.js | 117 - test/wrap.js | 46 - test/wrap.spec.ts | 44 + test/xor-methods.js | 70 - test/xor-methods.spec.ts | 72 + test/xorBy.js | 23 - test/xorBy.spec.ts | 23 + test/xorWith.spec.ts | 19 + test/xorWith.test.js | 13 - test/zipObject-methods.js | 39 - test/zipObject-methods.spec.ts | 43 + test/zipWith.js | 48 - test/zipWith.spec.ts | 44 + toArray.js | 55 - toNumber.js | 65 - toPath.js | 29 - toString.js | 44 - trim.js | 38 - trimEnd.js | 36 - trimStart.js | 36 - truncate.js | 113 - tsconfig.json | 16 + unzip.js | 43 - yarn.lock | 3233 +++++++++++++++++ 1052 files changed, 30244 insertions(+), 26856 deletions(-) create mode 100644 .commitlintrc.js create mode 100644 .eslintignore create mode 100644 .eslintrc delete mode 100644 .eslintrc.js create mode 100644 .husky/.gitignore create mode 100755 .husky/commit-msg create mode 100755 .husky/pre-commit create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 bunfig.toml delete mode 100644 debounce.js delete mode 100644 each.js delete mode 100644 eachRight.js delete mode 100644 first.js delete mode 100644 hasPath.js delete mode 100644 hasPathIn.js delete mode 100644 isBuffer.js delete mode 100644 isEmpty.js delete mode 100644 isError.js delete mode 100644 package-lock.json delete mode 100644 repeat.js delete mode 100644 sampleSize.js delete mode 100644 shuffle.js delete mode 100644 size.js delete mode 100644 split.js create mode 100644 src/.eslintrc.cjs rename .internal/Hash.js => src/.internal/Hash.ts (100%) rename .internal/ListCache.js => src/.internal/ListCache.ts (100%) rename .internal/MapCache.js => src/.internal/MapCache.ts (100%) rename .internal/SetCache.js => src/.internal/SetCache.ts (100%) rename .internal/Stack.js => src/.internal/Stack.ts (100%) rename .internal/addMapEntry.js => src/.internal/addMapEntry.ts (100%) rename .internal/addSetEntry.js => src/.internal/addSetEntry.ts (100%) rename .internal/arrayEach.js => src/.internal/arrayEach.ts (100%) rename .internal/arrayEachRight.js => src/.internal/arrayEachRight.ts (100%) rename .internal/arrayIncludes.js => src/.internal/arrayIncludes.ts (100%) rename .internal/arrayIncludesWith.js => src/.internal/arrayIncludesWith.ts (100%) rename .internal/arrayLikeKeys.js => src/.internal/arrayLikeKeys.ts (100%) rename .internal/arrayReduce.js => src/.internal/arrayReduce.ts (100%) rename .internal/arrayReduceRight.js => src/.internal/arrayReduceRight.ts (100%) rename .internal/asciiSize.js => src/.internal/asciiSize.ts (100%) rename .internal/asciiToArray.js => src/.internal/asciiToArray.ts (100%) rename .internal/assignMergeValue.js => src/.internal/assignMergeValue.ts (100%) rename .internal/assignValue.js => src/.internal/assignValue.ts (100%) rename .internal/assocIndexOf.js => src/.internal/assocIndexOf.ts (100%) rename .internal/baseAssignValue.js => src/.internal/baseAssignValue.ts (100%) rename .internal/baseAt.js => src/.internal/baseAt.ts (100%) rename .internal/baseClone.js => src/.internal/baseClone.ts (100%) rename .internal/baseConforms.js => src/.internal/baseConforms.ts (100%) rename .internal/baseConformsTo.js => src/.internal/baseConformsTo.ts (100%) rename .internal/baseDifference.js => src/.internal/baseDifference.ts (100%) rename .internal/baseEach.js => src/.internal/baseEach.ts (100%) rename .internal/baseEachRight.js => src/.internal/baseEachRight.ts (100%) rename .internal/baseFindIndex.js => src/.internal/baseFindIndex.ts (100%) rename .internal/baseFindKey.js => src/.internal/baseFindKey.ts (100%) rename .internal/baseFlatten.js => src/.internal/baseFlatten.ts (100%) rename .internal/baseFor.js => src/.internal/baseFor.ts (100%) rename .internal/baseForOwn.js => src/.internal/baseForOwn.ts (100%) rename .internal/baseForOwnRight.js => src/.internal/baseForOwnRight.ts (100%) rename .internal/baseForRight.js => src/.internal/baseForRight.ts (100%) rename .internal/baseGet.js => src/.internal/baseGet.ts (100%) rename .internal/baseInRange.js => src/.internal/baseInRange.ts (100%) rename .internal/baseIndexOf.js => src/.internal/baseIndexOf.ts (100%) rename .internal/baseIndexOfWith.js => src/.internal/baseIndexOfWith.ts (100%) rename .internal/baseIntersection.js => src/.internal/baseIntersection.ts (100%) rename .internal/baseIsEqual.js => src/.internal/baseIsEqual.ts (100%) rename .internal/baseIsEqualDeep.js => src/.internal/baseIsEqualDeep.ts (100%) rename .internal/baseIsMatch.js => src/.internal/baseIsMatch.ts (100%) rename .internal/baseIsNaN.js => src/.internal/baseIsNaN.ts (100%) rename .internal/baseMatches.js => src/.internal/baseMatches.ts (100%) rename .internal/baseMatchesProperty.js => src/.internal/baseMatchesProperty.ts (100%) rename .internal/baseMerge.js => src/.internal/baseMerge.ts (100%) rename .internal/baseMergeDeep.js => src/.internal/baseMergeDeep.ts (100%) rename .internal/baseOrderBy.js => src/.internal/baseOrderBy.ts (100%) rename .internal/basePick.js => src/.internal/basePick.ts (100%) rename .internal/basePickBy.js => src/.internal/basePickBy.ts (100%) rename .internal/baseProperty.js => src/.internal/baseProperty.ts (100%) rename .internal/basePropertyDeep.js => src/.internal/basePropertyDeep.ts (100%) rename .internal/basePropertyOf.js => src/.internal/basePropertyOf.ts (100%) rename .internal/basePullAll.js => src/.internal/basePullAll.ts (100%) rename .internal/basePullAt.js => src/.internal/basePullAt.ts (100%) rename .internal/baseRange.js => src/.internal/baseRange.ts (100%) rename .internal/baseReduce.js => src/.internal/baseReduce.ts (100%) rename .internal/baseSet.js => src/.internal/baseSet.ts (100%) rename .internal/baseSortBy.js => src/.internal/baseSortBy.ts (100%) rename .internal/baseSortedIndex.js => src/.internal/baseSortedIndex.ts (100%) rename .internal/baseSortedIndexBy.js => src/.internal/baseSortedIndexBy.ts (100%) rename .internal/baseSortedUniq.js => src/.internal/baseSortedUniq.ts (100%) rename .internal/baseSum.js => src/.internal/baseSum.ts (100%) rename .internal/baseToNumber.js => src/.internal/baseToNumber.ts (100%) rename .internal/baseToString.js => src/.internal/baseToString.ts (100%) rename .internal/baseUniq.js => src/.internal/baseUniq.ts (100%) rename .internal/baseUnset.js => src/.internal/baseUnset.ts (100%) rename .internal/baseUpdate.js => src/.internal/baseUpdate.ts (100%) rename .internal/baseValues.js => src/.internal/baseValues.ts (100%) rename .internal/baseWhile.js => src/.internal/baseWhile.ts (100%) rename .internal/baseXor.js => src/.internal/baseXor.ts (100%) rename .internal/baseZipObject.js => src/.internal/baseZipObject.ts (100%) rename .internal/cacheHas.js => src/.internal/cacheHas.ts (100%) rename .internal/castArrayLikeObject.js => src/.internal/castArrayLikeObject.ts (100%) rename .internal/castPath.js => src/.internal/castPath.ts (100%) rename .internal/castSlice.js => src/.internal/castSlice.ts (100%) rename .internal/charsEndIndex.js => src/.internal/charsEndIndex.ts (100%) rename .internal/charsStartIndex.js => src/.internal/charsStartIndex.ts (100%) rename .internal/cloneArrayBuffer.js => src/.internal/cloneArrayBuffer.ts (100%) rename .internal/cloneBuffer.js => src/.internal/cloneBuffer.ts (100%) rename .internal/cloneDataView.js => src/.internal/cloneDataView.ts (100%) rename .internal/cloneRegExp.js => src/.internal/cloneRegExp.ts (100%) rename .internal/cloneSymbol.js => src/.internal/cloneSymbol.ts (100%) rename .internal/cloneTypedArray.js => src/.internal/cloneTypedArray.ts (100%) rename .internal/compareAscending.js => src/.internal/compareAscending.ts (100%) rename .internal/compareMultiple.js => src/.internal/compareMultiple.ts (100%) rename .internal/composeArgs.js => src/.internal/composeArgs.ts (100%) rename .internal/composeArgsRight.js => src/.internal/composeArgsRight.ts (100%) rename .internal/copyArray.js => src/.internal/copyArray.ts (100%) rename .internal/copyObject.js => src/.internal/copyObject.ts (100%) rename .internal/copySymbols.js => src/.internal/copySymbols.ts (100%) rename .internal/copySymbolsIn.js => src/.internal/copySymbolsIn.ts (100%) rename .internal/createAssigner.js => src/.internal/createAssigner.ts (100%) rename .internal/createCaseFirst.js => src/.internal/createCaseFirst.ts (100%) rename .internal/createMathOperation.js => src/.internal/createMathOperation.ts (100%) rename .internal/createPadding.js => src/.internal/createPadding.ts (100%) rename .internal/createRange.js => src/.internal/createRange.ts (100%) rename .internal/createRound.js => src/.internal/createRound.ts (100%) rename .internal/createSet.js => src/.internal/createSet.ts (100%) rename .internal/customDefaultsMerge.js => src/.internal/customDefaultsMerge.ts (100%) rename .internal/deburrLetter.js => src/.internal/deburrLetter.ts (100%) rename .internal/equalArrays.js => src/.internal/equalArrays.ts (100%) rename .internal/equalByTag.js => src/.internal/equalByTag.ts (100%) rename .internal/equalObjects.js => src/.internal/equalObjects.ts (100%) rename .internal/freeGlobal.js => src/.internal/freeGlobal.ts (100%) rename .internal/getAllKeys.js => src/.internal/getAllKeys.ts (100%) rename .internal/getAllKeysIn.js => src/.internal/getAllKeysIn.ts (100%) rename .internal/getHolder.js => src/.internal/getHolder.ts (100%) rename .internal/getMatchData.js => src/.internal/getMatchData.ts (100%) rename .internal/getSymbols.js => src/.internal/getSymbols.ts (100%) rename .internal/getSymbolsIn.js => src/.internal/getSymbolsIn.ts (100%) rename .internal/getTag.js => src/.internal/getTag.ts (100%) rename .internal/hasUnicode.js => src/.internal/hasUnicode.ts (100%) rename .internal/initCloneObject.js => src/.internal/initCloneObject.ts (100%) rename .internal/isFlattenable.js => src/.internal/isFlattenable.ts (100%) rename .internal/isIndex.js => src/.internal/isIndex.ts (100%) rename .internal/isIterateeCall.js => src/.internal/isIterateeCall.ts (100%) rename .internal/isKey.js => src/.internal/isKey.ts (100%) rename .internal/isPrototype.js => src/.internal/isPrototype.ts (100%) rename .internal/isStrictComparable.js => src/.internal/isStrictComparable.ts (100%) rename .internal/iteratorToArray.js => src/.internal/iteratorToArray.ts (100%) rename .internal/mapToArray.js => src/.internal/mapToArray.ts (100%) rename .internal/matchesStrictComparable.js => src/.internal/matchesStrictComparable.ts (100%) rename .internal/memoizeCapped.js => src/.internal/memoizeCapped.ts (100%) rename .internal/metaMap.js => src/.internal/metaMap.ts (100%) rename .internal/nodeTypes.js => src/.internal/nodeTypes.ts (100%) rename .internal/parent.js => src/.internal/parent.ts (100%) rename .internal/reEscape.js => src/.internal/reEscape.ts (100%) rename .internal/reEvaluate.js => src/.internal/reEvaluate.ts (100%) rename .internal/reInterpolate.js => src/.internal/reInterpolate.ts (100%) rename .internal/root.js => src/.internal/root.ts (100%) rename .internal/setToArray.js => src/.internal/setToArray.ts (100%) rename .internal/setToPairs.js => src/.internal/setToPairs.ts (100%) rename .internal/setToString.js => src/.internal/setToString.ts (100%) rename .internal/strictIndexOf.js => src/.internal/strictIndexOf.ts (100%) rename .internal/strictLastIndexOf.js => src/.internal/strictLastIndexOf.ts (100%) rename .internal/stringSize.js => src/.internal/stringSize.ts (100%) rename .internal/stringToArray.js => src/.internal/stringToArray.ts (100%) rename .internal/stringToPath.js => src/.internal/stringToPath.ts (100%) rename .internal/toKey.js => src/.internal/toKey.ts (100%) rename .internal/unicodeSize.js => src/.internal/unicodeSize.ts (100%) rename .internal/unicodeToArray.js => src/.internal/unicodeToArray.ts (100%) rename .internal/unicodeWords.js => src/.internal/unicodeWords.ts (100%) rename add.js => src/add.ts (91%) rename after.js => src/after.ts (72%) rename at.js => src/at.ts (79%) rename attempt.js => src/attempt.ts (78%) rename before.js => src/before.ts (66%) rename camelCase.js => src/camelCase.ts (56%) rename capitalize.js => src/capitalize.ts (75%) rename castArray.js => src/castArray.ts (78%) rename ceil.js => src/ceil.ts (80%) rename chunk.js => src/chunk.ts (54%) rename clamp.js => src/clamp.ts (56%) rename clone.js => src/clone.ts (86%) rename cloneDeep.js => src/cloneDeep.ts (71%) rename cloneDeepWith.js => src/cloneDeepWith.ts (73%) rename cloneWith.js => src/cloneWith.ts (78%) rename compact.js => src/compact.ts (61%) rename cond.js => src/cond.ts (59%) rename conforms.js => src/conforms.ts (77%) rename conformsTo.js => src/conformsTo.ts (79%) rename countBy.js => src/countBy.ts (62%) rename create.js => src/create.ts (78%) create mode 100644 src/debounce.ts rename deburr.js => src/deburr.ts (58%) rename defaultTo.js => src/defaultTo.ts (83%) rename defaultToAny.js => src/defaultToAny.ts (77%) rename defaults.js => src/defaults.ts (55%) rename defaultsDeep.js => src/defaultsDeep.ts (77%) rename defer.js => src/defer.ts (75%) rename delay.js => src/delay.ts (76%) rename difference.js => src/difference.ts (68%) rename differenceBy.js => src/differenceBy.ts (62%) rename differenceWith.js => src/differenceWith.ts (59%) rename divide.js => src/divide.ts (89%) rename drop.js => src/drop.ts (64%) rename dropRight.js => src/dropRight.ts (62%) rename dropRightWhile.js => src/dropRightWhile.ts (80%) rename dropWhile.js => src/dropWhile.ts (81%) create mode 100644 src/each.ts create mode 100644 src/eachRight.ts rename endsWith.js => src/endsWith.ts (60%) rename eq.js => src/eq.ts (88%) rename eqDeep.js => src/eqDeep.ts (88%) rename escape.js => src/escape.ts (76%) rename escapeRegExp.js => src/escapeRegExp.ts (70%) rename every.js => src/every.ts (77%) rename everyValue.js => src/everyValue.ts (78%) rename filter.js => src/filter.ts (70%) rename filterObject.js => src/filterObject.ts (72%) rename findKey.js => src/findKey.ts (72%) rename findLast.js => src/findLast.ts (54%) rename findLastIndex.js => src/findLastIndex.ts (61%) rename findLastKey.js => src/findLastKey.ts (78%) create mode 100644 src/first.ts rename flatMap.js => src/flatMap.ts (81%) rename flatMapDeep.js => src/flatMapDeep.ts (77%) rename flatMapDepth.js => src/flatMapDepth.ts (76%) rename flatten.js => src/flatten.ts (67%) rename flattenDeep.js => src/flattenDeep.ts (65%) rename flattenDepth.js => src/flattenDepth.ts (66%) rename flip.js => src/flip.ts (66%) rename floor.js => src/floor.ts (77%) rename flow.js => src/flow.ts (55%) rename flowRight.js => src/flowRight.ts (84%) rename forEach.js => src/forEach.ts (81%) rename forEachRight.js => src/forEachRight.ts (68%) rename forOwn.js => src/forOwn.ts (85%) rename forOwnRight.js => src/forOwnRight.ts (73%) rename fromEntries.js => src/fromEntries.ts (63%) rename functions.js => src/functions.ts (74%) rename get.js => src/get.ts (78%) rename groupBy.js => src/groupBy.ts (60%) rename gt.js => src/gt.ts (71%) rename gte.js => src/gte.ts (72%) rename has.js => src/has.ts (79%) rename hasIn.js => src/hasIn.ts (86%) create mode 100644 src/hasPath.ts create mode 100644 src/hasPathIn.ts rename head.js => src/head.ts (77%) rename inRange.js => src/inRange.ts (81%) rename indexOf.js => src/indexOf.ts (64%) rename initial.js => src/initial.ts (63%) rename intersection.js => src/intersection.ts (69%) rename intersectionBy.js => src/intersectionBy.ts (62%) rename intersectionWith.js => src/intersectionWith.ts (62%) rename invert.js => src/invert.ts (58%) rename invertBy.js => src/invertBy.ts (68%) rename invoke.js => src/invoke.ts (56%) rename invokeMap.js => src/invokeMap.ts (66%) rename isArguments.js => src/isArguments.ts (66%) rename isArrayBuffer.js => src/isArrayBuffer.ts (54%) rename isArrayLike.js => src/isArrayLike.ts (80%) rename isArrayLikeObject.js => src/isArrayLikeObject.ts (74%) rename isBoolean.js => src/isBoolean.ts (57%) create mode 100644 src/isBuffer.ts rename isDate.js => src/isDate.ts (54%) rename isElement.js => src/isElement.ts (62%) create mode 100644 src/isEmpty.ts rename isEqualWith.js => src/isEqualWith.ts (75%) create mode 100644 src/isError.ts rename isFunction.js => src/isFunction.ts (88%) rename isLength.js => src/isLength.ts (78%) rename isMap.js => src/isMap.ts (53%) rename isMatch.js => src/isMatch.ts (79%) rename isMatchWith.js => src/isMatchWith.ts (78%) rename isNative.js => src/isNative.ts (56%) rename isNil.js => src/isNil.ts (87%) rename isNull.js => src/isNull.ts (85%) rename isNumber.js => src/isNumber.ts (73%) rename isObject.js => src/isObject.ts (81%) rename isObjectLike.js => src/isObjectLike.ts (85%) rename isPlainObject.js => src/isPlainObject.ts (55%) rename isRegExp.js => src/isRegExp.ts (52%) rename isSet.js => src/isSet.ts (53%) rename isString.js => src/isString.ts (53%) rename isSymbol.js => src/isSymbol.ts (60%) rename isTypedArray.js => src/isTypedArray.ts (57%) rename isUndefined.js => src/isUndefined.ts (84%) rename isWeakMap.js => src/isWeakMap.ts (64%) rename isWeakSet.js => src/isWeakSet.ts (64%) rename kebabCase.js => src/kebabCase.ts (62%) rename keyBy.js => src/keyBy.ts (75%) rename keys.js => src/keys.ts (75%) rename keysIn.js => src/keysIn.ts (78%) rename last.js => src/last.ts (66%) rename lastIndexOf.js => src/lastIndexOf.ts (51%) rename lowerCase.js => src/lowerCase.ts (58%) rename lowerFirst.js => src/lowerFirst.ts (68%) rename lt.js => src/lt.ts (71%) rename lte.js => src/lte.ts (72%) rename map.js => src/map.ts (67%) rename mapKey.js => src/mapKey.ts (74%) rename mapObject.js => src/mapObject.ts (71%) rename mapValue.js => src/mapValue.ts (78%) rename matches.js => src/matches.ts (81%) rename matchesProperty.js => src/matchesProperty.ts (83%) rename maxBy.js => src/maxBy.ts (53%) rename mean.js => src/mean.ts (71%) rename meanBy.js => src/meanBy.ts (75%) rename memoize.js => src/memoize.ts (70%) rename merge.js => src/merge.ts (85%) rename mergeWith.js => src/mergeWith.ts (84%) rename method.js => src/method.ts (85%) rename methodOf.js => src/methodOf.ts (86%) rename minBy.js => src/minBy.ts (53%) rename multiply.js => src/multiply.ts (86%) rename negate.js => src/negate.ts (70%) rename nth.js => src/nth.ts (65%) rename nthArg.js => src/nthArg.ts (84%) rename once.js => src/once.ts (86%) rename orderBy.js => src/orderBy.ts (78%) rename over.js => src/over.ts (71%) rename overArgs.js => src/overArgs.ts (63%) rename overEvery.js => src/overEvery.ts (73%) rename overSome.js => src/overSome.ts (74%) rename pad.js => src/pad.ts (59%) rename padEnd.js => src/padEnd.ts (64%) rename padStart.js => src/padStart.ts (64%) rename parseInt.js => src/parseInt.ts (71%) rename partition.js => src/partition.ts (80%) rename pick.js => src/pick.ts (77%) rename pickBy.js => src/pickBy.ts (59%) rename property.js => src/property.ts (61%) rename propertyOf.js => src/propertyOf.ts (78%) rename pull.js => src/pull.ts (88%) rename pullAll.js => src/pullAll.ts (72%) rename pullAllBy.js => src/pullAllBy.ts (79%) rename pullAllWith.js => src/pullAllWith.ts (78%) rename pullAt.js => src/pullAt.ts (57%) rename random.js => src/random.ts (52%) rename range.js => src/range.ts (90%) rename rangeRight.js => src/rangeRight.ts (85%) rename reduce.js => src/reduce.ts (78%) rename reduceRight.js => src/reduceRight.ts (61%) rename reject.js => src/reject.ts (72%) rename remove.js => src/remove.ts (63%) create mode 100644 src/repeat.ts rename replace.js => src/replace.ts (81%) rename result.js => src/result.ts (56%) rename round.js => src/round.ts (76%) rename sample.js => src/sample.ts (62%) create mode 100644 src/sampleSize.ts rename set.js => src/set.ts (86%) rename setWith.js => src/setWith.ts (78%) create mode 100644 src/shuffle.ts create mode 100644 src/size.ts rename slice.js => src/slice.ts (53%) rename snakeCase.js => src/snakeCase.ts (63%) rename some.js => src/some.ts (71%) rename someValue.js => src/someValue.ts (72%) rename sortedIndex.js => src/sortedIndex.ts (78%) rename sortedIndexBy.js => src/sortedIndexBy.ts (89%) rename sortedIndexOf.js => src/sortedIndexOf.ts (54%) rename sortedLastIndex.js => src/sortedLastIndex.ts (78%) rename sortedLastIndexBy.js => src/sortedLastIndexBy.ts (88%) rename sortedLastIndexOf.js => src/sortedLastIndexOf.ts (55%) rename sortedUniq.js => src/sortedUniq.ts (71%) rename sortedUniqBy.js => src/sortedUniqBy.ts (71%) create mode 100644 src/split.ts rename startCase.js => src/startCase.ts (63%) rename startsWith.js => src/startsWith.ts (64%) rename subtract.js => src/subtract.ts (88%) rename sum.js => src/sum.ts (62%) rename sumBy.js => src/sumBy.ts (79%) rename tail.js => src/tail.ts (60%) rename take.js => src/take.ts (69%) rename takeRight.js => src/takeRight.ts (63%) rename takeRightWhile.js => src/takeRightWhile.ts (80%) rename takeWhile.js => src/takeWhile.ts (81%) rename throttle.js => src/throttle.ts (81%) rename times.js => src/times.ts (56%) create mode 100644 src/toArray.ts rename toFinite.js => src/toFinite.ts (53%) rename toInteger.js => src/toInteger.ts (74%) rename toLength.js => src/toLength.ts (66%) create mode 100644 src/toNumber.ts create mode 100644 src/toPath.ts rename toPlainObject.js => src/toPlainObject.ts (76%) rename toSafeInteger.js => src/toSafeInteger.ts (58%) create mode 100644 src/toString.ts rename transform.js => src/transform.ts (57%) create mode 100644 src/trim.ts create mode 100644 src/trimEnd.ts create mode 100644 src/trimStart.ts create mode 100644 src/truncate.ts rename unescape.js => src/unescape.ts (66%) rename union.js => src/union.ts (66%) rename unionBy.js => src/unionBy.ts (63%) rename unionWith.js => src/unionWith.ts (66%) rename uniq.js => src/uniq.ts (80%) rename uniqBy.js => src/uniqBy.ts (81%) rename uniqWith.js => src/uniqWith.ts (75%) rename uniqueId.js => src/uniqueId.ts (57%) rename unset.js => src/unset.ts (83%) create mode 100644 src/unzip.ts rename unzipWith.js => src/unzipWith.ts (71%) rename update.js => src/update.ts (84%) rename updateWith.js => src/updateWith.ts (78%) rename upperCase.js => src/upperCase.ts (60%) rename upperFirst.js => src/upperFirst.ts (73%) rename values.js => src/values.ts (76%) rename without.js => src/without.ts (73%) rename words.js => src/words.ts (58%) rename xor.js => src/xor.ts (75%) rename xorBy.js => src/xorBy.ts (68%) rename xorWith.js => src/xorWith.ts (70%) rename zip.js => src/zip.ts (87%) rename zipObject.js => src/zipObject.ts (71%) rename zipObjectDeep.js => src/zipObjectDeep.ts (71%) rename zipWith.js => src/zipWith.ts (72%) create mode 100644 test/.eslintrc.cjs delete mode 100644 test/Arrays-category-methods.js create mode 100644 test/Arrays-category-methods.spec.ts create mode 100644 test/Strings-category-methods.spec.ts delete mode 100644 test/Strings-category-methods.test.js delete mode 100644 test/__proto__-property-bugs.js create mode 100644 test/__proto__-property-bugs.spec.ts create mode 100644 test/add.spec.ts delete mode 100644 test/add.test.js create mode 100644 test/after.spec.ts delete mode 100644 test/after.test.js delete mode 100644 test/ary.js create mode 100644 test/ary.spec.ts delete mode 100644 test/assign-and-assignIn.js create mode 100644 test/assign-and-assignIn.spec.ts delete mode 100644 test/assignIn.js create mode 100644 test/assignIn.spec.ts delete mode 100644 test/assignInWith.js create mode 100644 test/assignInWith.spec.ts delete mode 100644 test/assignWith-and-assignInWith.js create mode 100644 test/assignWith-and-assignInWith.spec.ts create mode 100644 test/at.spec.ts delete mode 100644 test/at.test.js create mode 100644 test/attempt.spec.ts delete mode 100644 test/attempt.test.js delete mode 100644 test/basename.js create mode 100644 test/basename.spec.ts delete mode 100644 test/before.js create mode 100644 test/before.spec.ts delete mode 100644 test/bind.js create mode 100644 test/bind.spec.ts delete mode 100644 test/bindAll.js create mode 100644 test/bindAll.spec.ts delete mode 100644 test/bindKey.js create mode 100644 test/bindKey.spec.ts create mode 100644 test/camelCase.spec.ts delete mode 100644 test/camelCase.test.js create mode 100644 test/capitalize.spec.ts delete mode 100644 test/capitalize.test.js create mode 100644 test/case-methods.spec.ts delete mode 100644 test/case-methods.test.js create mode 100644 test/castArray.spec.ts delete mode 100644 test/castArray.test.js delete mode 100644 test/chain.js create mode 100644 test/chain.spec.ts create mode 100644 test/chunk.spec.ts delete mode 100644 test/chunk.test.js delete mode 100644 test/clamp.js create mode 100644 test/clamp.spec.ts delete mode 100644 test/clone-methods.js create mode 100644 test/clone-methods.spec.ts delete mode 100644 test/compact.js create mode 100644 test/compact.spec.ts delete mode 100644 test/concat.js create mode 100644 test/concat.spec.ts delete mode 100644 test/cond.js create mode 100644 test/cond.spec.ts delete mode 100644 test/conforms-methods.js create mode 100644 test/conforms-methods.spec.ts delete mode 100644 test/conforms.js create mode 100644 test/conforms.spec.ts delete mode 100644 test/constant.js create mode 100644 test/constant.spec.ts delete mode 100644 test/countBy.js create mode 100644 test/countBy.spec.ts create mode 100644 test/create.spec.ts delete mode 100644 test/create.test.js delete mode 100644 test/curry-methods.js create mode 100644 test/curry-methods.spec.ts delete mode 100644 test/curry.js create mode 100644 test/curry.spec.ts delete mode 100644 test/curryRight.js create mode 100644 test/curryRight.spec.ts delete mode 100644 test/custom-_.iteratee-methods.js create mode 100644 test/custom-_.iteratee-methods.spec.ts delete mode 100644 test/debounce-and-throttle.js create mode 100644 test/debounce-and-throttle.spec.ts create mode 100644 test/debounce.spec.ts delete mode 100644 test/debounce.test.js create mode 100644 test/deburr.spec.ts delete mode 100644 test/deburr.test.js create mode 100644 test/defaultTo.spec.ts delete mode 100644 test/defaultTo.test.js create mode 100644 test/defaults.spec.ts delete mode 100644 test/defaults.test.js delete mode 100644 test/defaultsDeep.js create mode 100644 test/defaultsDeep.spec.ts create mode 100644 test/defer.spec.ts delete mode 100644 test/defer.test.js delete mode 100644 test/delay.js create mode 100644 test/delay.spec.ts delete mode 100644 test/difference-methods.js create mode 100644 test/difference-methods.spec.ts delete mode 100644 test/differenceBy.js create mode 100644 test/differenceBy.spec.ts create mode 100644 test/differenceWith.spec.ts delete mode 100644 test/differenceWith.test.js create mode 100644 test/divide.spec.ts delete mode 100644 test/divide.test.js create mode 100644 test/drop.spec.ts delete mode 100644 test/drop.test.js create mode 100644 test/dropRight.spec.ts delete mode 100644 test/dropRight.test.js delete mode 100644 test/dropRightWhile.js create mode 100644 test/dropRightWhile.spec.ts delete mode 100644 test/dropWhile.js create mode 100644 test/dropWhile.spec.ts create mode 100644 test/endsWith.spec.ts delete mode 100644 test/endsWith.test.js create mode 100644 test/eq.spec.ts delete mode 100644 test/eq.test.js create mode 100644 test/escape.spec.ts delete mode 100644 test/escape.test.js create mode 100644 test/escapeRegExp.spec.ts delete mode 100644 test/escapeRegExp.test.js delete mode 100644 test/every.js create mode 100644 test/every.spec.ts delete mode 100644 test/exit-early.js create mode 100644 test/exit-early.spec.ts delete mode 100644 test/extremum-methods.js create mode 100644 test/extremum-methods.spec.ts delete mode 100644 test/fill.js create mode 100644 test/fill.spec.ts delete mode 100644 test/filter-methods.js create mode 100644 test/filter-methods.spec.ts create mode 100644 test/filter.spec.ts delete mode 100644 test/filter.test.js delete mode 100644 test/find-and-findLast.js create mode 100644 test/find-and-findLast.spec.ts delete mode 100644 test/find-and-includes.js create mode 100644 test/find-and-includes.spec.ts delete mode 100644 test/find-methods.js create mode 100644 test/find-methods.spec.ts create mode 100644 test/findLast.spec.ts delete mode 100644 test/findLast.test.js create mode 100644 test/findLastIndex-and-lastIndexOf.spec.ts delete mode 100644 test/findLastIndex-and-lastIndexOf.test.js delete mode 100644 test/flatMap-methods.js create mode 100644 test/flatMap-methods.spec.ts delete mode 100644 test/flatMapDepth.js create mode 100644 test/flatMapDepth.spec.ts delete mode 100644 test/flatten-methods.js create mode 100644 test/flatten-methods.spec.ts delete mode 100644 test/flattenDepth.js create mode 100644 test/flattenDepth.spec.ts create mode 100644 test/flip.spec.ts delete mode 100644 test/flip.test.js create mode 100644 test/flow-methods.spec.ts delete mode 100644 test/flow-methods.test.js create mode 100644 test/forEach.spec.ts delete mode 100644 test/forEach.test.js create mode 100644 test/forEachRight.spec.ts delete mode 100644 test/forEachRight.test.js delete mode 100644 test/forIn-methods.js create mode 100644 test/forIn-methods.spec.ts delete mode 100644 test/forOwn-methods.js create mode 100644 test/forOwn-methods.spec.ts delete mode 100644 test/fromPairs.js create mode 100644 test/fromPairs.spec.ts create mode 100644 test/functions.spec.ts delete mode 100644 test/functions.test.js delete mode 100644 test/get-and-result.js create mode 100644 test/get-and-result.spec.ts delete mode 100644 test/groupBy.js create mode 100644 test/groupBy.spec.ts create mode 100644 test/gt.spec.ts delete mode 100644 test/gt.test.js create mode 100644 test/gte.spec.ts delete mode 100644 test/gte.test.js delete mode 100644 test/has-methods.js create mode 100644 test/has-methods.spec.ts delete mode 100644 test/head.js create mode 100644 test/head.spec.ts delete mode 100644 test/identity.js create mode 100644 test/identity.spec.ts delete mode 100644 test/inRange.js create mode 100644 test/inRange.spec.ts delete mode 100644 test/includes.js create mode 100644 test/includes.spec.ts delete mode 100644 test/indexOf-methods.js create mode 100644 test/indexOf-methods.spec.ts create mode 100644 test/indexOf.spec.ts delete mode 100644 test/indexOf.test.js delete mode 100644 test/initial.js create mode 100644 test/initial.spec.ts delete mode 100644 test/intersection-methods.js create mode 100644 test/intersection-methods.spec.ts delete mode 100644 test/intersectionBy.js create mode 100644 test/intersectionBy.spec.ts create mode 100644 test/intersectionWith.spec.ts delete mode 100644 test/intersectionWith.test.js create mode 100644 test/invert.spec.ts delete mode 100644 test/invert.test.js delete mode 100644 test/invertBy.js create mode 100644 test/invertBy.spec.ts delete mode 100644 test/invoke.js create mode 100644 test/invoke.spec.ts delete mode 100644 test/invokeMap.js create mode 100644 test/invokeMap.spec.ts create mode 100644 test/isArguments.spec.ts delete mode 100644 test/isArguments.test.js delete mode 100644 test/isArray.js create mode 100644 test/isArray.spec.ts create mode 100644 test/isArrayBuffer.spec.ts delete mode 100644 test/isArrayBuffer.test.js create mode 100644 test/isArrayLike.spec.ts delete mode 100644 test/isArrayLike.test.js create mode 100644 test/isBoolean.spec.ts delete mode 100644 test/isBoolean.test.js create mode 100644 test/isBuffer.spec.ts delete mode 100644 test/isBuffer.test.js create mode 100644 test/isDate.spec.ts delete mode 100644 test/isDate.test.js create mode 100644 test/isElement.spec.ts delete mode 100644 test/isElement.test.js delete mode 100644 test/isEmpty.js create mode 100644 test/isEmpty.spec.ts delete mode 100644 test/isEqual.js create mode 100644 test/isEqual.spec.ts delete mode 100644 test/isEqualWith.js create mode 100644 test/isEqualWith.spec.ts create mode 100644 test/isError.spec.ts delete mode 100644 test/isError.test.js delete mode 100644 test/isFinite.js create mode 100644 test/isFinite.spec.ts delete mode 100644 test/isFunction.js create mode 100644 test/isFunction.spec.ts create mode 100644 test/isIndex.spec.ts delete mode 100644 test/isIndex.test.js delete mode 100644 test/isInteger-methods.js create mode 100644 test/isInteger-methods.spec.ts delete mode 100644 test/isIterateeCall.js create mode 100644 test/isIterateeCall.spec.ts create mode 100644 test/isLength.spec.ts delete mode 100644 test/isLength.test.js create mode 100644 test/isMap.spec.ts delete mode 100644 test/isMap.test.js delete mode 100644 test/isMatchWith.js create mode 100644 test/isMatchWith.spec.ts delete mode 100644 test/isNaN.js create mode 100644 test/isNaN.spec.ts delete mode 100644 test/isNative.js create mode 100644 test/isNative.spec.ts create mode 100644 test/isNil.spec.ts delete mode 100644 test/isNil.test.js create mode 100644 test/isNull.spec.ts delete mode 100644 test/isNull.test.js create mode 100644 test/isNumber.spec.ts delete mode 100644 test/isNumber.test.js create mode 100644 test/isObject.spec.ts delete mode 100644 test/isObject.test.js create mode 100644 test/isObjectLike.spec.ts delete mode 100644 test/isObjectLike.test.js delete mode 100644 test/isPlainObject.js create mode 100644 test/isPlainObject.spec.ts create mode 100644 test/isRegExp.spec.ts delete mode 100644 test/isRegExp.test.js create mode 100644 test/isSet.spec.ts delete mode 100644 test/isSet.test.js create mode 100644 test/isString.spec.ts delete mode 100644 test/isString.test.js create mode 100644 test/isSymbol.spec.ts delete mode 100644 test/isSymbol.test.js delete mode 100644 test/isType-checks.js create mode 100644 test/isType-checks.spec.ts delete mode 100644 test/isTypedArray.js create mode 100644 test/isTypedArray.spec.ts create mode 100644 test/isUndefined.spec.ts delete mode 100644 test/isUndefined.test.js create mode 100644 test/isWeakMap.spec.ts delete mode 100644 test/isWeakMap.test.js create mode 100644 test/isWeakSet.spec.ts delete mode 100644 test/isWeakSet.test.js delete mode 100644 test/iteratee.js create mode 100644 test/iteratee.spec.ts delete mode 100644 test/iteration-methods.js create mode 100644 test/iteration-methods.spec.ts delete mode 100644 test/join.js create mode 100644 test/join.spec.ts delete mode 100644 test/keyBy.js create mode 100644 test/keyBy.spec.ts delete mode 100644 test/keys-methods.js create mode 100644 test/keys-methods.spec.ts delete mode 100644 test/last.js create mode 100644 test/last.spec.ts delete mode 100644 test/lodash(...)-methods-that-return-new-wrapped-values.js create mode 100644 test/lodash(...)-methods-that-return-new-wrapped-values.spec.ts delete mode 100644 test/lodash(...)-methods-that-return-the-wrapped-modified-array.js create mode 100644 test/lodash(...)-methods-that-return-the-wrapped-modified-array.spec.ts delete mode 100644 test/lodash(...)-methods-that-return-unwrapped-values.js create mode 100644 test/lodash(...)-methods-that-return-unwrapped-values.spec.ts delete mode 100644 test/lodash(...).commit.js create mode 100644 test/lodash(...).commit.spec.ts delete mode 100644 test/lodash(...).next.js create mode 100644 test/lodash(...).next.spec.ts delete mode 100644 test/lodash(...).plant.js create mode 100644 test/lodash(...).plant.spec.ts delete mode 100644 test/lodash(...).pop.js create mode 100644 test/lodash(...).pop.spec.ts delete mode 100644 test/lodash(...).push.js create mode 100644 test/lodash(...).push.spec.ts delete mode 100644 test/lodash(...).shift.js create mode 100644 test/lodash(...).shift.spec.ts delete mode 100644 test/lodash(...).sort.js create mode 100644 test/lodash(...).sort.spec.ts delete mode 100644 test/lodash(...).splice.js create mode 100644 test/lodash(...).splice.spec.ts delete mode 100644 test/lodash(...).unshift.js create mode 100644 test/lodash(...).unshift.spec.ts delete mode 100644 test/lodash(...).value.js create mode 100644 test/lodash(...).value.spec.ts delete mode 100644 test/lodash-constructor.js create mode 100644 test/lodash-constructor.spec.ts delete mode 100644 test/lodash-methods.js create mode 100644 test/lodash-methods.spec.ts delete mode 100644 test/lodash.methodName.js create mode 100644 test/lodash.methodName.spec.ts create mode 100644 test/lowerCase.spec.ts delete mode 100644 test/lowerCase.test.js create mode 100644 test/lowerFirst.spec.ts delete mode 100644 test/lowerFirst.test.js create mode 100644 test/lt.spec.ts delete mode 100644 test/lt.test.js create mode 100644 test/lte.spec.ts delete mode 100644 test/lte.test.js delete mode 100644 test/map-caches.js create mode 100644 test/map-caches.spec.ts delete mode 100644 test/map.js create mode 100644 test/map.spec.ts delete mode 100644 test/mapKeys-and-mapValues.js create mode 100644 test/mapKeys-and-mapValues.spec.ts delete mode 100644 test/mapKeys.js create mode 100644 test/mapKeys.spec.ts delete mode 100644 test/mapValues.js create mode 100644 test/mapValues.spec.ts delete mode 100644 test/matches-methods.js create mode 100644 test/matches-methods.spec.ts delete mode 100644 test/matches.js create mode 100644 test/matches.spec.ts delete mode 100644 test/matchesProperty.js create mode 100644 test/matchesProperty.spec.ts delete mode 100644 test/math-operator-methods.js create mode 100644 test/math-operator-methods.spec.ts delete mode 100644 test/max.js create mode 100644 test/max.spec.ts create mode 100644 test/mean.spec.ts delete mode 100644 test/mean.test.js delete mode 100644 test/meanBy.js create mode 100644 test/meanBy.spec.ts create mode 100644 test/memoize.spec.ts delete mode 100644 test/memoize.test.js create mode 100644 test/memoizeCapped.spec.ts delete mode 100644 test/memoizeCapped.test.js create mode 100644 test/merge.spec.ts delete mode 100644 test/merge.test.js delete mode 100644 test/mergeWith.js create mode 100644 test/mergeWith.spec.ts delete mode 100644 test/method.js create mode 100644 test/method.spec.ts delete mode 100644 test/methodOf.js create mode 100644 test/methodOf.spec.ts delete mode 100644 test/methods-using-createWrapper.js create mode 100644 test/methods-using-createWrapper.spec.ts delete mode 100644 test/min.js create mode 100644 test/min.spec.ts delete mode 100644 test/mixin.js create mode 100644 test/mixin.spec.ts create mode 100644 test/multiply.spec.ts delete mode 100644 test/multiply.test.js delete mode 100644 test/negate.js create mode 100644 test/negate.spec.ts delete mode 100644 test/noConflict.js create mode 100644 test/noConflict.spec.ts delete mode 100644 test/now.js create mode 100644 test/now.spec.ts delete mode 100644 test/nth.js create mode 100644 test/nth.spec.ts delete mode 100644 test/nthArg.js create mode 100644 test/nthArg.spec.ts delete mode 100644 test/number-coercion-methods.js create mode 100644 test/number-coercion-methods.spec.ts delete mode 100644 test/object-assignments.js create mode 100644 test/object-assignments.spec.ts delete mode 100644 test/omit-methods.js create mode 100644 test/omit-methods.spec.ts delete mode 100644 test/omit.js create mode 100644 test/omit.spec.ts delete mode 100644 test/omitBy.js create mode 100644 test/omitBy.spec.ts create mode 100644 test/once.spec.ts delete mode 100644 test/once.test.js delete mode 100644 test/orderBy.js create mode 100644 test/orderBy.spec.ts delete mode 100644 test/over.js create mode 100644 test/over.spec.ts delete mode 100644 test/overArgs.js create mode 100644 test/overArgs.spec.ts delete mode 100644 test/overEvery.js create mode 100644 test/overEvery.spec.ts delete mode 100644 test/overSome.js create mode 100644 test/overSome.spec.ts delete mode 100644 test/pad-methods.js create mode 100644 test/pad-methods.spec.ts delete mode 100644 test/pad.js create mode 100644 test/pad.spec.ts delete mode 100644 test/padEnd.js create mode 100644 test/padEnd.spec.ts delete mode 100644 test/padStart.js create mode 100644 test/padStart.spec.ts delete mode 100644 test/parseInt.js create mode 100644 test/parseInt.spec.ts delete mode 100644 test/partial-methods.js create mode 100644 test/partial-methods.spec.ts delete mode 100644 test/partialRight.js create mode 100644 test/partialRight.spec.ts delete mode 100644 test/partition.js create mode 100644 test/partition.spec.ts delete mode 100644 test/pick-methods.js create mode 100644 test/pick-methods.spec.ts delete mode 100644 test/pick.js create mode 100644 test/pick.spec.ts create mode 100644 test/pickBy.spec.ts delete mode 100644 test/pickBy.test.js create mode 100644 test/property.spec.ts delete mode 100644 test/property.test.js create mode 100644 test/propertyOf.spec.ts delete mode 100644 test/propertyOf.test.js delete mode 100644 test/pull-methods.js create mode 100644 test/pull-methods.spec.ts create mode 100644 test/pullAll.spec.ts delete mode 100644 test/pullAll.test.js create mode 100644 test/pullAllBy.spec.ts delete mode 100644 test/pullAllBy.test.js create mode 100644 test/pullAllWith.spec.ts delete mode 100644 test/pullAllWith.test.js delete mode 100644 test/pullAt.js create mode 100644 test/pullAt.spec.ts delete mode 100644 test/random.js create mode 100644 test/random.spec.ts delete mode 100644 test/range-methods.js create mode 100644 test/range-methods.spec.ts delete mode 100644 test/rearg.js create mode 100644 test/rearg.spec.ts delete mode 100644 test/reduce-methods.js create mode 100644 test/reduce-methods.spec.ts delete mode 100644 test/reduce.js create mode 100644 test/reduce.spec.ts delete mode 100644 test/reduceRight.js create mode 100644 test/reduceRight.spec.ts create mode 100644 test/reject.spec.ts delete mode 100644 test/reject.test.js delete mode 100644 test/remove.js create mode 100644 test/remove.spec.ts delete mode 100644 test/repeat.js create mode 100644 test/repeat.spec.ts create mode 100644 test/replace.spec.ts delete mode 100644 test/replace.test.js delete mode 100644 test/rest.js create mode 100644 test/rest.spec.ts create mode 100644 test/result.spec.ts delete mode 100644 test/result.test.js delete mode 100644 test/reverse.js create mode 100644 test/reverse.spec.ts delete mode 100644 test/round-methods.js create mode 100644 test/round-methods.spec.ts delete mode 100644 test/runInContext.js create mode 100644 test/runInContext.spec.ts delete mode 100644 test/sample.js create mode 100644 test/sample.spec.ts delete mode 100644 test/sampleSize.js create mode 100644 test/sampleSize.spec.ts delete mode 100644 test/set-methods.js create mode 100644 test/set-methods.spec.ts delete mode 100644 test/setWith.js create mode 100644 test/setWith.spec.ts delete mode 100644 test/shuffle.js create mode 100644 test/shuffle.spec.ts create mode 100644 test/size.spec.ts delete mode 100644 test/size.test.js delete mode 100644 test/slice-and-toArray.js create mode 100644 test/slice-and-toArray.spec.ts delete mode 100644 test/slice.js create mode 100644 test/slice.spec.ts delete mode 100644 test/some.js create mode 100644 test/some.spec.ts delete mode 100644 test/sortBy-methods.js create mode 100644 test/sortBy-methods.spec.ts delete mode 100644 test/sortBy.js create mode 100644 test/sortBy.spec.ts delete mode 100644 test/sortedIndex-methods.js create mode 100644 test/sortedIndex-methods.spec.ts delete mode 100644 test/sortedIndexBy-methods.js create mode 100644 test/sortedIndexBy-methods.spec.ts delete mode 100644 test/sortedIndexOf-methods.js create mode 100644 test/sortedIndexOf-methods.spec.ts create mode 100644 test/sortedUniq.spec.ts delete mode 100644 test/sortedUniq.test.js delete mode 100644 test/split.js create mode 100644 test/split.spec.ts delete mode 100644 test/spread.js create mode 100644 test/spread.spec.ts create mode 100644 test/startCase.spec.ts delete mode 100644 test/startCase.test.js delete mode 100644 test/startsWith-and-endsWith.js create mode 100644 test/startsWith-and-endsWith.spec.ts delete mode 100644 test/startsWith.js create mode 100644 test/startsWith.spec.ts delete mode 100644 test/strict-mode-checks.js create mode 100644 test/strict-mode-checks.spec.ts delete mode 100644 test/stub-methods.js create mode 100644 test/stub-methods.spec.ts create mode 100644 test/subtract.spec.ts delete mode 100644 test/subtract.test.js delete mode 100644 test/sum-methods.js create mode 100644 test/sum-methods.spec.ts delete mode 100644 test/sumBy.js create mode 100644 test/sumBy.spec.ts delete mode 100644 test/tail.js create mode 100644 test/tail.spec.ts delete mode 100644 test/take.js create mode 100644 test/take.spec.ts delete mode 100644 test/takeRight.js create mode 100644 test/takeRight.spec.ts delete mode 100644 test/takeRightWhile.js create mode 100644 test/takeRightWhile.spec.ts delete mode 100644 test/takeWhile.js create mode 100644 test/takeWhile.spec.ts delete mode 100644 test/tap.js create mode 100644 test/tap.spec.ts delete mode 100644 test/template.js create mode 100644 test/template.spec.ts delete mode 100644 test/throttle.js create mode 100644 test/throttle.spec.ts delete mode 100644 test/times.js create mode 100644 test/times.spec.ts create mode 100644 test/toArray.spec.ts delete mode 100644 test/toArray.test.js delete mode 100644 test/toInteger-methods.js create mode 100644 test/toInteger-methods.spec.ts create mode 100644 test/toLength.spec.ts delete mode 100644 test/toLength.test.js delete mode 100644 test/toLower.js create mode 100644 test/toLower.spec.ts delete mode 100644 test/toPairs-methods.js create mode 100644 test/toPairs-methods.spec.ts delete mode 100644 test/toPairs.js create mode 100644 test/toPairs.spec.ts delete mode 100644 test/toPairsIn.js create mode 100644 test/toPairsIn.spec.ts delete mode 100644 test/toPath.js create mode 100644 test/toPath.spec.ts delete mode 100644 test/toPlainObject.js create mode 100644 test/toPlainObject.spec.ts create mode 100644 test/toString.spec.ts delete mode 100644 test/toString.test.js delete mode 100644 test/toUpper.js create mode 100644 test/toUpper.spec.ts delete mode 100644 test/transform.js create mode 100644 test/transform.spec.ts delete mode 100644 test/trim-methods.js create mode 100644 test/trim-methods.spec.ts delete mode 100644 test/truncate.js create mode 100644 test/truncate.spec.ts delete mode 100644 test/unary.js create mode 100644 test/unary.spec.ts delete mode 100644 test/uncommon-symbols.js create mode 100644 test/uncommon-symbols.spec.ts delete mode 100644 test/unescape.js create mode 100644 test/unescape.spec.ts delete mode 100644 test/union-methods.js create mode 100644 test/union-methods.spec.ts delete mode 100644 test/unionBy.js create mode 100644 test/unionBy.spec.ts create mode 100644 test/unionWith.spec.ts delete mode 100644 test/unionWith.test.js delete mode 100644 test/uniq-methods.js create mode 100644 test/uniq-methods.spec.ts delete mode 100644 test/uniq.js create mode 100644 test/uniq.spec.ts delete mode 100644 test/uniqBy-methods.js create mode 100644 test/uniqBy-methods.spec.ts create mode 100644 test/uniqWith.spec.ts delete mode 100644 test/uniqWith.test.js create mode 100644 test/uniqueId.spec.ts delete mode 100644 test/uniqueId.test.js delete mode 100644 test/unset.js create mode 100644 test/unset.spec.ts delete mode 100644 test/unzip-and-zip.js create mode 100644 test/unzip-and-zip.spec.ts delete mode 100644 test/unzipWith.js create mode 100644 test/unzipWith.spec.ts delete mode 100644 test/update-methods.js create mode 100644 test/update-methods.spec.ts delete mode 100644 test/updateWith.js create mode 100644 test/updateWith.spec.ts create mode 100644 test/upperCase.spec.ts delete mode 100644 test/upperCase.test.js create mode 100644 test/upperFirst.spec.ts delete mode 100644 test/upperFirst.test.js delete mode 100644 test/utils.js create mode 100644 test/utils.ts delete mode 100644 test/values-methods.js create mode 100644 test/values-methods.spec.ts create mode 100644 test/without.spec.ts delete mode 100644 test/without.test.js create mode 100644 test/words.spec.ts delete mode 100644 test/words.test.js delete mode 100644 test/wrap.js create mode 100644 test/wrap.spec.ts delete mode 100644 test/xor-methods.js create mode 100644 test/xor-methods.spec.ts delete mode 100644 test/xorBy.js create mode 100644 test/xorBy.spec.ts create mode 100644 test/xorWith.spec.ts delete mode 100644 test/xorWith.test.js delete mode 100644 test/zipObject-methods.js create mode 100644 test/zipObject-methods.spec.ts delete mode 100644 test/zipWith.js create mode 100644 test/zipWith.spec.ts delete mode 100644 toArray.js delete mode 100644 toNumber.js delete mode 100644 toPath.js delete mode 100644 toString.js delete mode 100644 trim.js delete mode 100644 trimEnd.js delete mode 100644 trimStart.js delete mode 100644 truncate.js create mode 100644 tsconfig.json delete mode 100644 unzip.js create mode 100644 yarn.lock diff --git a/.commitlintrc.js b/.commitlintrc.js new file mode 100644 index 000000000..a8a92f0ef --- /dev/null +++ b/.commitlintrc.js @@ -0,0 +1,29 @@ +'use strict'; + +module.exports = { + extends: [ + '@commitlint/config-conventional', // scoped packages are not prefixed + ], + rules: { + 'type-enum': [ + 2, + 'always', + [ + 'build', + 'chore', + 'ci', + 'docs', + 'feat', + 'fix', + 'perf', + 'proposal', + 'refactor', + 'release', + 'revert', + 'style', + 'test', + 'wip', + ], + ], + }, +}; diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..e6c4d17ad --- /dev/null +++ b/.eslintignore @@ -0,0 +1,5 @@ +coverage/ +coverage-merged/ +dist/ +node_modules/ +types/ diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..9e6f3b9d3 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,98 @@ +{ + "extends": ["airbnb-base", "prettier"], + "root": true, + "env": { + "amd": true, + "browser": true, + "es6": true, + "jest": true, + "node": true + }, + "globals": { + "BigInt": "readonly", + "BigInt64Array": "readonly", + "BigUint64Array": "readonly", + "globalThis": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module" + }, + "plugins": [ + "prettier" + ], + "rules": { + "prettier/prettier": "error", + // Overridden + "no-eval": "off", + "camelcase": ["error", { "properties": "never", "allow": [ "W[0-9]+_"] }], + "import/extensions": "off", + // @TODO: Fix the following rules progressively. + "arrow-body-style": "warn", + "prefer-arrow-callback": "warn", + "prefer-object-spread": "off", + "max-classes-per-file": "off", + "dot-notation": "off", + "object-shorthand": "off", + "no-param-reassign": "off", + "no-cond-assign": "off", + "prefer-destructuring": "off", + "func-names": "off", + "no-nested-ternary": "off", + "no-plusplus": "off", + "strict": "off", + "no-restricted-syntax": "off", + "import/no-mutable-exports": "off", + "guard-for-in": "off", + "import/prefer-default-export": "off", + "prefer-rest-params": "off", + "one-var": "off", + "prefer-spread": "off", + "no-lonely-if": "off", + "no-prototype-builtins": "off", + "no-continue": "off", + "no-shadow": "off", + // Rules up for discussion. + "no-multi-assign": "off", + "new-cap": "off" + }, + "overrides": [ + { + "files": ["**/*.ts"], + "parserOptions": { + "project": "./tsconfig.json" + }, + "extends": [ + "airbnb-typescript/base", + "prettier" + ], + "plugins": ["@typescript-eslint"], + "rules": { + "@typescript-eslint/no-unused-vars": [ + "warn", + { + "vars": "all", + "args": "after-used", + "ignoreRestSiblings": true, + "argsIgnorePattern": "^_" // For tsc compatibility. + } + ], + "comma-dangle": "off", + "implicit-arrow-linebreak": "off", // Conflicts with prettier. + "import/extensions": "off", + "import/prefer-default-export": "off", + "operator-linebreak": "off", + "object-curly-newline": "off", + "prefer-rest-params": "off", // We need to use params. + "prettier/prettier": "error", + "@typescript-eslint/no-shadow": "warn", + "@typescript-eslint/no-use-before-define": ["warn", { "functions": false }], + "import/no-cycle": "warn", + "no-bitwise": "off", + "no-unsafe-finally": "warn", + "no-param-reassign": "off", + "no-shadow": "warn" + } + } + ] +} diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 8952c5779..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,125 +0,0 @@ -module.exports = { - 'extends': ['plugin:import/errors'], - 'plugins': ['import'], - 'env': { - 'es6': true, - 'node': true - }, - 'parserOptions': { - 'ecmaVersion': 6, - 'sourceType': 'module', - 'ecmaFeatures': { - 'impliedStrict': true, - 'objectLiteralDuplicateProperties': false - } - }, - 'rules': { - 'array-bracket-spacing': ['error', 'never'], - - 'camelcase': ['error', { - 'properties': 'never' - }], - - 'comma-dangle': ['error', 'never'], - - 'curly': ['error', 'all'], - - 'eol-last': ['error'], - - 'indent': ['error', 2, { - 'SwitchCase': 1 - }], - - 'keyword-spacing': ['error'], - - 'max-len': ['error', { - 'code': 180, - 'ignoreComments': true, - 'ignoreRegExpLiterals': true - }], - - 'no-else-return': ['error'], - - 'no-mixed-spaces-and-tabs': ['error'], - - 'no-multiple-empty-lines': ['error'], - - 'no-spaced-func': ['error'], - - 'no-trailing-spaces': ['error'], - - 'no-undef': ['error'], - - 'no-unexpected-multiline': ['error'], - - 'no-unused-vars': ['error', { - 'args': 'none', - 'vars': 'all' - }], - - 'quotes': ['error', 'single', { - 'allowTemplateLiterals': true, - 'avoidEscape': true - }], - - 'semi': ['error', 'never'], - - 'space-before-blocks': ['error', 'always'], - - 'space-before-function-paren': ['error', 'never'], - - 'space-in-parens': ['error', 'never'], - - 'space-unary-ops': ['error', { - 'nonwords': false, - 'overrides': {} - }], - - // 'valid-jsdoc': ['error'] - - // ECMAScript 6 rules - - 'arrow-body-style': ['error', 'as-needed', { - 'requireReturnForObjectLiteral': false - }], - - 'arrow-parens': ['error', 'always'], - - 'arrow-spacing': ['error', { - 'after': true, - 'before': true - }], - - 'no-class-assign': ['error'], - - 'no-const-assign': ['error'], - - 'no-dupe-class-members': ['error'], - - 'no-duplicate-imports': ['error'], - - 'no-new-symbol': ['error'], - - 'no-useless-rename': ['error'], - - 'no-var': ['error'], - - 'object-shorthand': ['error', 'always', { - 'avoidQuotes': true, - 'ignoreConstructors': false - }], - - 'prefer-arrow-callback': ['error', { - 'allowNamedFunctions': false, - 'allowUnboundThis': true - }], - - 'prefer-const': ['error'], - - 'prefer-rest-params': ['error'], - - 'prefer-template': ['error'], - - 'template-curly-spacing': ['error', 'never'] - } -}; diff --git a/.gitattributes b/.gitattributes index 176a458f9..6f28e15bf 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ * text=auto +*.lockb binary diff=lockb diff --git a/.gitignore b/.gitignore index 14ec97ff6..7e32d1977 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ .DS_Store *.log* -doc/*.html -node_modules +dist/ +node_modules/ *.code-workspace +*.lockb *.sublime-project *.sublime-workspace diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 000000000..31354ec13 --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 000000000..d6a1f7335 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +bun run commitlint --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 000000000..d28fd9d2c --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +bun run lint-staged diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..e6c4d17ad --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +coverage/ +coverage-merged/ +dist/ +node_modules/ +types/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..b06ca2eca --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "printWidth": 100, + "useTabs": false, + "tabWidth": 4, + "singleQuote": true +} diff --git a/README.md b/README.md index 75f0abd51..7aebe8e5a 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,14 @@ [Site](https://lodash.com/) | [Docs](https://lodash.com/docs) | -[FP Guide](https://github.com/lodash/lodash/wiki/FP-Guide) | [Contributing](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md) | [Wiki](https://github.com/lodash/lodash/wiki "Changelog, Roadmap, etc.") | -[Code of Conduct](https://code-of-conduct.openjsf.org) | -[Twitter](https://twitter.com/bestiejs) | -[Chat](https://gitter.im/lodash/lodash) +[Code of Conduct](https://code-of-conduct.openjsf.org) The [Lodash](https://lodash.com/) library exported as a [UMD](https://github.com/umdjs/umd) module. -Generated using [lodash-cli](https://www.npmjs.com/package/lodash-cli): ```shell -$ npm run build +$ bun run build $ lodash -o ./dist/lodash.js $ lodash core -o ./dist/lodash.core.js ``` @@ -34,14 +30,12 @@ In a browser: ``` -Using npm: +Using bun: ```shell -$ npm i -g npm -$ npm i lodash +$ bun i lodash ``` -Note: add `--save` if you are using npm < 5.0.0 -In Node.js: +In [Bun](https://bun.sh): ```js // Load the full build. var _ = require('lodash'); @@ -76,5 +70,3 @@ Lodash is available in a [variety of builds](https://lodash.com/custom-builds) & * [lodash](https://www.npmjs.com/package/lodash) & [per method packages](https://www.npmjs.com/search?q=keywords:lodash-modularized) * [lodash-es](https://www.npmjs.com/package/lodash-es), [babel-plugin-lodash](https://www.npmjs.com/package/babel-plugin-lodash), & [lodash-webpack-plugin](https://www.npmjs.com/package/lodash-webpack-plugin) - * [lodash/fp](https://github.com/lodash/lodash/tree/npm/fp) - * [lodash-amd](https://www.npmjs.com/package/lodash-amd) diff --git a/bunfig.toml b/bunfig.toml new file mode 100644 index 000000000..1fe90030c --- /dev/null +++ b/bunfig.toml @@ -0,0 +1,2 @@ +[install.lockfile] +print = "yarn" \ No newline at end of file diff --git a/debounce.js b/debounce.js deleted file mode 100644 index 2a799a613..000000000 --- a/debounce.js +++ /dev/null @@ -1,213 +0,0 @@ -import isObject from './isObject.js' -import root from './.internal/root.js' - -/** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked, or until the next browser frame is drawn. The debounced function - * comes with a `cancel` method to cancel delayed `func` invocations and a - * `flush` method to immediately invoke them. Provide `options` to indicate - * whether `func` should be invoked on the leading and/or trailing edge of the - * `wait` timeout. The `func` is invoked with the last arguments provided to the - * debounced function. 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 debounced function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until the next tick, similar to `setTimeout` with a timeout of `0`. - * - * If `wait` is omitted in an environment with `requestAnimationFrame`, `func` - * invocation will be deferred until the next frame is drawn (typically about - * 16ms). - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `debounce` and `throttle`. - * - * @since 0.1.0 - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] - * The number of milliseconds to delay; if omitted, `requestAnimationFrame` is - * used (if available). - * @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's 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 clicked, debouncing subsequent calls. - * jQuery(element).on('click', debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })) - * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * const debounced = debounce(batchLog, 250, { 'maxWait': 1000 }) - * const source = new EventSource('/stream') - * jQuery(source).on('message', debounced) - * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel) - * - * // Check for pending invocations. - * const status = debounced.pending() ? "Pending..." : "Ready" - */ -function debounce(func, wait, options) { - let lastArgs, - lastThis, - maxWait, - result, - timerId, - lastCallTime - - let lastInvokeTime = 0 - let leading = false - let maxing = false - let trailing = true - - // Bypass `requestAnimationFrame` by explicitly setting `wait=0`. - const useRAF = (!wait && wait !== 0 && typeof root.requestAnimationFrame === 'function') - - if (typeof func !== 'function') { - throw new TypeError('Expected a function') - } - wait = +wait || 0 - if (isObject(options)) { - leading = !!options.leading - maxing = 'maxWait' in options - maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait - trailing = 'trailing' in options ? !!options.trailing : trailing - } - - function invokeFunc(time) { - const args = lastArgs - const thisArg = lastThis - - lastArgs = lastThis = undefined - lastInvokeTime = time - result = func.apply(thisArg, args) - return result - } - - function startTimer(pendingFunc, wait) { - if (useRAF) { - root.cancelAnimationFrame(timerId) - return root.requestAnimationFrame(pendingFunc) - } - return setTimeout(pendingFunc, wait) - } - - function cancelTimer(id) { - if (useRAF) { - return root.cancelAnimationFrame(id) - } - clearTimeout(id) - } - - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time - // Start the timer for the trailing edge. - timerId = startTimer(timerExpired, wait) - // Invoke the leading edge. - return leading ? invokeFunc(time) : result - } - - function remainingWait(time) { - const timeSinceLastCall = time - lastCallTime - const timeSinceLastInvoke = time - lastInvokeTime - const timeWaiting = wait - timeSinceLastCall - - return maxing - ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) - : timeWaiting - } - - function shouldInvoke(time) { - const timeSinceLastCall = time - lastCallTime - const timeSinceLastInvoke = time - lastInvokeTime - - // Either this is the first call, activity has stopped and we're at the - // trailing edge, the system time has gone backwards and we're treating - // it as the trailing edge, or we've hit the `maxWait` limit. - return (lastCallTime === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)) - } - - function timerExpired() { - const time = Date.now() - if (shouldInvoke(time)) { - return trailingEdge(time) - } - // Restart the timer. - timerId = startTimer(timerExpired, remainingWait(time)) - } - - function trailingEdge(time) { - timerId = undefined - - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time) - } - lastArgs = lastThis = undefined - return result - } - - function cancel() { - if (timerId !== undefined) { - cancelTimer(timerId) - } - lastInvokeTime = 0 - lastArgs = lastCallTime = lastThis = timerId = undefined - } - - function flush() { - return timerId === undefined ? result : trailingEdge(Date.now()) - } - - function pending() { - return timerId !== undefined - } - - function debounced(...args) { - const time = Date.now() - const isInvoking = shouldInvoke(time) - - lastArgs = args - lastThis = this - lastCallTime = time - - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime) - } - if (maxing) { - // Handle invocations in a tight loop. - timerId = startTimer(timerExpired, wait) - return invokeFunc(lastCallTime) - } - } - if (timerId === undefined) { - timerId = startTimer(timerExpired, wait) - } - return result - } - debounced.cancel = cancel - debounced.flush = flush - debounced.pending = pending - return debounced -} - -export default debounce diff --git a/each.js b/each.js deleted file mode 100644 index d2fd2ffbd..000000000 --- a/each.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './forEach.js' diff --git a/eachRight.js b/eachRight.js deleted file mode 100644 index b08d8f5e0..000000000 --- a/eachRight.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './forEachRight.js' diff --git a/first.js b/first.js deleted file mode 100644 index db707ff9a..000000000 --- a/first.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './head.js' diff --git a/hasPath.js b/hasPath.js deleted file mode 100644 index 2a3a7fb6f..000000000 --- a/hasPath.js +++ /dev/null @@ -1,53 +0,0 @@ -import castPath from './.internal/castPath.js' -import isArguments from './isArguments.js' -import isIndex from './.internal/isIndex.js' -import isLength from './isLength.js' -import toKey from './.internal/toKey.js' - -/** Used to check objects for own properties. */ -const hasOwnProperty = Object.prototype.hasOwnProperty - -/** - * Checks if `path` is a direct property of `object`. - * - * @since 5.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @see has, hasIn, hasPathIn - * @example - * - * const object = { 'a': { 'b': 2 } } - * const other = create({ 'a': create({ 'b': 2 }) }) - * - * hasPath(object, 'a.b') - * // => true - * - * hasPath(object, ['a', 'b']) - * // => true - */ -function hasPath(object, path) { - path = castPath(path, object) - - let index = -1 - let { length } = path - let result = false - let key - - while (++index < length) { - key = toKey(path[index]) - if (!(result = object != null && hasOwnProperty.call(object, key))) { - break - } - object = object[key] - } - if (result || ++index != length) { - return result - } - length = object == null ? 0 : object.length - return !!length && isLength(length) && isIndex(key, length) && - (Array.isArray(object) || isArguments(object)) -} - -export default hasPath diff --git a/hasPathIn.js b/hasPathIn.js deleted file mode 100644 index 5b9b5a266..000000000 --- a/hasPathIn.js +++ /dev/null @@ -1,50 +0,0 @@ -import castPath from './.internal/castPath.js' -import isArguments from './isArguments.js' -import isIndex from './.internal/isIndex.js' -import isLength from './isLength.js' -import toKey from './.internal/toKey.js' - -/** - * Checks if `path` is a direct property of `object`. - * - * @since 5.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @see has, hasIn hasPath - * @example - * - * const object = { 'a': { 'b': 2 } } - * const other = create({ 'a': create({ 'b': 2 }) }) - * - * hasPathIn(object, 'a.b') - * // => true - * - * hasPathIn(object, ['a', 'b']) - * // => true - */ -function hasPathIn(object, path) { - path = castPath(path, object) - - let index = -1 - let { length } = path - let result = false - let key - - while (++index < length) { - key = toKey(path[index]) - if (!(result = object != null && key in Object(object))) { - break - } - object = object[key] - } - if (result || ++index != length) { - return result - } - length = object == null ? 0 : object.length - return !!length && isLength(length) && isIndex(key, length) && - (Array.isArray(object) || isArguments(object)) -} - -export default hasPathIn diff --git a/isBuffer.js b/isBuffer.js deleted file mode 100644 index 1831fe3a2..000000000 --- a/isBuffer.js +++ /dev/null @@ -1,35 +0,0 @@ -import root from './.internal/root.js' - -/** Detect free variable `exports`. */ -const freeExports = typeof exports === 'object' && exports !== null && !exports.nodeType && exports - -/** Detect free variable `module`. */ -const freeModule = freeExports && typeof module === 'object' && module !== null && !module.nodeType && module - -/** Detect the popular CommonJS extension `module.exports`. */ -const moduleExports = freeModule && freeModule.exports === freeExports - -/** Built-in value references. */ -const Buffer = moduleExports ? root.Buffer : undefined - -/* Built-in method references for those with the same name as other `lodash` methods. */ -const nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined - -/** - * Checks if `value` is a buffer. - * - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. - * @example - * - * isBuffer(new Buffer(2)) - * // => true - * - * isBuffer(new Uint8Array(2)) - * // => false - */ -const isBuffer = nativeIsBuffer || (() => false) - -export default isBuffer diff --git a/isEmpty.js b/isEmpty.js deleted file mode 100644 index 346b05140..000000000 --- a/isEmpty.js +++ /dev/null @@ -1,69 +0,0 @@ -import getTag from './.internal/getTag.js' -import isArguments from './isArguments.js' -import isArrayLike from './isArrayLike.js' -import isBuffer from './isBuffer.js' -import isPrototype from './.internal/isPrototype.js' -import isTypedArray from './isTypedArray.js' - -/** Used to check objects for own properties. */ -const hasOwnProperty = Object.prototype.hasOwnProperty - -/** - * Checks if `value` is an empty object, collection, map, or set. - * - * Objects are considered empty if they have no own enumerable string keyed - * properties. - * - * Array-like values such as `arguments` objects, arrays, buffers, strings, or - * jQuery-like collections are considered empty if they have a `length` of `0`. - * Similarly, maps and sets are considered empty if they have a `size` of `0`. - * - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @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('abc') - * // => false - * - * isEmpty({ 'a': 1 }) - * // => false - */ -function isEmpty(value) { - if (value == null) { - return true - } - if (isArrayLike(value) && - (Array.isArray(value) || typeof value === 'string' || typeof value.splice === 'function' || - isBuffer(value) || isTypedArray(value) || isArguments(value))) { - return !value.length - } - const tag = getTag(value) - if (tag == '[object Map]' || tag == '[object Set]') { - return !value.size - } - if (isPrototype(value)) { - return !Object.keys(value).length - } - for (const key in value) { - if (hasOwnProperty.call(value, key)) { - return false - } - } - return true -} - -export default isEmpty diff --git a/isError.js b/isError.js deleted file mode 100644 index 1e85ff5a8..000000000 --- a/isError.js +++ /dev/null @@ -1,30 +0,0 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' -import isPlainObject from './isPlainObject.js' - -/** - * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, - * `SyntaxError`, `TypeError`, or `URIError` object. - * - * @since 3.0.0 - * @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) { - if (!isObjectLike(value)) { - return false - } - const tag = getTag(value) - return tag == '[object Error]' || tag == '[object DOMException]' || - (typeof value.message === 'string' && typeof value.name === 'string' && !isPlainObject(value)) -} - -export default isError diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index d46ba027a..000000000 --- a/package-lock.json +++ /dev/null @@ -1,1697 +0,0 @@ -{ - "name": "lodash", - "version": "5.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@eslint/eslintrc": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", - "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } - } - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "dependencies": { - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - } - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-includes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", - "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "get-intrinsic": "^1.0.1", - "is-string": "^1.0.5" - } - }, - "array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - } - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "call-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", - "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz", - "integrity": "sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^6.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.4", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-plugin-import": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", - "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", - "dev": true, - "requires": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.4", - "eslint-module-utils": "^2.6.0", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - }, - "esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "file-entry-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", - "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", - "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "get-intrinsic": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", - "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", - "dev": true - }, - "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } - }, - "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", - "dev": true, - "requires": { - "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.5", - "he": "1.1.1", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "supports-color": "5.4.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.values": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", - "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - } - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - } - } - }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "requires": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - }, - "dependencies": { - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - } - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.4.tgz", - "integrity": "sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "lodash": "^4.17.20", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } - } - }, - "v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - } - } -} diff --git a/package.json b/package.json index 622676b99..c97bbf821 100644 --- a/package.json +++ b/package.json @@ -3,21 +3,48 @@ "version": "5.0.0", "license": "MIT", "private": true, - "main": "lodash.js", - "engines": { - "node": ">=4.0.0" - }, + "main": "dist/lodash.js", "sideEffects": false, "scripts": { - "style": "eslint *.js .internal/**/*.js", - "test": "mocha -r esm test/*.test.js", - "validate": "npm run style && npm run test" + "prepare": "husky install", + "lint": "eslint ./src/**/*.ts ./test/**/*.ts" }, "devDependencies": { - "mocha": "^5.2.0", - "eslint": "^7.16.0", - "eslint-plugin-import": "^2.22.1", - "lodash": "4.17.20", - "esm": "^3.2.25" - } + "@commitlint/cli": "17.7.1", + "@commitlint/config-conventional": "17.7.0", + "@types/eslint": "8.44.2", + "@types/jest": "29.5.5", + "@typescript-eslint/eslint-plugin": "6.7.0", + "@typescript-eslint/parser": "6.7.0", + "eslint": "8.49.0", + "eslint-config-airbnb-base": "15.0.0", + "eslint-config-airbnb-typescript": "17.1.0", + "eslint-config-prettier": "9.0.0", + "eslint-plugin-import": "2.28.1", + "eslint-plugin-prettier": "5.0.0", + "husky": "8.0.3", + "lint-staged": "14.0.1", + "lodash": "4.17.21", + "prettier": "3.0.3" + }, + "lint-staged": { + "src/**/*.{ts}": [ + "eslint --fix" + ] + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged", + "commit-msg": "bun run commitlint --edit $1" + } + }, + "engines": { + "node": "^18.17.1", + "yarn": "^1.22.19" + }, + "volta": { + "node": "18.17.1", + "yarn": "1.22.19" + }, + "engineStrict": true } diff --git a/repeat.js b/repeat.js deleted file mode 100644 index 89d8403da..000000000 --- a/repeat.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Repeats the given string `n` times. - * - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to repeat. - * @param {number} [n=1] 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) { - let result = '' - if (!string || n < 1 || n > Number.MAX_SAFE_INTEGER) { - 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 = Math.floor(n / 2) - if (n) { - string += string - } - } while (n) - - return result -} - -export default repeat diff --git a/sampleSize.js b/sampleSize.js deleted file mode 100644 index 265713cbf..000000000 --- a/sampleSize.js +++ /dev/null @@ -1,40 +0,0 @@ -import copyArray from './.internal/copyArray.js' -import slice from './slice.js' - -/** - * Gets `n` random elements at unique keys from `array` up to the - * size of `array`. - * - * @since 4.0.0 - * @category Array - * @param {Array} array The array to sample. - * @param {number} [n=1] The number of elements to sample. - * @returns {Array} Returns the random elements. - * @example - * - * sampleSize([1, 2, 3], 2) - * // => [3, 1] - * - * sampleSize([1, 2, 3], 4) - * // => [2, 3, 1] - */ -function sampleSize(array, n) { - n = n == null ? 1 : n - const length = array == null ? 0 : array.length - if (!length || n < 1) { - return [] - } - n = n > length ? length : n - let index = -1 - const lastIndex = length - 1 - const result = copyArray(array) - while (++index < n) { - const rand = index + Math.floor(Math.random() * (lastIndex - index + 1)) - const value = result[rand] - result[rand] = result[index] - result[index] = value - } - return slice(result, 0, n) -} - -export default sampleSize diff --git a/shuffle.js b/shuffle.js deleted file mode 100644 index dc45d1230..000000000 --- a/shuffle.js +++ /dev/null @@ -1,33 +0,0 @@ -import copyArray from './.internal/copyArray.js' - -/** - * Creates an array of shuffled values, using a version of the - * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). - * - * @since 0.1.0 - * @category Array - * @param {Array} array The array to shuffle. - * @returns {Array} Returns the new shuffled array. - * @example - * - * shuffle([1, 2, 3, 4]) - * // => [4, 1, 3, 2] - */ -function shuffle(array) { - const length = array == null ? 0 : array.length - if (!length) { - return [] - } - let index = -1 - const lastIndex = length - 1 - const result = copyArray(array) - while (++index < length) { - const rand = index + Math.floor(Math.random() * (lastIndex - index + 1)) - const value = result[rand] - result[rand] = result[index] - result[index] = value - } - return result -} - -export default shuffle diff --git a/size.js b/size.js deleted file mode 100644 index 831011e56..000000000 --- a/size.js +++ /dev/null @@ -1,43 +0,0 @@ -import getTag from './.internal/getTag.js' -import isArrayLike from './isArrayLike.js' -import isString from './isString.js' -import stringSize from './.internal/stringSize.js' - -/** `Object#toString` result references. */ -const mapTag = '[object Map]' -const setTag = '[object Set]' - -/** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable string keyed properties for objects. - * - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the collection size. - * @example - * - * size([1, 2, 3]) - * // => 3 - * - * size({ 'a': 1, 'b': 2 }) - * // => 2 - * - * size('pebbles') - * // => 7 - */ -function size(collection) { - if (collection == null) { - return 0 - } - if (isArrayLike(collection)) { - return isString(collection) ? stringSize(collection) : collection.length - } - const tag = getTag(collection) - if (tag == mapTag || tag == setTag) { - return collection.size - } - return Object.keys(collection).length -} - -export default size diff --git a/split.js b/split.js deleted file mode 100644 index e997c4a7f..000000000 --- a/split.js +++ /dev/null @@ -1,42 +0,0 @@ -import castSlice from './.internal/castSlice.js' -import hasUnicode from './.internal/hasUnicode.js' -import isRegExp from './isRegExp.js' -import stringToArray from './.internal/stringToArray.js' - -/** Used as references for the maximum length and index of an array. */ -const MAX_ARRAY_LENGTH = 4294967295 - -/** - * Splits `string` by `separator`. - * - * **Note:** This method is based on - * [`String#split`](https://mdn.io/String/split). - * - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to split. - * @param {RegExp|string} separator The separator pattern to split by. - * @param {number} [limit] The length to truncate results to. - * @returns {Array} Returns the string segments. - * @example - * - * split('a-b-c', '-', 2) - * // => ['a', 'b'] - */ -function split(string, separator, limit) { - limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0 - if (!limit) { - return [] - } - if (string && ( - typeof separator === 'string' || - (separator != null && !isRegExp(separator)) - )) { - if (!separator && hasUnicode(string)) { - return castSlice(stringToArray(string), 0, limit) - } - } - return string.split(separator, limit) -} - -export default split diff --git a/src/.eslintrc.cjs b/src/.eslintrc.cjs new file mode 100644 index 000000000..66ca1ac78 --- /dev/null +++ b/src/.eslintrc.cjs @@ -0,0 +1,18 @@ +'use strict'; + +const path = require('node:path'); + +module.exports = { + overrides: [ + { + files: ['**/*.{ts}'], + rules: { + 'import/no-extraneous-dependencies': [ + 'error', + // Use package.json from both this package folder and root. + { packageDir: [__dirname, path.join(__dirname, '../')] }, + ], + }, + }, + ], +}; diff --git a/.internal/Hash.js b/src/.internal/Hash.ts similarity index 100% rename from .internal/Hash.js rename to src/.internal/Hash.ts diff --git a/.internal/ListCache.js b/src/.internal/ListCache.ts similarity index 100% rename from .internal/ListCache.js rename to src/.internal/ListCache.ts diff --git a/.internal/MapCache.js b/src/.internal/MapCache.ts similarity index 100% rename from .internal/MapCache.js rename to src/.internal/MapCache.ts diff --git a/.internal/SetCache.js b/src/.internal/SetCache.ts similarity index 100% rename from .internal/SetCache.js rename to src/.internal/SetCache.ts diff --git a/.internal/Stack.js b/src/.internal/Stack.ts similarity index 100% rename from .internal/Stack.js rename to src/.internal/Stack.ts diff --git a/.internal/addMapEntry.js b/src/.internal/addMapEntry.ts similarity index 100% rename from .internal/addMapEntry.js rename to src/.internal/addMapEntry.ts diff --git a/.internal/addSetEntry.js b/src/.internal/addSetEntry.ts similarity index 100% rename from .internal/addSetEntry.js rename to src/.internal/addSetEntry.ts diff --git a/.internal/arrayEach.js b/src/.internal/arrayEach.ts similarity index 100% rename from .internal/arrayEach.js rename to src/.internal/arrayEach.ts diff --git a/.internal/arrayEachRight.js b/src/.internal/arrayEachRight.ts similarity index 100% rename from .internal/arrayEachRight.js rename to src/.internal/arrayEachRight.ts diff --git a/.internal/arrayIncludes.js b/src/.internal/arrayIncludes.ts similarity index 100% rename from .internal/arrayIncludes.js rename to src/.internal/arrayIncludes.ts diff --git a/.internal/arrayIncludesWith.js b/src/.internal/arrayIncludesWith.ts similarity index 100% rename from .internal/arrayIncludesWith.js rename to src/.internal/arrayIncludesWith.ts diff --git a/.internal/arrayLikeKeys.js b/src/.internal/arrayLikeKeys.ts similarity index 100% rename from .internal/arrayLikeKeys.js rename to src/.internal/arrayLikeKeys.ts diff --git a/.internal/arrayReduce.js b/src/.internal/arrayReduce.ts similarity index 100% rename from .internal/arrayReduce.js rename to src/.internal/arrayReduce.ts diff --git a/.internal/arrayReduceRight.js b/src/.internal/arrayReduceRight.ts similarity index 100% rename from .internal/arrayReduceRight.js rename to src/.internal/arrayReduceRight.ts diff --git a/.internal/asciiSize.js b/src/.internal/asciiSize.ts similarity index 100% rename from .internal/asciiSize.js rename to src/.internal/asciiSize.ts diff --git a/.internal/asciiToArray.js b/src/.internal/asciiToArray.ts similarity index 100% rename from .internal/asciiToArray.js rename to src/.internal/asciiToArray.ts diff --git a/.internal/assignMergeValue.js b/src/.internal/assignMergeValue.ts similarity index 100% rename from .internal/assignMergeValue.js rename to src/.internal/assignMergeValue.ts diff --git a/.internal/assignValue.js b/src/.internal/assignValue.ts similarity index 100% rename from .internal/assignValue.js rename to src/.internal/assignValue.ts diff --git a/.internal/assocIndexOf.js b/src/.internal/assocIndexOf.ts similarity index 100% rename from .internal/assocIndexOf.js rename to src/.internal/assocIndexOf.ts diff --git a/.internal/baseAssignValue.js b/src/.internal/baseAssignValue.ts similarity index 100% rename from .internal/baseAssignValue.js rename to src/.internal/baseAssignValue.ts diff --git a/.internal/baseAt.js b/src/.internal/baseAt.ts similarity index 100% rename from .internal/baseAt.js rename to src/.internal/baseAt.ts diff --git a/.internal/baseClone.js b/src/.internal/baseClone.ts similarity index 100% rename from .internal/baseClone.js rename to src/.internal/baseClone.ts diff --git a/.internal/baseConforms.js b/src/.internal/baseConforms.ts similarity index 100% rename from .internal/baseConforms.js rename to src/.internal/baseConforms.ts diff --git a/.internal/baseConformsTo.js b/src/.internal/baseConformsTo.ts similarity index 100% rename from .internal/baseConformsTo.js rename to src/.internal/baseConformsTo.ts diff --git a/.internal/baseDifference.js b/src/.internal/baseDifference.ts similarity index 100% rename from .internal/baseDifference.js rename to src/.internal/baseDifference.ts diff --git a/.internal/baseEach.js b/src/.internal/baseEach.ts similarity index 100% rename from .internal/baseEach.js rename to src/.internal/baseEach.ts diff --git a/.internal/baseEachRight.js b/src/.internal/baseEachRight.ts similarity index 100% rename from .internal/baseEachRight.js rename to src/.internal/baseEachRight.ts diff --git a/.internal/baseFindIndex.js b/src/.internal/baseFindIndex.ts similarity index 100% rename from .internal/baseFindIndex.js rename to src/.internal/baseFindIndex.ts diff --git a/.internal/baseFindKey.js b/src/.internal/baseFindKey.ts similarity index 100% rename from .internal/baseFindKey.js rename to src/.internal/baseFindKey.ts diff --git a/.internal/baseFlatten.js b/src/.internal/baseFlatten.ts similarity index 100% rename from .internal/baseFlatten.js rename to src/.internal/baseFlatten.ts diff --git a/.internal/baseFor.js b/src/.internal/baseFor.ts similarity index 100% rename from .internal/baseFor.js rename to src/.internal/baseFor.ts diff --git a/.internal/baseForOwn.js b/src/.internal/baseForOwn.ts similarity index 100% rename from .internal/baseForOwn.js rename to src/.internal/baseForOwn.ts diff --git a/.internal/baseForOwnRight.js b/src/.internal/baseForOwnRight.ts similarity index 100% rename from .internal/baseForOwnRight.js rename to src/.internal/baseForOwnRight.ts diff --git a/.internal/baseForRight.js b/src/.internal/baseForRight.ts similarity index 100% rename from .internal/baseForRight.js rename to src/.internal/baseForRight.ts diff --git a/.internal/baseGet.js b/src/.internal/baseGet.ts similarity index 100% rename from .internal/baseGet.js rename to src/.internal/baseGet.ts diff --git a/.internal/baseInRange.js b/src/.internal/baseInRange.ts similarity index 100% rename from .internal/baseInRange.js rename to src/.internal/baseInRange.ts diff --git a/.internal/baseIndexOf.js b/src/.internal/baseIndexOf.ts similarity index 100% rename from .internal/baseIndexOf.js rename to src/.internal/baseIndexOf.ts diff --git a/.internal/baseIndexOfWith.js b/src/.internal/baseIndexOfWith.ts similarity index 100% rename from .internal/baseIndexOfWith.js rename to src/.internal/baseIndexOfWith.ts diff --git a/.internal/baseIntersection.js b/src/.internal/baseIntersection.ts similarity index 100% rename from .internal/baseIntersection.js rename to src/.internal/baseIntersection.ts diff --git a/.internal/baseIsEqual.js b/src/.internal/baseIsEqual.ts similarity index 100% rename from .internal/baseIsEqual.js rename to src/.internal/baseIsEqual.ts diff --git a/.internal/baseIsEqualDeep.js b/src/.internal/baseIsEqualDeep.ts similarity index 100% rename from .internal/baseIsEqualDeep.js rename to src/.internal/baseIsEqualDeep.ts diff --git a/.internal/baseIsMatch.js b/src/.internal/baseIsMatch.ts similarity index 100% rename from .internal/baseIsMatch.js rename to src/.internal/baseIsMatch.ts diff --git a/.internal/baseIsNaN.js b/src/.internal/baseIsNaN.ts similarity index 100% rename from .internal/baseIsNaN.js rename to src/.internal/baseIsNaN.ts diff --git a/.internal/baseMatches.js b/src/.internal/baseMatches.ts similarity index 100% rename from .internal/baseMatches.js rename to src/.internal/baseMatches.ts diff --git a/.internal/baseMatchesProperty.js b/src/.internal/baseMatchesProperty.ts similarity index 100% rename from .internal/baseMatchesProperty.js rename to src/.internal/baseMatchesProperty.ts diff --git a/.internal/baseMerge.js b/src/.internal/baseMerge.ts similarity index 100% rename from .internal/baseMerge.js rename to src/.internal/baseMerge.ts diff --git a/.internal/baseMergeDeep.js b/src/.internal/baseMergeDeep.ts similarity index 100% rename from .internal/baseMergeDeep.js rename to src/.internal/baseMergeDeep.ts diff --git a/.internal/baseOrderBy.js b/src/.internal/baseOrderBy.ts similarity index 100% rename from .internal/baseOrderBy.js rename to src/.internal/baseOrderBy.ts diff --git a/.internal/basePick.js b/src/.internal/basePick.ts similarity index 100% rename from .internal/basePick.js rename to src/.internal/basePick.ts diff --git a/.internal/basePickBy.js b/src/.internal/basePickBy.ts similarity index 100% rename from .internal/basePickBy.js rename to src/.internal/basePickBy.ts diff --git a/.internal/baseProperty.js b/src/.internal/baseProperty.ts similarity index 100% rename from .internal/baseProperty.js rename to src/.internal/baseProperty.ts diff --git a/.internal/basePropertyDeep.js b/src/.internal/basePropertyDeep.ts similarity index 100% rename from .internal/basePropertyDeep.js rename to src/.internal/basePropertyDeep.ts diff --git a/.internal/basePropertyOf.js b/src/.internal/basePropertyOf.ts similarity index 100% rename from .internal/basePropertyOf.js rename to src/.internal/basePropertyOf.ts diff --git a/.internal/basePullAll.js b/src/.internal/basePullAll.ts similarity index 100% rename from .internal/basePullAll.js rename to src/.internal/basePullAll.ts diff --git a/.internal/basePullAt.js b/src/.internal/basePullAt.ts similarity index 100% rename from .internal/basePullAt.js rename to src/.internal/basePullAt.ts diff --git a/.internal/baseRange.js b/src/.internal/baseRange.ts similarity index 100% rename from .internal/baseRange.js rename to src/.internal/baseRange.ts diff --git a/.internal/baseReduce.js b/src/.internal/baseReduce.ts similarity index 100% rename from .internal/baseReduce.js rename to src/.internal/baseReduce.ts diff --git a/.internal/baseSet.js b/src/.internal/baseSet.ts similarity index 100% rename from .internal/baseSet.js rename to src/.internal/baseSet.ts diff --git a/.internal/baseSortBy.js b/src/.internal/baseSortBy.ts similarity index 100% rename from .internal/baseSortBy.js rename to src/.internal/baseSortBy.ts diff --git a/.internal/baseSortedIndex.js b/src/.internal/baseSortedIndex.ts similarity index 100% rename from .internal/baseSortedIndex.js rename to src/.internal/baseSortedIndex.ts diff --git a/.internal/baseSortedIndexBy.js b/src/.internal/baseSortedIndexBy.ts similarity index 100% rename from .internal/baseSortedIndexBy.js rename to src/.internal/baseSortedIndexBy.ts diff --git a/.internal/baseSortedUniq.js b/src/.internal/baseSortedUniq.ts similarity index 100% rename from .internal/baseSortedUniq.js rename to src/.internal/baseSortedUniq.ts diff --git a/.internal/baseSum.js b/src/.internal/baseSum.ts similarity index 100% rename from .internal/baseSum.js rename to src/.internal/baseSum.ts diff --git a/.internal/baseToNumber.js b/src/.internal/baseToNumber.ts similarity index 100% rename from .internal/baseToNumber.js rename to src/.internal/baseToNumber.ts diff --git a/.internal/baseToString.js b/src/.internal/baseToString.ts similarity index 100% rename from .internal/baseToString.js rename to src/.internal/baseToString.ts diff --git a/.internal/baseUniq.js b/src/.internal/baseUniq.ts similarity index 100% rename from .internal/baseUniq.js rename to src/.internal/baseUniq.ts diff --git a/.internal/baseUnset.js b/src/.internal/baseUnset.ts similarity index 100% rename from .internal/baseUnset.js rename to src/.internal/baseUnset.ts diff --git a/.internal/baseUpdate.js b/src/.internal/baseUpdate.ts similarity index 100% rename from .internal/baseUpdate.js rename to src/.internal/baseUpdate.ts diff --git a/.internal/baseValues.js b/src/.internal/baseValues.ts similarity index 100% rename from .internal/baseValues.js rename to src/.internal/baseValues.ts diff --git a/.internal/baseWhile.js b/src/.internal/baseWhile.ts similarity index 100% rename from .internal/baseWhile.js rename to src/.internal/baseWhile.ts diff --git a/.internal/baseXor.js b/src/.internal/baseXor.ts similarity index 100% rename from .internal/baseXor.js rename to src/.internal/baseXor.ts diff --git a/.internal/baseZipObject.js b/src/.internal/baseZipObject.ts similarity index 100% rename from .internal/baseZipObject.js rename to src/.internal/baseZipObject.ts diff --git a/.internal/cacheHas.js b/src/.internal/cacheHas.ts similarity index 100% rename from .internal/cacheHas.js rename to src/.internal/cacheHas.ts diff --git a/.internal/castArrayLikeObject.js b/src/.internal/castArrayLikeObject.ts similarity index 100% rename from .internal/castArrayLikeObject.js rename to src/.internal/castArrayLikeObject.ts diff --git a/.internal/castPath.js b/src/.internal/castPath.ts similarity index 100% rename from .internal/castPath.js rename to src/.internal/castPath.ts diff --git a/.internal/castSlice.js b/src/.internal/castSlice.ts similarity index 100% rename from .internal/castSlice.js rename to src/.internal/castSlice.ts diff --git a/.internal/charsEndIndex.js b/src/.internal/charsEndIndex.ts similarity index 100% rename from .internal/charsEndIndex.js rename to src/.internal/charsEndIndex.ts diff --git a/.internal/charsStartIndex.js b/src/.internal/charsStartIndex.ts similarity index 100% rename from .internal/charsStartIndex.js rename to src/.internal/charsStartIndex.ts diff --git a/.internal/cloneArrayBuffer.js b/src/.internal/cloneArrayBuffer.ts similarity index 100% rename from .internal/cloneArrayBuffer.js rename to src/.internal/cloneArrayBuffer.ts diff --git a/.internal/cloneBuffer.js b/src/.internal/cloneBuffer.ts similarity index 100% rename from .internal/cloneBuffer.js rename to src/.internal/cloneBuffer.ts diff --git a/.internal/cloneDataView.js b/src/.internal/cloneDataView.ts similarity index 100% rename from .internal/cloneDataView.js rename to src/.internal/cloneDataView.ts diff --git a/.internal/cloneRegExp.js b/src/.internal/cloneRegExp.ts similarity index 100% rename from .internal/cloneRegExp.js rename to src/.internal/cloneRegExp.ts diff --git a/.internal/cloneSymbol.js b/src/.internal/cloneSymbol.ts similarity index 100% rename from .internal/cloneSymbol.js rename to src/.internal/cloneSymbol.ts diff --git a/.internal/cloneTypedArray.js b/src/.internal/cloneTypedArray.ts similarity index 100% rename from .internal/cloneTypedArray.js rename to src/.internal/cloneTypedArray.ts diff --git a/.internal/compareAscending.js b/src/.internal/compareAscending.ts similarity index 100% rename from .internal/compareAscending.js rename to src/.internal/compareAscending.ts diff --git a/.internal/compareMultiple.js b/src/.internal/compareMultiple.ts similarity index 100% rename from .internal/compareMultiple.js rename to src/.internal/compareMultiple.ts diff --git a/.internal/composeArgs.js b/src/.internal/composeArgs.ts similarity index 100% rename from .internal/composeArgs.js rename to src/.internal/composeArgs.ts diff --git a/.internal/composeArgsRight.js b/src/.internal/composeArgsRight.ts similarity index 100% rename from .internal/composeArgsRight.js rename to src/.internal/composeArgsRight.ts diff --git a/.internal/copyArray.js b/src/.internal/copyArray.ts similarity index 100% rename from .internal/copyArray.js rename to src/.internal/copyArray.ts diff --git a/.internal/copyObject.js b/src/.internal/copyObject.ts similarity index 100% rename from .internal/copyObject.js rename to src/.internal/copyObject.ts diff --git a/.internal/copySymbols.js b/src/.internal/copySymbols.ts similarity index 100% rename from .internal/copySymbols.js rename to src/.internal/copySymbols.ts diff --git a/.internal/copySymbolsIn.js b/src/.internal/copySymbolsIn.ts similarity index 100% rename from .internal/copySymbolsIn.js rename to src/.internal/copySymbolsIn.ts diff --git a/.internal/createAssigner.js b/src/.internal/createAssigner.ts similarity index 100% rename from .internal/createAssigner.js rename to src/.internal/createAssigner.ts diff --git a/.internal/createCaseFirst.js b/src/.internal/createCaseFirst.ts similarity index 100% rename from .internal/createCaseFirst.js rename to src/.internal/createCaseFirst.ts diff --git a/.internal/createMathOperation.js b/src/.internal/createMathOperation.ts similarity index 100% rename from .internal/createMathOperation.js rename to src/.internal/createMathOperation.ts diff --git a/.internal/createPadding.js b/src/.internal/createPadding.ts similarity index 100% rename from .internal/createPadding.js rename to src/.internal/createPadding.ts diff --git a/.internal/createRange.js b/src/.internal/createRange.ts similarity index 100% rename from .internal/createRange.js rename to src/.internal/createRange.ts diff --git a/.internal/createRound.js b/src/.internal/createRound.ts similarity index 100% rename from .internal/createRound.js rename to src/.internal/createRound.ts diff --git a/.internal/createSet.js b/src/.internal/createSet.ts similarity index 100% rename from .internal/createSet.js rename to src/.internal/createSet.ts diff --git a/.internal/customDefaultsMerge.js b/src/.internal/customDefaultsMerge.ts similarity index 100% rename from .internal/customDefaultsMerge.js rename to src/.internal/customDefaultsMerge.ts diff --git a/.internal/deburrLetter.js b/src/.internal/deburrLetter.ts similarity index 100% rename from .internal/deburrLetter.js rename to src/.internal/deburrLetter.ts diff --git a/.internal/equalArrays.js b/src/.internal/equalArrays.ts similarity index 100% rename from .internal/equalArrays.js rename to src/.internal/equalArrays.ts diff --git a/.internal/equalByTag.js b/src/.internal/equalByTag.ts similarity index 100% rename from .internal/equalByTag.js rename to src/.internal/equalByTag.ts diff --git a/.internal/equalObjects.js b/src/.internal/equalObjects.ts similarity index 100% rename from .internal/equalObjects.js rename to src/.internal/equalObjects.ts diff --git a/.internal/freeGlobal.js b/src/.internal/freeGlobal.ts similarity index 100% rename from .internal/freeGlobal.js rename to src/.internal/freeGlobal.ts diff --git a/.internal/getAllKeys.js b/src/.internal/getAllKeys.ts similarity index 100% rename from .internal/getAllKeys.js rename to src/.internal/getAllKeys.ts diff --git a/.internal/getAllKeysIn.js b/src/.internal/getAllKeysIn.ts similarity index 100% rename from .internal/getAllKeysIn.js rename to src/.internal/getAllKeysIn.ts diff --git a/.internal/getHolder.js b/src/.internal/getHolder.ts similarity index 100% rename from .internal/getHolder.js rename to src/.internal/getHolder.ts diff --git a/.internal/getMatchData.js b/src/.internal/getMatchData.ts similarity index 100% rename from .internal/getMatchData.js rename to src/.internal/getMatchData.ts diff --git a/.internal/getSymbols.js b/src/.internal/getSymbols.ts similarity index 100% rename from .internal/getSymbols.js rename to src/.internal/getSymbols.ts diff --git a/.internal/getSymbolsIn.js b/src/.internal/getSymbolsIn.ts similarity index 100% rename from .internal/getSymbolsIn.js rename to src/.internal/getSymbolsIn.ts diff --git a/.internal/getTag.js b/src/.internal/getTag.ts similarity index 100% rename from .internal/getTag.js rename to src/.internal/getTag.ts diff --git a/.internal/hasUnicode.js b/src/.internal/hasUnicode.ts similarity index 100% rename from .internal/hasUnicode.js rename to src/.internal/hasUnicode.ts diff --git a/.internal/initCloneObject.js b/src/.internal/initCloneObject.ts similarity index 100% rename from .internal/initCloneObject.js rename to src/.internal/initCloneObject.ts diff --git a/.internal/isFlattenable.js b/src/.internal/isFlattenable.ts similarity index 100% rename from .internal/isFlattenable.js rename to src/.internal/isFlattenable.ts diff --git a/.internal/isIndex.js b/src/.internal/isIndex.ts similarity index 100% rename from .internal/isIndex.js rename to src/.internal/isIndex.ts diff --git a/.internal/isIterateeCall.js b/src/.internal/isIterateeCall.ts similarity index 100% rename from .internal/isIterateeCall.js rename to src/.internal/isIterateeCall.ts diff --git a/.internal/isKey.js b/src/.internal/isKey.ts similarity index 100% rename from .internal/isKey.js rename to src/.internal/isKey.ts diff --git a/.internal/isPrototype.js b/src/.internal/isPrototype.ts similarity index 100% rename from .internal/isPrototype.js rename to src/.internal/isPrototype.ts diff --git a/.internal/isStrictComparable.js b/src/.internal/isStrictComparable.ts similarity index 100% rename from .internal/isStrictComparable.js rename to src/.internal/isStrictComparable.ts diff --git a/.internal/iteratorToArray.js b/src/.internal/iteratorToArray.ts similarity index 100% rename from .internal/iteratorToArray.js rename to src/.internal/iteratorToArray.ts diff --git a/.internal/mapToArray.js b/src/.internal/mapToArray.ts similarity index 100% rename from .internal/mapToArray.js rename to src/.internal/mapToArray.ts diff --git a/.internal/matchesStrictComparable.js b/src/.internal/matchesStrictComparable.ts similarity index 100% rename from .internal/matchesStrictComparable.js rename to src/.internal/matchesStrictComparable.ts diff --git a/.internal/memoizeCapped.js b/src/.internal/memoizeCapped.ts similarity index 100% rename from .internal/memoizeCapped.js rename to src/.internal/memoizeCapped.ts diff --git a/.internal/metaMap.js b/src/.internal/metaMap.ts similarity index 100% rename from .internal/metaMap.js rename to src/.internal/metaMap.ts diff --git a/.internal/nodeTypes.js b/src/.internal/nodeTypes.ts similarity index 100% rename from .internal/nodeTypes.js rename to src/.internal/nodeTypes.ts diff --git a/.internal/parent.js b/src/.internal/parent.ts similarity index 100% rename from .internal/parent.js rename to src/.internal/parent.ts diff --git a/.internal/reEscape.js b/src/.internal/reEscape.ts similarity index 100% rename from .internal/reEscape.js rename to src/.internal/reEscape.ts diff --git a/.internal/reEvaluate.js b/src/.internal/reEvaluate.ts similarity index 100% rename from .internal/reEvaluate.js rename to src/.internal/reEvaluate.ts diff --git a/.internal/reInterpolate.js b/src/.internal/reInterpolate.ts similarity index 100% rename from .internal/reInterpolate.js rename to src/.internal/reInterpolate.ts diff --git a/.internal/root.js b/src/.internal/root.ts similarity index 100% rename from .internal/root.js rename to src/.internal/root.ts diff --git a/.internal/setToArray.js b/src/.internal/setToArray.ts similarity index 100% rename from .internal/setToArray.js rename to src/.internal/setToArray.ts diff --git a/.internal/setToPairs.js b/src/.internal/setToPairs.ts similarity index 100% rename from .internal/setToPairs.js rename to src/.internal/setToPairs.ts diff --git a/.internal/setToString.js b/src/.internal/setToString.ts similarity index 100% rename from .internal/setToString.js rename to src/.internal/setToString.ts diff --git a/.internal/strictIndexOf.js b/src/.internal/strictIndexOf.ts similarity index 100% rename from .internal/strictIndexOf.js rename to src/.internal/strictIndexOf.ts diff --git a/.internal/strictLastIndexOf.js b/src/.internal/strictLastIndexOf.ts similarity index 100% rename from .internal/strictLastIndexOf.js rename to src/.internal/strictLastIndexOf.ts diff --git a/.internal/stringSize.js b/src/.internal/stringSize.ts similarity index 100% rename from .internal/stringSize.js rename to src/.internal/stringSize.ts diff --git a/.internal/stringToArray.js b/src/.internal/stringToArray.ts similarity index 100% rename from .internal/stringToArray.js rename to src/.internal/stringToArray.ts diff --git a/.internal/stringToPath.js b/src/.internal/stringToPath.ts similarity index 100% rename from .internal/stringToPath.js rename to src/.internal/stringToPath.ts diff --git a/.internal/toKey.js b/src/.internal/toKey.ts similarity index 100% rename from .internal/toKey.js rename to src/.internal/toKey.ts diff --git a/.internal/unicodeSize.js b/src/.internal/unicodeSize.ts similarity index 100% rename from .internal/unicodeSize.js rename to src/.internal/unicodeSize.ts diff --git a/.internal/unicodeToArray.js b/src/.internal/unicodeToArray.ts similarity index 100% rename from .internal/unicodeToArray.js rename to src/.internal/unicodeToArray.ts diff --git a/.internal/unicodeWords.js b/src/.internal/unicodeWords.ts similarity index 100% rename from .internal/unicodeWords.js rename to src/.internal/unicodeWords.ts diff --git a/add.js b/src/add.ts similarity index 91% rename from add.js rename to src/add.ts index 1e6917659..4485c8dfa 100644 --- a/add.js +++ b/src/add.ts @@ -1,4 +1,4 @@ -import createMathOperation from './.internal/createMathOperation.js' +import createMathOperation from './.internal/createMathOperation.js'; /** * Adds two numbers. @@ -13,6 +13,6 @@ import createMathOperation from './.internal/createMathOperation.js' * add(6, 4) * // => 10 */ -const add = createMathOperation((augend, addend) => augend + addend, 0) +const add = createMathOperation((augend, addend) => augend + addend, 0); -export default add +export default add; diff --git a/after.js b/src/after.ts similarity index 72% rename from after.js rename to src/after.ts index dade4fd0c..0c647fbbc 100644 --- a/after.js +++ b/src/after.ts @@ -16,15 +16,15 @@ * // => Logs 'done saving!' after the two async saves have completed. */ function after(n, func) { - if (typeof func !== 'function') { - throw new TypeError('Expected a function') - } - n = n || 0 - return function(...args) { - if (--n < 1) { - return func.apply(this, args) + if (typeof func !== 'function') { + throw new TypeError('Expected a function'); } - } + n = n || 0; + return function (...args) { + if (--n < 1) { + return func.apply(this, args); + } + }; } -export default after +export default after; diff --git a/at.js b/src/at.ts similarity index 79% rename from at.js rename to src/at.ts index 69bcecc0d..b3f2a8b9e 100644 --- a/at.js +++ b/src/at.ts @@ -1,5 +1,5 @@ -import baseAt from './.internal/baseAt.js' -import baseFlatten from './.internal/baseFlatten.js' +import baseAt from './.internal/baseAt.js'; +import baseFlatten from './.internal/baseFlatten.js'; /** * Creates an array of values corresponding to `paths` of `object`. @@ -16,6 +16,6 @@ import baseFlatten from './.internal/baseFlatten.js' * at(object, ['a[0].b.c', 'a[1]']) * // => [3, 4] */ -const at = (object, ...paths) => baseAt(object, baseFlatten(paths, 1)) +const at = (object, ...paths) => baseAt(object, baseFlatten(paths, 1)); -export default at +export default at; diff --git a/attempt.js b/src/attempt.ts similarity index 78% rename from attempt.js rename to src/attempt.ts index ee6c48296..ab1dfe071 100644 --- a/attempt.js +++ b/src/attempt.ts @@ -1,4 +1,4 @@ -import isError from './isError.js' +import isError from './isError.js'; /** * Attempts to invoke `func`, returning either the result or the caught error @@ -20,11 +20,11 @@ import isError from './isError.js' * } */ function attempt(func, ...args) { - try { - return func(...args) - } catch (e) { - return isError(e) ? e : new Error(e) - } + try { + return func(...args); + } catch (e) { + return isError(e) ? e : new Error(e); + } } -export default attempt +export default attempt; diff --git a/before.js b/src/before.ts similarity index 66% rename from before.js rename to src/before.ts index 88ba32f40..e861d8d30 100644 --- a/before.js +++ b/src/before.ts @@ -14,19 +14,19 @@ * // => Allows adding up to 4 contacts to the list. */ function before(n, func) { - let result - if (typeof func !== 'function') { - throw new TypeError('Expected a function') - } - return function(...args) { - if (--n > 0) { - result = func.apply(this, args) + let result; + if (typeof func !== 'function') { + throw new TypeError('Expected a function'); } - if (n <= 1) { - func = undefined - } - return result - } + return function (...args) { + if (--n > 0) { + result = func.apply(this, args); + } + if (n <= 1) { + func = undefined; + } + return result; + }; } -export default before +export default before; diff --git a/camelCase.js b/src/camelCase.ts similarity index 56% rename from camelCase.js rename to src/camelCase.ts index 9882da6f2..c653595e5 100644 --- a/camelCase.js +++ b/src/camelCase.ts @@ -1,6 +1,6 @@ -import upperFirst from './upperFirst.js' -import words from './words.js' -import toString from './toString.js' +import upperFirst from './upperFirst.js'; +import words from './words.js'; +import toString from './toString.js'; /** * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). @@ -21,11 +21,10 @@ import toString from './toString.js' * camelCase('__FOO_BAR__') * // => 'fooBar' */ -const camelCase = (string) => ( - words(toString(string).replace(/['\u2019]/g, '')).reduce((result, word, index) => { - word = word.toLowerCase() - return result + (index ? upperFirst(word) : word) - }, '') -) +const camelCase = (string) => + words(toString(string).replace(/['\u2019]/g, '')).reduce((result, word, index) => { + word = word.toLowerCase(); + return result + (index ? upperFirst(word) : word); + }, ''); -export default camelCase +export default camelCase; diff --git a/capitalize.js b/src/capitalize.ts similarity index 75% rename from capitalize.js rename to src/capitalize.ts index 2ad2ffed9..25ee906a6 100644 --- a/capitalize.js +++ b/src/capitalize.ts @@ -1,5 +1,5 @@ -import upperFirst from './upperFirst.js' -import toString from './toString.js' +import upperFirst from './upperFirst.js'; +import toString from './toString.js'; /** * Converts the first character of `string` to upper case and the remaining @@ -14,7 +14,6 @@ import toString from './toString.js' * capitalize('FRED') * // => 'Fred' */ -const capitalize = (string) => upperFirst(toString(string).toLowerCase()) +const capitalize = (string) => upperFirst(toString(string).toLowerCase()); - -export default capitalize +export default capitalize; diff --git a/castArray.js b/src/castArray.ts similarity index 78% rename from castArray.js rename to src/castArray.ts index d00bd367c..0378acd09 100644 --- a/castArray.js +++ b/src/castArray.ts @@ -1,4 +1,3 @@ - /** * Casts `value` as an array if it's not one. * @@ -31,11 +30,11 @@ * // => true */ function castArray(...args) { - if (!args.length) { - return [] - } - const value = args[0] - return Array.isArray(value) ? value : [value] + if (!args.length) { + return []; + } + const value = args[0]; + return Array.isArray(value) ? value : [value]; } -export default castArray +export default castArray; diff --git a/ceil.js b/src/ceil.ts similarity index 80% rename from ceil.js rename to src/ceil.ts index ffb78b360..6a27e4442 100644 --- a/ceil.js +++ b/src/ceil.ts @@ -1,4 +1,4 @@ -import createRound from './.internal/createRound.js' +import createRound from './.internal/createRound.js'; /** * Computes `number` rounded up to `precision`. (Round up: the smallest integer greater than or equal to a given number.) @@ -19,6 +19,6 @@ import createRound from './.internal/createRound.js' * ceil(6040, -2) * // => 6100 */ -const ceil = createRound('ceil') +const ceil = createRound('ceil'); -export default ceil +export default ceil; diff --git a/chunk.js b/src/chunk.ts similarity index 54% rename from chunk.js rename to src/chunk.ts index 8d57b4b19..91ecfdd74 100644 --- a/chunk.js +++ b/src/chunk.ts @@ -1,5 +1,5 @@ -import slice from './slice.js' -import toInteger from './toInteger.js' +import slice from './slice.js'; +import toInteger from './toInteger.js'; /** * Creates an array of elements split into groups the length of `size`. @@ -20,19 +20,19 @@ import toInteger from './toInteger.js' * // => [['a', 'b', 'c'], ['d']] */ function chunk(array, size = 1) { - size = Math.max(toInteger(size), 0) - const length = array == null ? 0 : array.length - if (!length || size < 1) { - return [] - } - let index = 0 - let resIndex = 0 - const result = new Array(Math.ceil(length / size)) + size = Math.max(toInteger(size), 0); + const length = array == null ? 0 : array.length; + if (!length || size < 1) { + return []; + } + let index = 0; + let resIndex = 0; + const result = new Array(Math.ceil(length / size)); - while (index < length) { - result[resIndex++] = slice(array, index, (index += size)) - } - return result + while (index < length) { + result[resIndex++] = slice(array, index, (index += size)); + } + return result; } -export default chunk +export default chunk; diff --git a/clamp.js b/src/clamp.ts similarity index 56% rename from clamp.js rename to src/clamp.ts index 602377136..244e7a873 100644 --- a/clamp.js +++ b/src/clamp.ts @@ -16,16 +16,16 @@ * // => 5 */ function clamp(number, lower, upper) { - number = +number - lower = +lower - upper = +upper - lower = lower === lower ? lower : 0 - upper = upper === upper ? upper : 0 - if (number === number) { - number = number <= upper ? number : upper - number = number >= lower ? number : lower - } - return number + number = +number; + lower = +lower; + upper = +upper; + lower = lower === lower ? lower : 0; + upper = upper === upper ? upper : 0; + if (number === number) { + number = number <= upper ? number : upper; + number = number >= lower ? number : lower; + } + return number; } -export default clamp +export default clamp; diff --git a/clone.js b/src/clone.ts similarity index 86% rename from clone.js rename to src/clone.ts index 97d084f0d..7fce8feb6 100644 --- a/clone.js +++ b/src/clone.ts @@ -1,7 +1,7 @@ -import baseClone from './.internal/baseClone.js' +import baseClone from './.internal/baseClone.js'; /** Used to compose bitmasks for cloning. */ -const CLONE_SYMBOLS_FLAG = 4 +const CLONE_SYMBOLS_FLAG = 4; /** * Creates a shallow clone of `value`. @@ -29,7 +29,7 @@ const CLONE_SYMBOLS_FLAG = 4 * // => true */ function clone(value) { - return baseClone(value, CLONE_SYMBOLS_FLAG) + return baseClone(value, CLONE_SYMBOLS_FLAG); } -export default clone +export default clone; diff --git a/cloneDeep.js b/src/cloneDeep.ts similarity index 71% rename from cloneDeep.js rename to src/cloneDeep.ts index 390e945fb..7cf3193b6 100644 --- a/cloneDeep.js +++ b/src/cloneDeep.ts @@ -1,8 +1,8 @@ -import baseClone from './.internal/baseClone.js' +import baseClone from './.internal/baseClone.js'; /** Used to compose bitmasks for cloning. */ -const CLONE_DEEP_FLAG = 1 -const CLONE_SYMBOLS_FLAG = 4 +const CLONE_DEEP_FLAG = 1; +const CLONE_SYMBOLS_FLAG = 4; /** * This method is like `clone` except that it recursively clones `value`. @@ -22,7 +22,7 @@ const CLONE_SYMBOLS_FLAG = 4 * // => false */ function cloneDeep(value) { - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG) + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); } -export default cloneDeep +export default cloneDeep; diff --git a/cloneDeepWith.js b/src/cloneDeepWith.ts similarity index 73% rename from cloneDeepWith.js rename to src/cloneDeepWith.ts index 4c29b9eaf..b206a9c85 100644 --- a/cloneDeepWith.js +++ b/src/cloneDeepWith.ts @@ -1,8 +1,8 @@ -import baseClone from './.internal/baseClone.js' +import baseClone from './.internal/baseClone.js'; /** Used to compose bitmasks for cloning. */ -const CLONE_DEEP_FLAG = 1 -const CLONE_SYMBOLS_FLAG = 4 +const CLONE_DEEP_FLAG = 1; +const CLONE_SYMBOLS_FLAG = 4; /** * This method is like `cloneWith` except that it recursively clones `value`. @@ -33,8 +33,8 @@ const CLONE_SYMBOLS_FLAG = 4 * // => 20 */ function cloneDeepWith(value, customizer) { - customizer = typeof customizer === 'function' ? customizer : undefined - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer) + customizer = typeof customizer === 'function' ? customizer : undefined; + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); } -export default cloneDeepWith +export default cloneDeepWith; diff --git a/cloneWith.js b/src/cloneWith.ts similarity index 78% rename from cloneWith.js rename to src/cloneWith.ts index 58da039ce..2661bcfe0 100644 --- a/cloneWith.js +++ b/src/cloneWith.ts @@ -1,7 +1,7 @@ -import baseClone from './.internal/baseClone.js' +import baseClone from './.internal/baseClone.js'; /** Used to compose bitmasks for cloning. */ -const CLONE_SYMBOLS_FLAG = 4 +const CLONE_SYMBOLS_FLAG = 4; /** * This method is like `clone` except that it accepts `customizer` which @@ -33,8 +33,8 @@ const CLONE_SYMBOLS_FLAG = 4 * // => 0 */ function cloneWith(value, customizer) { - customizer = typeof customizer === 'function' ? customizer : undefined - return baseClone(value, CLONE_SYMBOLS_FLAG, customizer) + customizer = typeof customizer === 'function' ? customizer : undefined; + return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); } -export default cloneWith +export default cloneWith; diff --git a/compact.js b/src/compact.ts similarity index 61% rename from compact.js rename to src/compact.ts index 5078673e8..da1aadd07 100644 --- a/compact.js +++ b/src/compact.ts @@ -12,19 +12,19 @@ * // => [1, 2, 3] */ function compact(array) { - let resIndex = 0 - const result = [] + let resIndex = 0; + const result = []; - if (array == null) { - return result - } - - for (const value of array) { - if (value) { - result[resIndex++] = value + if (array == null) { + return result; } - } - return result + + for (const value of array) { + if (value) { + result[resIndex++] = value; + } + } + return result; } -export default compact +export default compact; diff --git a/cond.js b/src/cond.ts similarity index 59% rename from cond.js rename to src/cond.ts index 292711038..a1a55822b 100644 --- a/cond.js +++ b/src/cond.ts @@ -1,4 +1,4 @@ -import map from './map.js' +import map from './map.js'; /** * Creates a function that iterates over `pairs` and invokes the corresponding @@ -28,22 +28,24 @@ import map from './map.js' * // => 'no match' */ function cond(pairs) { - const length = pairs == null ? 0 : pairs.length + const length = pairs == null ? 0 : pairs.length; - pairs = !length ? [] : map(pairs, (pair) => { - if (typeof pair[1] !== 'function') { - throw new TypeError('Expected a function') - } - return [pair[0], pair[1]] - }) + pairs = !length + ? [] + : map(pairs, (pair) => { + if (typeof pair[1] !== 'function') { + throw new TypeError('Expected a function'); + } + return [pair[0], pair[1]]; + }); - return (...args) => { - for (const pair of pairs) { - if (pair[0].apply(this, args)) { - return pair[1].apply(this, args) - } - } - } + return (...args) => { + for (const pair of pairs) { + if (pair[0].apply(this, args)) { + return pair[1].apply(this, args); + } + } + }; } -export default cond +export default cond; diff --git a/conforms.js b/src/conforms.ts similarity index 77% rename from conforms.js rename to src/conforms.ts index 843035eb0..23d6fc9bc 100644 --- a/conforms.js +++ b/src/conforms.ts @@ -1,8 +1,8 @@ -import baseClone from './.internal/baseClone.js' -import baseConforms from './.internal/baseConforms.js' +import baseClone from './.internal/baseClone.js'; +import baseConforms from './.internal/baseConforms.js'; /** Used to compose bitmasks for cloning. */ -const CLONE_DEEP_FLAG = 1 +const CLONE_DEEP_FLAG = 1; /** * Creates a function that invokes the predicate properties of `source` with @@ -27,7 +27,7 @@ const CLONE_DEEP_FLAG = 1 * // => [{ 'a': 1, 'b': 2 }] */ function conforms(source) { - return baseConforms(baseClone(source, CLONE_DEEP_FLAG)) + return baseConforms(baseClone(source, CLONE_DEEP_FLAG)); } -export default conforms +export default conforms; diff --git a/conformsTo.js b/src/conformsTo.ts similarity index 79% rename from conformsTo.js rename to src/conformsTo.ts index ffe47039d..764697dc9 100644 --- a/conformsTo.js +++ b/src/conformsTo.ts @@ -1,5 +1,5 @@ -import baseConformsTo from './.internal/baseConformsTo.js' -import keys from './keys.js' +import baseConformsTo from './.internal/baseConformsTo.js'; +import keys from './keys.js'; /** * Checks if `object` conforms to `source` by invoking the predicate @@ -24,7 +24,7 @@ import keys from './keys.js' * // => false */ function conformsTo(object, source) { - return source == null || baseConformsTo(object, source, keys(source)) + return source == null || baseConformsTo(object, source, keys(source)); } -export default conformsTo +export default conformsTo; diff --git a/countBy.js b/src/countBy.ts similarity index 62% rename from countBy.js rename to src/countBy.ts index 94f45edac..bf427e56b 100644 --- a/countBy.js +++ b/src/countBy.ts @@ -1,8 +1,8 @@ -import baseAssignValue from './.internal/baseAssignValue.js' -import reduce from './reduce.js' +import baseAssignValue from './.internal/baseAssignValue.js'; +import reduce from './reduce.js'; /** Used to check objects for own properties. */ -const hasOwnProperty = Object.prototype.hasOwnProperty +const hasOwnProperty = Object.prototype.hasOwnProperty; /** * Creates an object composed of keys generated from the results of running @@ -27,15 +27,19 @@ const hasOwnProperty = Object.prototype.hasOwnProperty * // => { 'true': 2, 'false': 1 } */ function countBy(collection, iteratee) { - return reduce(collection, (result, value, key) => { - key = iteratee(value) - if (hasOwnProperty.call(result, key)) { - ++result[key] - } else { - baseAssignValue(result, key, 1) - } - return result - }, {}) + return reduce( + collection, + (result, value, key) => { + key = iteratee(value); + if (hasOwnProperty.call(result, key)) { + ++result[key]; + } else { + baseAssignValue(result, key, 1); + } + return result; + }, + {}, + ); } -export default countBy +export default countBy; diff --git a/create.js b/src/create.ts similarity index 78% rename from create.js rename to src/create.ts index cd01b4d53..217de794b 100644 --- a/create.js +++ b/src/create.ts @@ -31,9 +31,9 @@ * // => true */ function create(prototype, properties) { - prototype = prototype === null ? null : Object(prototype) - const result = Object.create(prototype) - return properties == null ? result : Object.assign(result, properties) + prototype = prototype === null ? null : Object(prototype); + const result = Object.create(prototype); + return properties == null ? result : Object.assign(result, properties); } -export default create +export default create; diff --git a/src/debounce.ts b/src/debounce.ts new file mode 100644 index 000000000..ac49cf35a --- /dev/null +++ b/src/debounce.ts @@ -0,0 +1,210 @@ +import isObject from './isObject.js'; +import root from './.internal/root.js'; + +/** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked, or until the next browser frame is drawn. The debounced function + * comes with a `cancel` method to cancel delayed `func` invocations and a + * `flush` method to immediately invoke them. Provide `options` to indicate + * whether `func` should be invoked on the leading and/or trailing edge of the + * `wait` timeout. The `func` is invoked with the last arguments provided to the + * debounced function. 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 debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until the next tick, similar to `setTimeout` with a timeout of `0`. + * + * If `wait` is omitted in an environment with `requestAnimationFrame`, `func` + * invocation will be deferred until the next frame is drawn (typically about + * 16ms). + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `debounce` and `throttle`. + * + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] + * The number of milliseconds to delay; if omitted, `requestAnimationFrame` is + * used (if available). + * @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's 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 clicked, debouncing subsequent calls. + * jQuery(element).on('click', debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })) + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * const debounced = debounce(batchLog, 250, { 'maxWait': 1000 }) + * const source = new EventSource('/stream') + * jQuery(source).on('message', debounced) + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel) + * + * // Check for pending invocations. + * const status = debounced.pending() ? "Pending..." : "Ready" + */ +function debounce(func, wait, options) { + let lastArgs, lastThis, maxWait, result, timerId, lastCallTime; + + let lastInvokeTime = 0; + let leading = false; + let maxing = false; + let trailing = true; + + // Bypass `requestAnimationFrame` by explicitly setting `wait=0`. + const useRAF = !wait && wait !== 0 && typeof root.requestAnimationFrame === 'function'; + + if (typeof func !== 'function') { + throw new TypeError('Expected a function'); + } + wait = +wait || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function invokeFunc(time) { + const args = lastArgs; + const thisArg = lastThis; + + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + + function startTimer(pendingFunc, wait) { + if (useRAF) { + root.cancelAnimationFrame(timerId); + return root.requestAnimationFrame(pendingFunc); + } + return setTimeout(pendingFunc, wait); + } + + function cancelTimer(id) { + if (useRAF) { + return root.cancelAnimationFrame(id); + } + clearTimeout(id); + } + + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = startTimer(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } + + function remainingWait(time) { + const timeSinceLastCall = time - lastCallTime; + const timeSinceLastInvoke = time - lastInvokeTime; + const timeWaiting = wait - timeSinceLastCall; + + return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting; + } + + function shouldInvoke(time) { + const timeSinceLastCall = time - lastCallTime; + const timeSinceLastInvoke = time - lastInvokeTime; + + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return ( + lastCallTime === undefined || + timeSinceLastCall >= wait || + timeSinceLastCall < 0 || + (maxing && timeSinceLastInvoke >= maxWait) + ); + } + + function timerExpired() { + const time = Date.now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = startTimer(timerExpired, remainingWait(time)); + } + + function trailingEdge(time) { + timerId = undefined; + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } + + function cancel() { + if (timerId !== undefined) { + cancelTimer(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } + + function flush() { + return timerId === undefined ? result : trailingEdge(Date.now()); + } + + function pending() { + return timerId !== undefined; + } + + function debounced(...args) { + const time = Date.now(); + const isInvoking = shouldInvoke(time); + + lastArgs = args; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = startTimer(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = startTimer(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + debounced.pending = pending; + return debounced; +} + +export default debounce; diff --git a/deburr.js b/src/deburr.ts similarity index 58% rename from deburr.js rename to src/deburr.ts index 8475fab62..1abb09bc0 100644 --- a/deburr.js +++ b/src/deburr.ts @@ -1,24 +1,29 @@ -import deburrLetter from './.internal/deburrLetter.js' +import deburrLetter from './.internal/deburrLetter.js'; /** Used to match Latin Unicode letters (excluding mathematical operators). */ -const reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g +const reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; /** Used to compose unicode character classes. */ -const rsComboMarksRange = '\\u0300-\\u036f' -const reComboHalfMarksRange = '\\ufe20-\\ufe2f' -const rsComboSymbolsRange = '\\u20d0-\\u20ff' -const rsComboMarksExtendedRange = '\\u1ab0-\\u1aff' -const rsComboMarksSupplementRange = '\\u1dc0-\\u1dff' -const rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange + rsComboMarksExtendedRange + rsComboMarksSupplementRange +const rsComboMarksRange = '\\u0300-\\u036f'; +const reComboHalfMarksRange = '\\ufe20-\\ufe2f'; +const rsComboSymbolsRange = '\\u20d0-\\u20ff'; +const rsComboMarksExtendedRange = '\\u1ab0-\\u1aff'; +const rsComboMarksSupplementRange = '\\u1dc0-\\u1dff'; +const rsComboRange = + rsComboMarksRange + + reComboHalfMarksRange + + rsComboSymbolsRange + + rsComboMarksExtendedRange + + rsComboMarksSupplementRange; /** Used to compose unicode capture groups. */ -const rsCombo = `[${rsComboRange}]` +const rsCombo = `[${rsComboRange}]`; /** * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). */ -const reComboMark = RegExp(rsCombo, 'g') +const reComboMark = RegExp(rsCombo, 'g'); /** * Deburrs `string` by converting @@ -37,7 +42,7 @@ const reComboMark = RegExp(rsCombo, 'g') * // => 'deja vu' */ function deburr(string) { - return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '') + return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); } -export default deburr +export default deburr; diff --git a/defaultTo.js b/src/defaultTo.ts similarity index 83% rename from defaultTo.js rename to src/defaultTo.ts index 6f43f29ca..a334ed7d0 100644 --- a/defaultTo.js +++ b/src/defaultTo.ts @@ -17,7 +17,7 @@ * // => 10 */ function defaultTo(value, defaultValue) { - return (value == null || value !== value) ? defaultValue : value + return value == null || value !== value ? defaultValue : value; } -export default defaultTo +export default defaultTo; diff --git a/defaultToAny.js b/src/defaultToAny.ts similarity index 77% rename from defaultToAny.js rename to src/defaultToAny.ts index 038730c86..78d807b97 100644 --- a/defaultToAny.js +++ b/src/defaultToAny.ts @@ -1,5 +1,5 @@ -import arrayReduce from './.internal/arrayReduce.js' -import defaultTo from './defaultTo.js' +import arrayReduce from './.internal/arrayReduce.js'; +import defaultTo from './defaultTo.js'; /** * This method is like `defaultTo` except that it accepts multiple default values and returns the first one that is not @@ -26,7 +26,7 @@ import defaultTo from './defaultTo.js' * // => NaN */ function defaultToAny(value, ...defaultValues) { - return arrayReduce(defaultValues, defaultTo, value) + return arrayReduce(defaultValues, defaultTo, value); } -export default defaultToAny +export default defaultToAny; diff --git a/defaults.js b/src/defaults.ts similarity index 55% rename from defaults.js rename to src/defaults.ts index 99e234dbd..6f891919f 100644 --- a/defaults.js +++ b/src/defaults.ts @@ -1,10 +1,10 @@ -import eq from './eq.js' +import eq from './eq.js'; /** Used for built-in method references. */ -const objectProto = Object.prototype +const objectProto = Object.prototype; /** Used to check objects for own properties. */ -const hasOwnProperty = objectProto.hasOwnProperty +const hasOwnProperty = objectProto.hasOwnProperty; /** * Assigns own and inherited enumerable string keyed properties of source @@ -26,20 +26,22 @@ const hasOwnProperty = objectProto.hasOwnProperty * // => { 'a': 1, 'b': 2 } */ function defaults(object, ...sources) { - object = Object(object) - sources.forEach((source) => { - if (source != null) { - source = Object(source) - for (const key in source) { - const value = object[key] - if (value === undefined || - (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) { - object[key] = source[key] + object = Object(object); + sources.forEach((source) => { + if (source != null) { + source = Object(source); + for (const key in source) { + const value = object[key]; + if ( + value === undefined || + (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key)) + ) { + object[key] = source[key]; + } + } } - } - } - }) - return object + }); + return object; } -export default defaults +export default defaults; diff --git a/defaultsDeep.js b/src/defaultsDeep.ts similarity index 77% rename from defaultsDeep.js rename to src/defaultsDeep.ts index ae942f0cb..921b1b97c 100644 --- a/defaultsDeep.js +++ b/src/defaultsDeep.ts @@ -1,5 +1,5 @@ -import customDefaultsMerge from './.internal/customDefaultsMerge.js' -import mergeWith from './mergeWith.js' +import customDefaultsMerge from './.internal/customDefaultsMerge.js'; +import mergeWith from './mergeWith.js'; /** * This method is like `defaults` except that it recursively assigns @@ -19,8 +19,8 @@ import mergeWith from './mergeWith.js' * // => { 'a': { 'b': 2, 'c': 3 } } */ function defaultsDeep(...args) { - args.push(undefined, customDefaultsMerge) - return mergeWith.apply(undefined, args) + args.push(undefined, customDefaultsMerge); + return mergeWith.apply(undefined, args); } -export default defaultsDeep +export default defaultsDeep; diff --git a/defer.js b/src/defer.ts similarity index 75% rename from defer.js rename to src/defer.ts index 77c3da601..b9f7be80f 100644 --- a/defer.js +++ b/src/defer.ts @@ -13,10 +13,10 @@ * // => Logs 'deferred' after one millisecond. */ function defer(func, ...args) { - if (typeof func !== 'function') { - throw new TypeError('Expected a function') - } - return setTimeout(func, 1, ...args) + if (typeof func !== 'function') { + throw new TypeError('Expected a function'); + } + return setTimeout(func, 1, ...args); } -export default defer +export default defer; diff --git a/delay.js b/src/delay.ts similarity index 76% rename from delay.js rename to src/delay.ts index 52258b280..c25738fd0 100644 --- a/delay.js +++ b/src/delay.ts @@ -14,10 +14,10 @@ * // => Logs 'later' after one second. */ function delay(func, wait, ...args) { - if (typeof func !== 'function') { - throw new TypeError('Expected a function') - } - return setTimeout(func, +wait || 0, ...args) + if (typeof func !== 'function') { + throw new TypeError('Expected a function'); + } + return setTimeout(func, +wait || 0, ...args); } -export default delay +export default delay; diff --git a/difference.js b/src/difference.ts similarity index 68% rename from difference.js rename to src/difference.ts index 6a25b1e8a..61168cc58 100644 --- a/difference.js +++ b/src/difference.ts @@ -1,6 +1,6 @@ -import baseDifference from './.internal/baseDifference.js' -import baseFlatten from './.internal/baseFlatten.js' -import isArrayLikeObject from './isArrayLikeObject.js' +import baseDifference from './.internal/baseDifference.js'; +import baseFlatten from './.internal/baseFlatten.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; /** * Creates an array of `array` values not included in the other given arrays @@ -22,9 +22,9 @@ import isArrayLikeObject from './isArrayLikeObject.js' * // => [1] */ function difference(array, ...values) { - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) - : [] + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) + : []; } -export default difference +export default difference; diff --git a/differenceBy.js b/src/differenceBy.ts similarity index 62% rename from differenceBy.js rename to src/differenceBy.ts index f4c063e0e..59e61d79c 100644 --- a/differenceBy.js +++ b/src/differenceBy.ts @@ -1,7 +1,7 @@ -import baseDifference from './.internal/baseDifference.js' -import baseFlatten from './.internal/baseFlatten.js' -import isArrayLikeObject from './isArrayLikeObject.js' -import last from './last.js' +import baseDifference from './.internal/baseDifference.js'; +import baseFlatten from './.internal/baseFlatten.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; +import last from './last.js'; /** * This method is like `difference` except that it accepts `iteratee` which @@ -24,13 +24,13 @@ import last from './last.js' * // => [1.2] */ function differenceBy(array, ...values) { - let iteratee = last(values) - if (isArrayLikeObject(iteratee)) { - iteratee = undefined - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), iteratee) - : [] + let iteratee = last(values); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), iteratee) + : []; } -export default differenceBy +export default differenceBy; diff --git a/differenceWith.js b/src/differenceWith.ts similarity index 59% rename from differenceWith.js rename to src/differenceWith.ts index 542cf2adf..a20665b0d 100644 --- a/differenceWith.js +++ b/src/differenceWith.ts @@ -1,7 +1,7 @@ -import baseDifference from './.internal/baseDifference.js' -import baseFlatten from './.internal/baseFlatten.js' -import isArrayLikeObject from './isArrayLikeObject.js' -import last from './last.js' +import baseDifference from './.internal/baseDifference.js'; +import baseFlatten from './.internal/baseFlatten.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; +import last from './last.js'; /** * This method is like `difference` except that it accepts `comparator` @@ -25,13 +25,18 @@ import last from './last.js' * // => [{ 'x': 2, 'y': 1 }] */ function differenceWith(array, ...values) { - let comparator = last(values) - if (isArrayLikeObject(comparator)) { - comparator = undefined - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) - : [] + let comparator = last(values); + if (isArrayLikeObject(comparator)) { + comparator = undefined; + } + return isArrayLikeObject(array) + ? baseDifference( + array, + baseFlatten(values, 1, isArrayLikeObject, true), + undefined, + comparator, + ) + : []; } -export default differenceWith +export default differenceWith; diff --git a/divide.js b/src/divide.ts similarity index 89% rename from divide.js rename to src/divide.ts index 70f6f4d0b..560153425 100644 --- a/divide.js +++ b/src/divide.ts @@ -1,4 +1,4 @@ -import createMathOperation from './.internal/createMathOperation.js' +import createMathOperation from './.internal/createMathOperation.js'; /** * Divide two numbers. @@ -13,6 +13,6 @@ import createMathOperation from './.internal/createMathOperation.js' * divide(6, 4) * // => 1.5 */ -const divide = createMathOperation((dividend, divisor) => dividend / divisor, 1) +const divide = createMathOperation((dividend, divisor) => dividend / divisor, 1); -export default divide +export default divide; diff --git a/drop.js b/src/drop.ts similarity index 64% rename from drop.js rename to src/drop.ts index 438f1e201..b242852f9 100644 --- a/drop.js +++ b/src/drop.ts @@ -1,5 +1,5 @@ -import slice from './slice.js' -import toInteger from './toInteger.js' +import slice from './slice.js'; +import toInteger from './toInteger.js'; /** * Creates a slice of `array` with `n` elements dropped from the beginning. @@ -23,11 +23,9 @@ import toInteger from './toInteger.js' * drop([1, 2, 3], 0) * // => [1, 2, 3] */ -function drop(array, n=1) { - const length = array == null ? 0 : array.length - return length - ? slice(array, n < 0 ? 0 : toInteger(n), length) - : [] +function drop(array, n = 1) { + const length = array == null ? 0 : array.length; + return length ? slice(array, n < 0 ? 0 : toInteger(n), length) : []; } -export default drop +export default drop; diff --git a/dropRight.js b/src/dropRight.ts similarity index 62% rename from dropRight.js rename to src/dropRight.ts index 2f023aeea..9729672db 100644 --- a/dropRight.js +++ b/src/dropRight.ts @@ -1,5 +1,5 @@ -import slice from './slice.js' -import toInteger from './toInteger.js' +import slice from './slice.js'; +import toInteger from './toInteger.js'; /** * Creates a slice of `array` with `n` elements dropped from the end. @@ -23,10 +23,10 @@ import toInteger from './toInteger.js' * dropRight([1, 2, 3], 0) * // => [1, 2, 3] */ -function dropRight(array, n=1) { - const length = array == null ? 0 : array.length - n = length - toInteger(n) - return length ? slice(array, 0, n < 0 ? 0 : n) : [] +function dropRight(array, n = 1) { + const length = array == null ? 0 : array.length; + n = length - toInteger(n); + return length ? slice(array, 0, n < 0 ? 0 : n) : []; } -export default dropRight +export default dropRight; diff --git a/dropRightWhile.js b/src/dropRightWhile.ts similarity index 80% rename from dropRightWhile.js rename to src/dropRightWhile.ts index e209b70d3..1ce47b1d2 100644 --- a/dropRightWhile.js +++ b/src/dropRightWhile.ts @@ -1,4 +1,4 @@ -import baseWhile from './.internal/baseWhile.js' +import baseWhile from './.internal/baseWhile.js'; /** * Creates a slice of `array` excluding elements dropped from the end. @@ -22,9 +22,7 @@ import baseWhile from './.internal/baseWhile.js' * // => objects for ['barney'] */ function dropRightWhile(array, predicate) { - return (array != null && array.length) - ? baseWhile(array, predicate, true, true) - : [] + return array != null && array.length ? baseWhile(array, predicate, true, true) : []; } -export default dropRightWhile +export default dropRightWhile; diff --git a/dropWhile.js b/src/dropWhile.ts similarity index 81% rename from dropWhile.js rename to src/dropWhile.ts index 88b7b6c8b..e3cb5d157 100644 --- a/dropWhile.js +++ b/src/dropWhile.ts @@ -1,4 +1,4 @@ -import baseWhile from './.internal/baseWhile.js' +import baseWhile from './.internal/baseWhile.js'; /** * Creates a slice of `array` excluding elements dropped from the beginning. @@ -22,9 +22,7 @@ import baseWhile from './.internal/baseWhile.js' * // => objects for ['pebbles'] */ function dropWhile(array, predicate) { - return (array != null && array.length) - ? baseWhile(array, predicate, true) - : [] + return array != null && array.length ? baseWhile(array, predicate, true) : []; } -export default dropWhile +export default dropWhile; diff --git a/src/each.ts b/src/each.ts new file mode 100644 index 000000000..3032e55d9 --- /dev/null +++ b/src/each.ts @@ -0,0 +1 @@ +export { default } from './forEach.js'; diff --git a/src/eachRight.ts b/src/eachRight.ts new file mode 100644 index 000000000..c485893e3 --- /dev/null +++ b/src/eachRight.ts @@ -0,0 +1 @@ +export { default } from './forEachRight.js'; diff --git a/endsWith.js b/src/endsWith.ts similarity index 60% rename from endsWith.js rename to src/endsWith.ts index 9cba731c5..c19cba674 100644 --- a/endsWith.js +++ b/src/endsWith.ts @@ -21,17 +21,16 @@ * // => true */ function endsWith(string, target, position) { - const { length } = string - position = position === undefined ? length : +position - if (position < 0 || position != position) { - position = 0 - } - else if (position > length) { - position = length - } - const end = position - position -= target.length - return position >= 0 && string.slice(position, end) == target + const { length } = string; + position = position === undefined ? length : +position; + if (position < 0 || position != position) { + position = 0; + } else if (position > length) { + position = length; + } + const end = position; + position -= target.length; + return position >= 0 && string.slice(position, end) == target; } -export default endsWith +export default endsWith; diff --git a/eq.js b/src/eq.ts similarity index 88% rename from eq.js rename to src/eq.ts index 06333c4cd..b63102679 100644 --- a/eq.js +++ b/src/eq.ts @@ -29,7 +29,7 @@ * // => true */ function eq(value, other) { - return value === other || (value !== value && other !== other) + return value === other || (value !== value && other !== other); } -export default eq +export default eq; diff --git a/eqDeep.js b/src/eqDeep.ts similarity index 88% rename from eqDeep.js rename to src/eqDeep.ts index b1870f5d6..64d37d288 100644 --- a/eqDeep.js +++ b/src/eqDeep.ts @@ -1,4 +1,4 @@ -import baseIsEqual from './.internal/baseIsEqual.js' +import baseIsEqual from './.internal/baseIsEqual.js'; /** * Performs a deep comparison between two values to determine if they are @@ -27,7 +27,7 @@ import baseIsEqual from './.internal/baseIsEqual.js' * // => false */ function isEqual(value, other) { - return baseIsEqual(value, other) + return baseIsEqual(value, other); } -export default isEqual +export default isEqual; diff --git a/escape.js b/src/escape.ts similarity index 76% rename from escape.js rename to src/escape.ts index eda499a1c..0517f42e8 100644 --- a/escape.js +++ b/src/escape.ts @@ -1,15 +1,15 @@ /** Used to map characters to HTML entities. */ const htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''' -} + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', +}; /** Used to match HTML entities and HTML characters. */ -const reUnescapedHtml = /[&<>"']/g -const reHasUnescapedHtml = RegExp(reUnescapedHtml.source) +const reUnescapedHtml = /[&<>"']/g; +const reHasUnescapedHtml = RegExp(reUnescapedHtml.source); /** * Converts the characters "&", "<", ">", '"', and "'" in `string` to their @@ -39,9 +39,9 @@ const reHasUnescapedHtml = RegExp(reUnescapedHtml.source) * // => 'fred, barney, & pebbles' */ function escape(string) { - return (string && reHasUnescapedHtml.test(string)) - ? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr]) - : (string || '') + return string && reHasUnescapedHtml.test(string) + ? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr]) + : string || ''; } -export default escape +export default escape; diff --git a/escapeRegExp.js b/src/escapeRegExp.ts similarity index 70% rename from escapeRegExp.js rename to src/escapeRegExp.ts index 6c77d42de..2d06b7d83 100644 --- a/escapeRegExp.js +++ b/src/escapeRegExp.ts @@ -2,8 +2,8 @@ * Used to match `RegExp` * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ -const reRegExpChar = /[\\^$.*+?()[\]{}|]/g -const reHasRegExpChar = RegExp(reRegExpChar.source) +const reRegExpChar = /[\\^$.*+?()[\]{}|]/g; +const reHasRegExpChar = RegExp(reRegExpChar.source); /** * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", @@ -20,9 +20,9 @@ const reHasRegExpChar = RegExp(reRegExpChar.source) * // => '\[lodash\]\(https://lodash\.com/\)' */ function escapeRegExp(string) { - return (string && reHasRegExpChar.test(string)) - ? string.replace(reRegExpChar, '\\$&') - : (string || '') + return string && reHasRegExpChar.test(string) + ? string.replace(reRegExpChar, '\\$&') + : string || ''; } -export default escapeRegExp +export default escapeRegExp; diff --git a/every.js b/src/every.ts similarity index 77% rename from every.js rename to src/every.ts index 045cde669..c738e4c57 100644 --- a/every.js +++ b/src/every.ts @@ -20,15 +20,15 @@ * // => false */ function every(array, predicate) { - let index = -1 - const length = array == null ? 0 : array.length + let index = -1; + const length = array == null ? 0 : array.length; - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } } - } - return true + return true; } -export default every +export default every; diff --git a/everyValue.js b/src/everyValue.ts similarity index 78% rename from everyValue.js rename to src/everyValue.ts index bec5e7aac..d35489594 100644 --- a/everyValue.js +++ b/src/everyValue.ts @@ -20,15 +20,15 @@ * // => false */ function everyValue(object, predicate) { - object = Object(object) - const props = Object.keys(object) + object = Object(object); + const props = Object.keys(object); - for (const key of props) { - if (!predicate(object[key], key, object)) { - return false + for (const key of props) { + if (!predicate(object[key], key, object)) { + return false; + } } - } - return true + return true; } -export default everyValue +export default everyValue; diff --git a/filter.js b/src/filter.ts similarity index 70% rename from filter.js rename to src/filter.ts index 98606e531..12f9487fa 100644 --- a/filter.js +++ b/src/filter.ts @@ -22,18 +22,18 @@ * // => objects for ['barney'] */ function filter(array, predicate) { - let index = -1 - let resIndex = 0 - const length = array == null ? 0 : array.length - const result = [] + let index = -1; + let resIndex = 0; + const length = array == null ? 0 : array.length; + const result = []; - while (++index < length) { - const value = array[index] - if (predicate(value, index, array)) { - result[resIndex++] = value + while (++index < length) { + const value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } } - } - return result + return result; } -export default filter +export default filter; diff --git a/filterObject.js b/src/filterObject.ts similarity index 72% rename from filterObject.js rename to src/filterObject.ts index 08631f571..be9bec3d7 100644 --- a/filterObject.js +++ b/src/filterObject.ts @@ -19,16 +19,16 @@ * // => [5, 10] */ function filterObject(object, predicate) { - object = Object(object) - const result = [] + object = Object(object); + const result = []; - Object.keys(object).forEach((key) => { - const value = object[key] - if (predicate(value, key, object)) { - result.push(value) - } - }) - return result + Object.keys(object).forEach((key) => { + const value = object[key]; + if (predicate(value, key, object)) { + result.push(value); + } + }); + return result; } -export default filterObject +export default filterObject; diff --git a/findKey.js b/src/findKey.ts similarity index 72% rename from findKey.js rename to src/findKey.ts index 1cced32f1..39640a281 100644 --- a/findKey.js +++ b/src/findKey.ts @@ -21,18 +21,18 @@ * // => 'barney' (iteration order is not guaranteed) */ function findKey(object, predicate) { - let result - if (object == null) { - return result - } - Object.keys(object).some((key) => { - const value = object[key] - if (predicate(value, key, object)) { - result = key - return true + let result; + if (object == null) { + return result; } - }) - return result + Object.keys(object).some((key) => { + const value = object[key]; + if (predicate(value, key, object)) { + result = key; + return true; + } + }); + return result; } -export default findKey +export default findKey; diff --git a/findLast.js b/src/findLast.ts similarity index 54% rename from findLast.js rename to src/findLast.ts index 391b5e9c4..29feecb8f 100644 --- a/findLast.js +++ b/src/findLast.ts @@ -1,5 +1,5 @@ -import findLastIndex from './findLastIndex.js' -import isArrayLike from './isArrayLike.js' +import findLastIndex from './findLastIndex.js'; +import isArrayLike from './isArrayLike.js'; /** * This method is like `find` except that it iterates over elements of @@ -18,15 +18,15 @@ import isArrayLike from './isArrayLike.js' * // => 3 */ function findLast(collection, predicate, fromIndex) { - let iteratee - const iterable = Object(collection) - if (!isArrayLike(collection)) { - collection = Object.keys(collection) - iteratee = predicate - predicate = (key) => iteratee(iterable[key], key, iterable) - } - const index = findLastIndex(collection, predicate, fromIndex) - return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined + let iteratee; + const iterable = Object(collection); + if (!isArrayLike(collection)) { + collection = Object.keys(collection); + iteratee = predicate; + predicate = (key) => iteratee(iterable[key], key, iterable); + } + const index = findLastIndex(collection, predicate, fromIndex); + return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; } -export default findLast +export default findLast; diff --git a/findLastIndex.js b/src/findLastIndex.ts similarity index 61% rename from findLastIndex.js rename to src/findLastIndex.ts index f38fc082d..a1d09bd0e 100644 --- a/findLastIndex.js +++ b/src/findLastIndex.ts @@ -1,5 +1,5 @@ -import baseFindIndex from './.internal/baseFindIndex.js' -import toInteger from './toInteger.js' +import baseFindIndex from './.internal/baseFindIndex.js'; +import toInteger from './toInteger.js'; /** * This method is like `findIndex` except that it iterates over elements @@ -24,18 +24,16 @@ import toInteger from './toInteger.js' * // => 2 */ function findLastIndex(array, predicate, fromIndex) { - const length = array == null ? 0 : array.length - if (!length) { - return -1 - } - let index = length - 1 - if (fromIndex !== undefined) { - index = toInteger(fromIndex) - index = fromIndex < 0 - ? Math.max(length + index, 0) - : Math.min(index, length - 1) - } - return baseFindIndex(array, predicate, index, true) + const length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + let index = length - 1; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = fromIndex < 0 ? Math.max(length + index, 0) : Math.min(index, length - 1); + } + return baseFindIndex(array, predicate, index, true); } -export default findLastIndex +export default findLastIndex; diff --git a/findLastKey.js b/src/findLastKey.ts similarity index 78% rename from findLastKey.js rename to src/findLastKey.ts index 879f3ad5f..adef032f7 100644 --- a/findLastKey.js +++ b/src/findLastKey.ts @@ -1,5 +1,5 @@ -import baseFindKey from './.internal/baseFindKey.js' -import baseForOwnRight from './.internal/baseForOwnRight.js' +import baseFindKey from './.internal/baseFindKey.js'; +import baseForOwnRight from './.internal/baseForOwnRight.js'; /** * This method is like `findKey` except that it iterates over elements of @@ -24,7 +24,7 @@ import baseForOwnRight from './.internal/baseForOwnRight.js' * // => returns 'pebbles' assuming `findKey` returns 'barney' */ function findLastKey(object, predicate) { - return baseFindKey(object, predicate, baseForOwnRight) + return baseFindKey(object, predicate, baseForOwnRight); } -export default findLastKey +export default findLastKey; diff --git a/src/first.ts b/src/first.ts new file mode 100644 index 000000000..b92dbb611 --- /dev/null +++ b/src/first.ts @@ -0,0 +1 @@ +export { default } from './head.js'; diff --git a/flatMap.js b/src/flatMap.ts similarity index 81% rename from flatMap.js rename to src/flatMap.ts index 54d88448b..410987039 100644 --- a/flatMap.js +++ b/src/flatMap.ts @@ -1,5 +1,5 @@ -import baseFlatten from './.internal/baseFlatten.js' -import map from './map.js' +import baseFlatten from './.internal/baseFlatten.js'; +import map from './map.js'; /** * Creates a flattened array of values by running each element in `collection` @@ -22,7 +22,7 @@ import map from './map.js' * // => [1, 1, 2, 2] */ function flatMap(collection, iteratee) { - return baseFlatten(map(collection, iteratee), 1) + return baseFlatten(map(collection, iteratee), 1); } -export default flatMap +export default flatMap; diff --git a/flatMapDeep.js b/src/flatMapDeep.ts similarity index 77% rename from flatMapDeep.js rename to src/flatMapDeep.ts index 9c9c5d855..d19abe768 100644 --- a/flatMapDeep.js +++ b/src/flatMapDeep.ts @@ -1,8 +1,8 @@ -import baseFlatten from './.internal/baseFlatten.js' -import map from './map.js' +import baseFlatten from './.internal/baseFlatten.js'; +import map from './map.js'; /** Used as references for various `Number` constants. */ -const INFINITY = 1 / 0 +const INFINITY = 1 / 0; /** * This method is like `flatMap` except that it recursively flattens the @@ -24,7 +24,7 @@ const INFINITY = 1 / 0 * // => [1, 1, 2, 2] */ function flatMapDeep(collection, iteratee) { - return baseFlatten(map(collection, iteratee), INFINITY) + return baseFlatten(map(collection, iteratee), INFINITY); } -export default flatMapDeep +export default flatMapDeep; diff --git a/flatMapDepth.js b/src/flatMapDepth.ts similarity index 76% rename from flatMapDepth.js rename to src/flatMapDepth.ts index 8a1ee20c9..607c76f5e 100644 --- a/flatMapDepth.js +++ b/src/flatMapDepth.ts @@ -1,5 +1,5 @@ -import baseFlatten from './.internal/baseFlatten.js' -import map from './map.js' +import baseFlatten from './.internal/baseFlatten.js'; +import map from './map.js'; /** * This method is like `flatMap` except that it recursively flattens the @@ -22,8 +22,8 @@ import map from './map.js' * // => [[1, 1], [2, 2]] */ function flatMapDepth(collection, iteratee, depth) { - depth = depth === undefined ? 1 : +depth - return baseFlatten(map(collection, iteratee), depth) + depth = depth === undefined ? 1 : +depth; + return baseFlatten(map(collection, iteratee), depth); } -export default flatMapDepth +export default flatMapDepth; diff --git a/flatten.js b/src/flatten.ts similarity index 67% rename from flatten.js rename to src/flatten.ts index 75a834c84..ff9ccfee3 100644 --- a/flatten.js +++ b/src/flatten.ts @@ -1,4 +1,4 @@ -import baseFlatten from './.internal/baseFlatten.js' +import baseFlatten from './.internal/baseFlatten.js'; /** * Flattens `array` a single level deep. @@ -14,8 +14,8 @@ import baseFlatten from './.internal/baseFlatten.js' * // => [1, 2, [3, [4]], 5] */ function flatten(array) { - const length = array == null ? 0 : array.length - return length ? baseFlatten(array, 1) : [] + const length = array == null ? 0 : array.length; + return length ? baseFlatten(array, 1) : []; } -export default flatten +export default flatten; diff --git a/flattenDeep.js b/src/flattenDeep.ts similarity index 65% rename from flattenDeep.js rename to src/flattenDeep.ts index 8a96f58cf..9e58ed488 100644 --- a/flattenDeep.js +++ b/src/flattenDeep.ts @@ -1,7 +1,7 @@ -import baseFlatten from './.internal/baseFlatten.js' +import baseFlatten from './.internal/baseFlatten.js'; /** Used as references for various `Number` constants. */ -const INFINITY = 1 / 0 +const INFINITY = 1 / 0; /** * Recursively flattens `array`. @@ -17,8 +17,8 @@ const INFINITY = 1 / 0 * // => [1, 2, 3, 4, 5] */ function flattenDeep(array) { - const length = array == null ? 0 : array.length - return length ? baseFlatten(array, INFINITY) : [] + const length = array == null ? 0 : array.length; + return length ? baseFlatten(array, INFINITY) : []; } -export default flattenDeep +export default flattenDeep; diff --git a/flattenDepth.js b/src/flattenDepth.ts similarity index 66% rename from flattenDepth.js rename to src/flattenDepth.ts index 0a8c4564b..0844c98b6 100644 --- a/flattenDepth.js +++ b/src/flattenDepth.ts @@ -1,4 +1,4 @@ -import baseFlatten from './.internal/baseFlatten.js' +import baseFlatten from './.internal/baseFlatten.js'; /** * Recursively flatten `array` up to `depth` times. @@ -20,12 +20,12 @@ import baseFlatten from './.internal/baseFlatten.js' * // => [1, 2, 3, [4], 5] */ function flattenDepth(array, depth) { - const length = array == null ? 0 : array.length - if (!length) { - return [] - } - depth = depth === undefined ? 1 : +depth - return baseFlatten(array, depth) + const length = array == null ? 0 : array.length; + if (!length) { + return []; + } + depth = depth === undefined ? 1 : +depth; + return baseFlatten(array, depth); } -export default flattenDepth +export default flattenDepth; diff --git a/flip.js b/src/flip.ts similarity index 66% rename from flip.js rename to src/flip.ts index 99297aa64..dc1e099d3 100644 --- a/flip.js +++ b/src/flip.ts @@ -14,12 +14,12 @@ * // => ['d', 'c', 'b', 'a'] */ function flip(func) { - if (typeof func !== 'function') { - throw new TypeError('Expected a function') - } - return function(...args) { - return func.apply(this, args.reverse()) - } + if (typeof func !== 'function') { + throw new TypeError('Expected a function'); + } + return function (...args) { + return func.apply(this, args.reverse()); + }; } -export default flip +export default flip; diff --git a/floor.js b/src/floor.ts similarity index 77% rename from floor.js rename to src/floor.ts index b9124a6ce..98ed9bcfa 100644 --- a/floor.js +++ b/src/floor.ts @@ -1,4 +1,4 @@ -import createRound from './.internal/createRound.js' +import createRound from './.internal/createRound.js'; /** * Computes `number` rounded down to `precision`. @@ -19,6 +19,6 @@ import createRound from './.internal/createRound.js' * floor(4060, -2) * // => 4000 */ -const floor = createRound('floor') +const floor = createRound('floor'); -export default floor +export default floor; diff --git a/flow.js b/src/flow.ts similarity index 55% rename from flow.js rename to src/flow.ts index c797a7247..6f66d122c 100644 --- a/flow.js +++ b/src/flow.ts @@ -21,21 +21,21 @@ * // => 9 */ function flow(...funcs) { - const length = funcs.length - let index = length - while (index--) { - if (typeof funcs[index] !== 'function') { - throw new TypeError('Expected a function') + const length = funcs.length; + let index = length; + while (index--) { + if (typeof funcs[index] !== 'function') { + throw new TypeError('Expected a function'); + } } - } - return function(...args) { - let index = 0 - let result = length ? funcs[index].apply(this, args) : args[0] - while (++index < length) { - result = funcs[index].call(this, result) - } - return result - } + return function (...args) { + let index = 0; + let result = length ? funcs[index].apply(this, args) : args[0]; + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; } -export default flow +export default flow; diff --git a/flowRight.js b/src/flowRight.ts similarity index 84% rename from flowRight.js rename to src/flowRight.ts index c1fafff78..4b0d47353 100644 --- a/flowRight.js +++ b/src/flowRight.ts @@ -1,4 +1,4 @@ -import flow from './flow.js' +import flow from './flow.js'; /** * This method is like `flow` except that it composes a function that @@ -22,7 +22,7 @@ import flow from './flow.js' * // => 9 */ function flowRight(...funcs) { - return flow(...funcs.reverse()) + return flow(...funcs.reverse()); } -export default flowRight +export default flowRight; diff --git a/forEach.js b/src/forEach.ts similarity index 81% rename from forEach.js rename to src/forEach.ts index facccb07a..91896fb3d 100644 --- a/forEach.js +++ b/src/forEach.ts @@ -1,5 +1,5 @@ -import arrayEach from './.internal/arrayEach.js' -import baseEach from './.internal/baseEach.js' +import arrayEach from './.internal/arrayEach.js'; +import baseEach from './.internal/baseEach.js'; /** * Iterates over elements of `collection` and invokes `iteratee` for each element. @@ -26,8 +26,8 @@ import baseEach from './.internal/baseEach.js' * // => Logs 'a' then 'b' (iteration order is not guaranteed). */ function forEach(collection, iteratee) { - const func = Array.isArray(collection) ? arrayEach : baseEach - return func(collection, iteratee) + const func = Array.isArray(collection) ? arrayEach : baseEach; + return func(collection, iteratee); } -export default forEach +export default forEach; diff --git a/forEachRight.js b/src/forEachRight.ts similarity index 68% rename from forEachRight.js rename to src/forEachRight.ts index b8682b94b..993be6b3e 100644 --- a/forEachRight.js +++ b/src/forEachRight.ts @@ -1,5 +1,5 @@ -import arrayEachRight from './.internal/arrayEachRight.js' -import baseEachRight from './.internal/baseEachRight.js' +import arrayEachRight from './.internal/arrayEachRight.js'; +import baseEachRight from './.internal/baseEachRight.js'; /** * This method is like `forEach` except that it iterates over elements of @@ -18,8 +18,8 @@ import baseEachRight from './.internal/baseEachRight.js' * // => Logs `2` then `1`. */ function forEachRight(collection, iteratee) { - const func = Array.isArray(collection) ? arrayEachRight : baseEachRight - return func(collection, iteratee) + const func = Array.isArray(collection) ? arrayEachRight : baseEachRight; + return func(collection, iteratee); } -export default forEachRight +export default forEachRight; diff --git a/forOwn.js b/src/forOwn.ts similarity index 85% rename from forOwn.js rename to src/forOwn.ts index 40ea48b25..65641e55a 100644 --- a/forOwn.js +++ b/src/forOwn.ts @@ -24,8 +24,8 @@ * // => Logs 'a' then 'b' (iteration order is not guaranteed). */ function forOwn(object, iteratee) { - object = Object(object) - Object.keys(object).forEach((key) => iteratee(object[key], key, object)) + object = Object(object); + Object.keys(object).forEach((key) => iteratee(object[key], key, object)); } -export default forOwn +export default forOwn; diff --git a/forOwnRight.js b/src/forOwnRight.ts similarity index 73% rename from forOwnRight.js rename to src/forOwnRight.ts index 5fbfbd5e1..740984108 100644 --- a/forOwnRight.js +++ b/src/forOwnRight.ts @@ -23,14 +23,14 @@ * // => Logs 'b' then 'a' assuming `forOwn` logs 'a' then 'b'. */ function forOwnRight(object, iteratee) { - if (object == null) { - return - } - const props = Object.keys(object) - let length = props.length - while (length--) { - iteratee(object[props[length]], iteratee, object) - } + if (object == null) { + return; + } + const props = Object.keys(object); + let length = props.length; + while (length--) { + iteratee(object[props[length]], iteratee, object); + } } -export default forOwnRight +export default forOwnRight; diff --git a/fromEntries.js b/src/fromEntries.ts similarity index 63% rename from fromEntries.js rename to src/fromEntries.ts index cd21ba02a..dd39c9ad2 100644 --- a/fromEntries.js +++ b/src/fromEntries.ts @@ -12,14 +12,14 @@ * // => { 'a': 1, 'b': 2 } */ function fromEntries(pairs) { - const result = {} - if (pairs == null) { - return result - } - for (const pair of pairs) { - result[pair[0]] = pair[1] - } - return result + const result = {}; + if (pairs == null) { + return result; + } + for (const pair of pairs) { + result[pair[0]] = pair[1]; + } + return result; } -export default fromEntries +export default fromEntries; diff --git a/functions.js b/src/functions.ts similarity index 74% rename from functions.js rename to src/functions.ts index f59d8a737..f4cc38267 100644 --- a/functions.js +++ b/src/functions.ts @@ -20,10 +20,10 @@ * // => ['a', 'b'] */ function functions(object) { - if (object == null) { - return [] - } - return Object.keys(object).filter((key) => typeof object[key] === 'function') + if (object == null) { + return []; + } + return Object.keys(object).filter((key) => typeof object[key] === 'function'); } -export default functions +export default functions; diff --git a/get.js b/src/get.ts similarity index 78% rename from get.js rename to src/get.ts index ca4354c41..55c22e9cb 100644 --- a/get.js +++ b/src/get.ts @@ -1,4 +1,4 @@ -import baseGet from './.internal/baseGet.js' +import baseGet from './.internal/baseGet.js'; /** * Gets the value at `path` of `object`. If the resolved value is @@ -25,8 +25,8 @@ import baseGet from './.internal/baseGet.js' * // => 'default' */ function get(object, path, defaultValue) { - const result = object == null ? undefined : baseGet(object, path) - return result === undefined ? defaultValue : result + const result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; } -export default get +export default get; diff --git a/groupBy.js b/src/groupBy.ts similarity index 60% rename from groupBy.js rename to src/groupBy.ts index 03b5ea557..690d21541 100644 --- a/groupBy.js +++ b/src/groupBy.ts @@ -1,8 +1,8 @@ -import baseAssignValue from './.internal/baseAssignValue.js' -import reduce from './reduce.js' +import baseAssignValue from './.internal/baseAssignValue.js'; +import reduce from './reduce.js'; /** Used to check objects for own properties. */ -const hasOwnProperty = Object.prototype.hasOwnProperty +const hasOwnProperty = Object.prototype.hasOwnProperty; /** * Creates an object composed of keys generated from the results of running @@ -22,15 +22,19 @@ const hasOwnProperty = Object.prototype.hasOwnProperty * // => { '4': [4.2], '6': [6.1, 6.3] } */ function groupBy(collection, iteratee) { - return reduce(collection, (result, value, key) => { - key = iteratee(value) - if (hasOwnProperty.call(result, key)) { - result[key].push(value) - } else { - baseAssignValue(result, key, [value]) - } - return result - }, {}) + return reduce( + collection, + (result, value, key) => { + key = iteratee(value); + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + baseAssignValue(result, key, [value]); + } + return result; + }, + {}, + ); } -export default groupBy +export default groupBy; diff --git a/gt.js b/src/gt.ts similarity index 71% rename from gt.js rename to src/gt.ts index 5359e1665..d1367bc27 100644 --- a/gt.js +++ b/src/gt.ts @@ -20,11 +20,11 @@ * // => false */ function gt(value, other) { - if (!(typeof value === 'string' && typeof other === 'string')) { - value = +value - other = +other - } - return value > other + if (!(typeof value === 'string' && typeof other === 'string')) { + value = +value; + other = +other; + } + return value > other; } -export default gt +export default gt; diff --git a/gte.js b/src/gte.ts similarity index 72% rename from gte.js rename to src/gte.ts index b6fa0e572..8005034b0 100644 --- a/gte.js +++ b/src/gte.ts @@ -20,11 +20,11 @@ * // => false */ function gte(value, other) { - if (!(typeof value === 'string' && typeof other === 'string')) { - value = +value - other = +other - } - return value >= other + if (!(typeof value === 'string' && typeof other === 'string')) { + value = +value; + other = +other; + } + return value >= other; } -export default gte +export default gte; diff --git a/has.js b/src/has.ts similarity index 79% rename from has.js rename to src/has.ts index 9cec79d5a..433f60a54 100644 --- a/has.js +++ b/src/has.ts @@ -1,5 +1,5 @@ /** Used to check objects for own properties. */ -const hasOwnProperty = Object.prototype.hasOwnProperty +const hasOwnProperty = Object.prototype.hasOwnProperty; /** * Checks if `key` is a direct property of `object`. @@ -22,7 +22,7 @@ const hasOwnProperty = Object.prototype.hasOwnProperty * // => false */ function has(object, key) { - return object != null && hasOwnProperty.call(object, key) + return object != null && hasOwnProperty.call(object, key); } -export default has +export default has; diff --git a/hasIn.js b/src/hasIn.ts similarity index 86% rename from hasIn.js rename to src/hasIn.ts index 71d35d511..4cfb6148b 100644 --- a/hasIn.js +++ b/src/hasIn.ts @@ -18,7 +18,7 @@ * // => false */ function hasIn(object, key) { - return object != null && key in Object(object) + return object != null && key in Object(object); } -export default hasIn +export default hasIn; diff --git a/src/hasPath.ts b/src/hasPath.ts new file mode 100644 index 000000000..ec2337bf9 --- /dev/null +++ b/src/hasPath.ts @@ -0,0 +1,57 @@ +import castPath from './.internal/castPath.js'; +import isArguments from './isArguments.js'; +import isIndex from './.internal/isIndex.js'; +import isLength from './isLength.js'; +import toKey from './.internal/toKey.js'; + +/** Used to check objects for own properties. */ +const hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Checks if `path` is a direct property of `object`. + * + * @since 5.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @see has, hasIn, hasPathIn + * @example + * + * const object = { 'a': { 'b': 2 } } + * const other = create({ 'a': create({ 'b': 2 }) }) + * + * hasPath(object, 'a.b') + * // => true + * + * hasPath(object, ['a', 'b']) + * // => true + */ +function hasPath(object, path) { + path = castPath(path, object); + + let index = -1; + let { length } = path; + let result = false; + let key; + + while (++index < length) { + key = toKey(path[index]); + if (!(result = object != null && hasOwnProperty.call(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return ( + !!length && + isLength(length) && + isIndex(key, length) && + (Array.isArray(object) || isArguments(object)) + ); +} + +export default hasPath; diff --git a/src/hasPathIn.ts b/src/hasPathIn.ts new file mode 100644 index 000000000..98166aadb --- /dev/null +++ b/src/hasPathIn.ts @@ -0,0 +1,54 @@ +import castPath from './.internal/castPath.js'; +import isArguments from './isArguments.js'; +import isIndex from './.internal/isIndex.js'; +import isLength from './isLength.js'; +import toKey from './.internal/toKey.js'; + +/** + * Checks if `path` is a direct property of `object`. + * + * @since 5.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @see has, hasIn hasPath + * @example + * + * const object = { 'a': { 'b': 2 } } + * const other = create({ 'a': create({ 'b': 2 }) }) + * + * hasPathIn(object, 'a.b') + * // => true + * + * hasPathIn(object, ['a', 'b']) + * // => true + */ +function hasPathIn(object, path) { + path = castPath(path, object); + + let index = -1; + let { length } = path; + let result = false; + let key; + + while (++index < length) { + key = toKey(path[index]); + if (!(result = object != null && key in Object(object))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return ( + !!length && + isLength(length) && + isIndex(key, length) && + (Array.isArray(object) || isArguments(object)) + ); +} + +export default hasPathIn; diff --git a/head.js b/src/head.ts similarity index 77% rename from head.js rename to src/head.ts index a9df4111f..061d1d309 100644 --- a/head.js +++ b/src/head.ts @@ -16,9 +16,7 @@ * // => undefined */ function head(array) { - return (array != null && array.length) - ? array[0] - : undefined + return array != null && array.length ? array[0] : undefined; } -export default head +export default head; diff --git a/inRange.js b/src/inRange.ts similarity index 81% rename from inRange.js rename to src/inRange.ts index ce2962de0..1bf950e7e 100644 --- a/inRange.js +++ b/src/inRange.ts @@ -1,4 +1,4 @@ -import baseInRange from './.internal/baseInRange.js' +import baseInRange from './.internal/baseInRange.js'; /** * Checks if `number` is between `start` and up to, but not including, `end`. If @@ -37,11 +37,11 @@ import baseInRange from './.internal/baseInRange.js' * // => true */ function inRange(number, start, end) { - if (end === undefined) { - end = start - start = 0 - } - return baseInRange(+number, +start, +end) + if (end === undefined) { + end = start; + start = 0; + } + return baseInRange(+number, +start, +end); } -export default inRange +export default inRange; diff --git a/indexOf.js b/src/indexOf.ts similarity index 64% rename from indexOf.js rename to src/indexOf.ts index 358fff4cc..897c593e2 100644 --- a/indexOf.js +++ b/src/indexOf.ts @@ -1,5 +1,5 @@ -import baseIndexOf from './.internal/baseIndexOf.js' -import toInteger from './toInteger.js' +import baseIndexOf from './.internal/baseIndexOf.js'; +import toInteger from './toInteger.js'; /** * Gets the index at which the first occurrence of `value` is found in `array` @@ -23,15 +23,15 @@ import toInteger from './toInteger.js' * // => 3 */ function indexOf(array, value, fromIndex) { - const length = array == null ? 0 : array.length - if (!length) { - return -1 - } - let index = fromIndex == null ? 0 : toInteger(fromIndex) - if (index < 0) { - index = Math.max(length + index, 0) - } - return baseIndexOf(array, value, index) + const length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + let index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = Math.max(length + index, 0); + } + return baseIndexOf(array, value, index); } -export default indexOf +export default indexOf; diff --git a/initial.js b/src/initial.ts similarity index 63% rename from initial.js rename to src/initial.ts index 1a4b1d837..9a2fb081a 100644 --- a/initial.js +++ b/src/initial.ts @@ -1,4 +1,4 @@ -import slice from './slice.js' +import slice from './slice.js'; /** * Gets all but the last element of `array`. @@ -13,8 +13,8 @@ import slice from './slice.js' * // => [1, 2] */ function initial(array) { - const length = array == null ? 0 : array.length - return length ? slice(array, 0, -1) : [] + const length = array == null ? 0 : array.length; + return length ? slice(array, 0, -1) : []; } -export default initial +export default initial; diff --git a/intersection.js b/src/intersection.ts similarity index 69% rename from intersection.js rename to src/intersection.ts index 0b16d3b4a..a78c37e6b 100644 --- a/intersection.js +++ b/src/intersection.ts @@ -1,6 +1,6 @@ -import map from './map.js' -import baseIntersection from './.internal/baseIntersection.js' -import castArrayLikeObject from './.internal/castArrayLikeObject.js' +import map from './map.js'; +import baseIntersection from './.internal/baseIntersection.js'; +import castArrayLikeObject from './.internal/castArrayLikeObject.js'; /** * Creates an array of unique values that are included in all given arrays @@ -18,10 +18,8 @@ import castArrayLikeObject from './.internal/castArrayLikeObject.js' * // => [2] */ function intersection(...arrays) { - const mapped = map(arrays, castArrayLikeObject) - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped) - : [] + const mapped = map(arrays, castArrayLikeObject); + return mapped.length && mapped[0] === arrays[0] ? baseIntersection(mapped) : []; } -export default intersection +export default intersection; diff --git a/intersectionBy.js b/src/intersectionBy.ts similarity index 62% rename from intersectionBy.js rename to src/intersectionBy.ts index 3f1f85246..d6eff943e 100644 --- a/intersectionBy.js +++ b/src/intersectionBy.ts @@ -1,7 +1,7 @@ -import map from './map.js' -import baseIntersection from './.internal/baseIntersection.js' -import castArrayLikeObject from './.internal/castArrayLikeObject.js' -import last from './last.js' +import map from './map.js'; +import baseIntersection from './.internal/baseIntersection.js'; +import castArrayLikeObject from './.internal/castArrayLikeObject.js'; +import last from './last.js'; /** * This method is like `intersection` except that it accepts `iteratee` @@ -21,17 +21,15 @@ import last from './last.js' * // => [2.1] */ function intersectionBy(...arrays) { - let iteratee = last(arrays) - const mapped = map(arrays, castArrayLikeObject) + let iteratee = last(arrays); + const mapped = map(arrays, castArrayLikeObject); - if (iteratee === last(mapped)) { - iteratee = undefined - } else { - mapped.pop() - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, iteratee) - : [] + if (iteratee === last(mapped)) { + iteratee = undefined; + } else { + mapped.pop(); + } + return mapped.length && mapped[0] === arrays[0] ? baseIntersection(mapped, iteratee) : []; } -export default intersectionBy +export default intersectionBy; diff --git a/intersectionWith.js b/src/intersectionWith.ts similarity index 62% rename from intersectionWith.js rename to src/intersectionWith.ts index 7621de8c3..ae92386b2 100644 --- a/intersectionWith.js +++ b/src/intersectionWith.ts @@ -1,7 +1,7 @@ -import map from './map.js' -import baseIntersection from './.internal/baseIntersection.js' -import castArrayLikeObject from './.internal/castArrayLikeObject.js' -import last from './last.js' +import map from './map.js'; +import baseIntersection from './.internal/baseIntersection.js'; +import castArrayLikeObject from './.internal/castArrayLikeObject.js'; +import last from './last.js'; /** * This method is like `intersection` except that it accepts `comparator` @@ -23,16 +23,16 @@ import last from './last.js' * // => [{ 'x': 1, 'y': 2 }] */ function intersectionWith(...arrays) { - let comparator = last(arrays) - const mapped = map(arrays, castArrayLikeObject) + let comparator = last(arrays); + const mapped = map(arrays, castArrayLikeObject); - comparator = typeof comparator === 'function' ? comparator : undefined - if (comparator) { - mapped.pop() - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, undefined, comparator) - : [] + comparator = typeof comparator === 'function' ? comparator : undefined; + if (comparator) { + mapped.pop(); + } + return mapped.length && mapped[0] === arrays[0] + ? baseIntersection(mapped, undefined, comparator) + : []; } -export default intersectionWith +export default intersectionWith; diff --git a/invert.js b/src/invert.ts similarity index 58% rename from invert.js rename to src/invert.ts index f6e67398c..e730613e7 100644 --- a/invert.js +++ b/src/invert.ts @@ -1,4 +1,4 @@ -const toString = Object.prototype.toString +const toString = Object.prototype.toString; /** * Creates an object composed of the inverted keys and values of `object`. @@ -17,15 +17,15 @@ const toString = Object.prototype.toString * // => { '1': 'c', '2': 'b' } */ function invert(object) { - const result = {} - Object.keys(object).forEach((key) => { - let value = object[key] - if (value != null && typeof value.toString !== 'function') { - value = toString.call(value) - } - result[value] = key - }) - return result + const result = {}; + Object.keys(object).forEach((key) => { + let value = object[key]; + if (value != null && typeof value.toString !== 'function') { + value = toString.call(value); + } + result[value] = key; + }); + return result; } -export default invert +export default invert; diff --git a/invertBy.js b/src/invertBy.ts similarity index 68% rename from invertBy.js rename to src/invertBy.ts index 856f9f77f..30ba88563 100644 --- a/invertBy.js +++ b/src/invertBy.ts @@ -1,5 +1,5 @@ /** Used to check objects for own properties. */ -const hasOwnProperty = Object.prototype.hasOwnProperty +const hasOwnProperty = Object.prototype.hasOwnProperty; /** * This method is like `invert` except that the inverted object is generated @@ -21,16 +21,16 @@ const hasOwnProperty = Object.prototype.hasOwnProperty * // => { 'group1': ['a', 'c'], 'group2': ['b'] } */ function invertBy(object, iteratee) { - const result = {} - Object.keys(object).forEach((key) => { - const value = iteratee(object[key]) - if (hasOwnProperty.call(result, value)) { - result[value].push(key) - } else { - result[value] = [key] - } - }) - return result + const result = {}; + Object.keys(object).forEach((key) => { + const value = iteratee(object[key]); + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + }); + return result; } -export default invertBy +export default invertBy; diff --git a/invoke.js b/src/invoke.ts similarity index 56% rename from invoke.js rename to src/invoke.ts index 6767b99d2..968b9395a 100644 --- a/invoke.js +++ b/src/invoke.ts @@ -1,7 +1,7 @@ -import castPath from './.internal/castPath.js' -import last from './last.js' -import parent from './.internal/parent.js' -import toKey from './.internal/toKey.js' +import castPath from './.internal/castPath.js'; +import last from './last.js'; +import parent from './.internal/parent.js'; +import toKey from './.internal/toKey.js'; /** * Invokes the method at `path` of `object`. @@ -20,10 +20,10 @@ import toKey from './.internal/toKey.js' * // => [2, 3] */ function invoke(object, path, args) { - path = castPath(path, object) - object = parent(object, path) - const func = object == null ? object : object[toKey(last(path))] - return func == null ? undefined : func.apply(object, args) + path = castPath(path, object); + object = parent(object, path); + const func = object == null ? object : object[toKey(last(path))]; + return func == null ? undefined : func.apply(object, args); } -export default invoke +export default invoke; diff --git a/invokeMap.js b/src/invokeMap.ts similarity index 66% rename from invokeMap.js rename to src/invokeMap.ts index f52890b49..2e2947921 100644 --- a/invokeMap.js +++ b/src/invokeMap.ts @@ -1,6 +1,6 @@ -import baseEach from './.internal/baseEach.js' -import invoke from './invoke.js' -import isArrayLike from './isArrayLike.js' +import baseEach from './.internal/baseEach.js'; +import invoke from './invoke.js'; +import isArrayLike from './isArrayLike.js'; /** * Invokes the method at `path` of each element in `collection`, returning @@ -24,14 +24,14 @@ import isArrayLike from './isArrayLike.js' * // => [['1', '2', '3'], ['4', '5', '6']] */ function invokeMap(collection, path, args) { - let index = -1 - const isFunc = typeof path === 'function' - const result = isArrayLike(collection) ? new Array(collection.length) : [] + let index = -1; + const isFunc = typeof path === 'function'; + const result = isArrayLike(collection) ? new Array(collection.length) : []; - baseEach(collection, (value) => { - result[++index] = isFunc ? path.apply(value, args) : invoke(value, path, args) - }) - return result + baseEach(collection, (value) => { + result[++index] = isFunc ? path.apply(value, args) : invoke(value, path, args); + }); + return result; } -export default invokeMap +export default invokeMap; diff --git a/isArguments.js b/src/isArguments.ts similarity index 66% rename from isArguments.js rename to src/isArguments.ts index acddb7fcb..3746c4c61 100644 --- a/isArguments.js +++ b/src/isArguments.ts @@ -1,5 +1,5 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; /** * Checks if `value` is likely an `arguments` object. @@ -17,7 +17,7 @@ import isObjectLike from './isObjectLike.js' * // => false */ function isArguments(value) { - return isObjectLike(value) && getTag(value) == '[object Arguments]' + return isObjectLike(value) && getTag(value) == '[object Arguments]'; } -export default isArguments +export default isArguments; diff --git a/isArrayBuffer.js b/src/isArrayBuffer.ts similarity index 54% rename from isArrayBuffer.js rename to src/isArrayBuffer.ts index add5067c7..20fdf9ca2 100644 --- a/isArrayBuffer.js +++ b/src/isArrayBuffer.ts @@ -1,9 +1,9 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' -import nodeTypes from './.internal/nodeTypes.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; +import nodeTypes from './.internal/nodeTypes.js'; /* Node.js helper references. */ -const nodeIsArrayBuffer = nodeTypes && nodeTypes.isArrayBuffer +const nodeIsArrayBuffer = nodeTypes && nodeTypes.isArrayBuffer; /** * Checks if `value` is classified as an `ArrayBuffer` object. @@ -21,7 +21,7 @@ const nodeIsArrayBuffer = nodeTypes && nodeTypes.isArrayBuffer * // => false */ const isArrayBuffer = nodeIsArrayBuffer - ? (value) => nodeIsArrayBuffer(value) - : (value) => isObjectLike(value) && getTag(value) == '[object ArrayBuffer]' + ? (value) => nodeIsArrayBuffer(value) + : (value) => isObjectLike(value) && getTag(value) == '[object ArrayBuffer]'; -export default isArrayBuffer +export default isArrayBuffer; diff --git a/isArrayLike.js b/src/isArrayLike.ts similarity index 80% rename from isArrayLike.js rename to src/isArrayLike.ts index ab72a6353..102bfe464 100644 --- a/isArrayLike.js +++ b/src/isArrayLike.ts @@ -1,4 +1,4 @@ -import isLength from './isLength.js' +import isLength from './isLength.js'; /** * Checks if `value` is array-like. A value is considered array-like if it's @@ -24,7 +24,7 @@ import isLength from './isLength.js' * // => false */ function isArrayLike(value) { - return value != null && typeof value !== 'function' && isLength(value.length) + return value != null && typeof value !== 'function' && isLength(value.length); } -export default isArrayLike +export default isArrayLike; diff --git a/isArrayLikeObject.js b/src/isArrayLikeObject.ts similarity index 74% rename from isArrayLikeObject.js rename to src/isArrayLikeObject.ts index 50ac56bd2..1b975cb83 100644 --- a/isArrayLikeObject.js +++ b/src/isArrayLikeObject.ts @@ -1,5 +1,5 @@ -import isArrayLike from './isArrayLike.js' -import isObjectLike from './isObjectLike.js' +import isArrayLike from './isArrayLike.js'; +import isObjectLike from './isObjectLike.js'; /** * This method is like `isArrayLike` except that it also checks if `value` @@ -25,7 +25,7 @@ import isObjectLike from './isObjectLike.js' * // => false */ function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value) + return isObjectLike(value) && isArrayLike(value); } -export default isArrayLikeObject +export default isArrayLikeObject; diff --git a/isBoolean.js b/src/isBoolean.ts similarity index 57% rename from isBoolean.js rename to src/isBoolean.ts index 04a5c530b..e1004de41 100644 --- a/isBoolean.js +++ b/src/isBoolean.ts @@ -1,5 +1,5 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; /** * Checks if `value` is classified as a boolean primitive or object. @@ -17,8 +17,11 @@ import isObjectLike from './isObjectLike.js' * // => false */ function isBoolean(value) { - return value === true || value === false || - (isObjectLike(value) && getTag(value) == '[object Boolean]') + return ( + value === true || + value === false || + (isObjectLike(value) && getTag(value) == '[object Boolean]') + ); } -export default isBoolean +export default isBoolean; diff --git a/src/isBuffer.ts b/src/isBuffer.ts new file mode 100644 index 000000000..3264442d1 --- /dev/null +++ b/src/isBuffer.ts @@ -0,0 +1,23 @@ +import root from './.internal/root.js'; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +const nativeIsBuffer = root?.Buffer?.isBuffer; + +/** + * Checks if `value` is a buffer. + * + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * isBuffer(new Buffer(2)) + * // => true + * + * isBuffer(new Uint8Array(2)) + * // => false + */ +const isBuffer = typeof nativeIsBuffer === 'function' ? nativeIsBuffer : () => false; + +export default isBuffer; diff --git a/isDate.js b/src/isDate.ts similarity index 54% rename from isDate.js rename to src/isDate.ts index 1486be633..8c81d4653 100644 --- a/isDate.js +++ b/src/isDate.ts @@ -1,9 +1,9 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' -import nodeTypes from './.internal/nodeTypes.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; +import nodeTypes from './.internal/nodeTypes.js'; /* Node.js helper references. */ -const nodeIsDate = nodeTypes && nodeTypes.isDate +const nodeIsDate = nodeTypes && nodeTypes.isDate; /** * Checks if `value` is classified as a `Date` object. @@ -21,7 +21,7 @@ const nodeIsDate = nodeTypes && nodeTypes.isDate * // => false */ const isDate = nodeIsDate - ? (value) => nodeIsDate(value) - : (value) => isObjectLike(value) && getTag(value) == '[object Date]' + ? (value) => nodeIsDate(value) + : (value) => isObjectLike(value) && getTag(value) == '[object Date]'; -export default isDate +export default isDate; diff --git a/isElement.js b/src/isElement.ts similarity index 62% rename from isElement.js rename to src/isElement.ts index 636d792ed..7b88528d5 100644 --- a/isElement.js +++ b/src/isElement.ts @@ -1,5 +1,5 @@ -import isObjectLike from './isObjectLike.js' -import isPlainObject from './isPlainObject.js' +import isObjectLike from './isObjectLike.js'; +import isPlainObject from './isPlainObject.js'; /** * Checks if `value` is likely a DOM element. @@ -17,7 +17,7 @@ import isPlainObject from './isPlainObject.js' * // => false */ function isElement(value) { - return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value) + return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); } -export default isElement +export default isElement; diff --git a/src/isEmpty.ts b/src/isEmpty.ts new file mode 100644 index 000000000..c5f40f26b --- /dev/null +++ b/src/isEmpty.ts @@ -0,0 +1,75 @@ +import getTag from './.internal/getTag.js'; +import isArguments from './isArguments.js'; +import isArrayLike from './isArrayLike.js'; +import isBuffer from './isBuffer.js'; +import isPrototype from './.internal/isPrototype.js'; +import isTypedArray from './isTypedArray.js'; + +/** Used to check objects for own properties. */ +const hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Checks if `value` is an empty object, collection, map, or set. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Array-like values such as `arguments` objects, arrays, buffers, strings, or + * jQuery-like collections are considered empty if they have a `length` of `0`. + * Similarly, maps and sets are considered empty if they have a `size` of `0`. + * + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @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('abc') + * // => false + * + * isEmpty({ 'a': 1 }) + * // => false + */ +function isEmpty(value) { + if (value == null) { + return true; + } + if ( + isArrayLike(value) && + (Array.isArray(value) || + typeof value === 'string' || + typeof value.splice === 'function' || + isBuffer(value) || + isTypedArray(value) || + isArguments(value)) + ) { + return !value.length; + } + const tag = getTag(value); + if (tag == '[object Map]' || tag == '[object Set]') { + return !value.size; + } + if (isPrototype(value)) { + return !Object.keys(value).length; + } + for (const key in value) { + if (hasOwnProperty.call(value, key)) { + return false; + } + } + return true; +} + +export default isEmpty; diff --git a/isEqualWith.js b/src/isEqualWith.ts similarity index 75% rename from isEqualWith.js rename to src/isEqualWith.ts index 98ab4f7b0..7c7b3e0d7 100644 --- a/isEqualWith.js +++ b/src/isEqualWith.ts @@ -1,4 +1,4 @@ -import baseIsEqual from './.internal/baseIsEqual.js' +import baseIsEqual from './.internal/baseIsEqual.js'; /** * This method is like `isEqual` except that it accepts `customizer` which @@ -31,9 +31,9 @@ import baseIsEqual from './.internal/baseIsEqual.js' * // => true */ function isEqualWith(value, other, customizer) { - customizer = typeof customizer === 'function' ? customizer : undefined - const result = customizer ? customizer(value, other) : undefined - return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result + customizer = typeof customizer === 'function' ? customizer : undefined; + const result = customizer ? customizer(value, other) : undefined; + return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; } -export default isEqualWith +export default isEqualWith; diff --git a/src/isError.ts b/src/isError.ts new file mode 100644 index 000000000..c8297c879 --- /dev/null +++ b/src/isError.ts @@ -0,0 +1,35 @@ +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; +import isPlainObject from './isPlainObject.js'; + +/** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @since 3.0.0 + * @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) { + if (!isObjectLike(value)) { + return false; + } + const tag = getTag(value); + return ( + tag == '[object Error]' || + tag == '[object DOMException]' || + (typeof value.message === 'string' && + typeof value.name === 'string' && + !isPlainObject(value)) + ); +} + +export default isError; diff --git a/isFunction.js b/src/isFunction.ts similarity index 88% rename from isFunction.js rename to src/isFunction.ts index be3f2f89f..07a03754e 100644 --- a/isFunction.js +++ b/src/isFunction.ts @@ -26,7 +26,7 @@ * // => false */ function isFunction(value) { - return typeof value === 'function' + return typeof value === 'function'; } -export default isFunction +export default isFunction; diff --git a/isLength.js b/src/isLength.ts similarity index 78% rename from isLength.js rename to src/isLength.ts index 193f254e8..224964857 100644 --- a/isLength.js +++ b/src/isLength.ts @@ -1,5 +1,5 @@ /** Used as references for various `Number` constants. */ -const MAX_SAFE_INTEGER = 9007199254740991 +const MAX_SAFE_INTEGER = 9007199254740991; /** * Checks if `value` is a valid array-like length. @@ -26,8 +26,7 @@ const MAX_SAFE_INTEGER = 9007199254740991 * // => false */ function isLength(value) { - return typeof value === 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER + return typeof value === 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; } -export default isLength +export default isLength; diff --git a/isMap.js b/src/isMap.ts similarity index 53% rename from isMap.js rename to src/isMap.ts index 1b59892e2..63bcd1d0e 100644 --- a/isMap.js +++ b/src/isMap.ts @@ -1,9 +1,9 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' -import nodeTypes from './.internal/nodeTypes.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; +import nodeTypes from './.internal/nodeTypes.js'; /* Node.js helper references. */ -const nodeIsMap = nodeTypes && nodeTypes.isMap +const nodeIsMap = nodeTypes && nodeTypes.isMap; /** * Checks if `value` is classified as a `Map` object. @@ -21,7 +21,7 @@ const nodeIsMap = nodeTypes && nodeTypes.isMap * // => false */ const isMap = nodeIsMap - ? (value) => nodeIsMap(value) - : (value) => isObjectLike(value) && getTag(value) == '[object Map]' + ? (value) => nodeIsMap(value) + : (value) => isObjectLike(value) && getTag(value) == '[object Map]'; -export default isMap +export default isMap; diff --git a/isMatch.js b/src/isMatch.ts similarity index 79% rename from isMatch.js rename to src/isMatch.ts index a9c46ad21..1d28085bc 100644 --- a/isMatch.js +++ b/src/isMatch.ts @@ -1,5 +1,5 @@ -import baseIsMatch from './.internal/baseIsMatch.js' -import getMatchData from './.internal/getMatchData.js' +import baseIsMatch from './.internal/baseIsMatch.js'; +import getMatchData from './.internal/getMatchData.js'; /** * Performs a partial deep comparison between `object` and `source` to @@ -28,7 +28,7 @@ import getMatchData from './.internal/getMatchData.js' * // => false */ function isMatch(object, source) { - return object === source || baseIsMatch(object, source, getMatchData(source)) + return object === source || baseIsMatch(object, source, getMatchData(source)); } -export default isMatch +export default isMatch; diff --git a/isMatchWith.js b/src/isMatchWith.ts similarity index 78% rename from isMatchWith.js rename to src/isMatchWith.ts index 79ef07a57..f2ec26247 100644 --- a/isMatchWith.js +++ b/src/isMatchWith.ts @@ -1,5 +1,5 @@ -import baseIsMatch from './.internal/baseIsMatch.js' -import getMatchData from './.internal/getMatchData.js' +import baseIsMatch from './.internal/baseIsMatch.js'; +import getMatchData from './.internal/getMatchData.js'; /** * This method is like `isMatch` except that it accepts `customizer` which @@ -32,8 +32,8 @@ import getMatchData from './.internal/getMatchData.js' * // => true */ function isMatchWith(object, source, customizer) { - customizer = typeof customizer === 'function' ? customizer : undefined - return baseIsMatch(object, source, getMatchData(source), customizer) + customizer = typeof customizer === 'function' ? customizer : undefined; + return baseIsMatch(object, source, getMatchData(source), customizer); } -export default isMatchWith +export default isMatchWith; diff --git a/isNative.js b/src/isNative.ts similarity index 56% rename from isNative.js rename to src/isNative.ts index 2bcd26816..4b7a6cc07 100644 --- a/isNative.js +++ b/src/isNative.ts @@ -1,17 +1,18 @@ -import isObject from './isObject.js' +import isObject from './isObject.js'; /** * Used to match `RegExp` * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ -const reRegExpChar = /[\\^$.*+?()[\]{}|]/g +const reRegExpChar = /[\\^$.*+?()[\]{}|]/g; /** Used to detect if a method is native. */ -const reIsNative = RegExp(`^${ - Function.prototype.toString.call(Object.prototype.hasOwnProperty) - .replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') -}$`) +const reIsNative = RegExp( + `^${Function.prototype.toString + .call(Object.prototype.hasOwnProperty) + .replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?')}$`, +); /** * Checks if `value` is a pristine native function. @@ -30,7 +31,7 @@ const reIsNative = RegExp(`^${ * // => false */ function isNative(value) { - return isObject(value) && reIsNative.test(value) + return isObject(value) && reIsNative.test(value); } -export default isNative +export default isNative; diff --git a/isNil.js b/src/isNil.ts similarity index 87% rename from isNil.js rename to src/isNil.ts index 4a70c9a56..85559616d 100644 --- a/isNil.js +++ b/src/isNil.ts @@ -17,7 +17,7 @@ * // => false */ function isNil(value) { - return value == null + return value == null; } -export default isNil +export default isNil; diff --git a/isNull.js b/src/isNull.ts similarity index 85% rename from isNull.js rename to src/isNull.ts index 1627b3ce7..d2e068e3e 100644 --- a/isNull.js +++ b/src/isNull.ts @@ -14,7 +14,7 @@ * // => false */ function isNull(value) { - return value === null + return value === null; } -export default isNull +export default isNull; diff --git a/isNumber.js b/src/isNumber.ts similarity index 73% rename from isNumber.js rename to src/isNumber.ts index bb808a2c4..366a1786f 100644 --- a/isNumber.js +++ b/src/isNumber.ts @@ -1,5 +1,5 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; /** * Checks if `value` is classified as a `Number` primitive or object. @@ -27,8 +27,7 @@ import isObjectLike from './isObjectLike.js' * // => false */ function isNumber(value) { - return typeof value === 'number' || - (isObjectLike(value) && getTag(value) == '[object Number]') + return typeof value === 'number' || (isObjectLike(value) && getTag(value) == '[object Number]'); } -export default isNumber +export default isNumber; diff --git a/isObject.js b/src/isObject.ts similarity index 81% rename from isObject.js rename to src/isObject.ts index e9e81bff5..f5bb8e806 100644 --- a/isObject.js +++ b/src/isObject.ts @@ -22,8 +22,8 @@ * // => false */ function isObject(value) { - const type = typeof value - return value != null && (type === 'object' || type === 'function') + const type = typeof value; + return value != null && (type === 'object' || type === 'function'); } -export default isObject +export default isObject; diff --git a/isObjectLike.js b/src/isObjectLike.ts similarity index 85% rename from isObjectLike.js rename to src/isObjectLike.ts index 7175076a8..7ed077300 100644 --- a/isObjectLike.js +++ b/src/isObjectLike.ts @@ -21,7 +21,7 @@ * // => false */ function isObjectLike(value) { - return typeof value === 'object' && value !== null + return typeof value === 'object' && value !== null; } -export default isObjectLike +export default isObjectLike; diff --git a/isPlainObject.js b/src/isPlainObject.ts similarity index 55% rename from isPlainObject.js rename to src/isPlainObject.ts index 896d4576f..975a295d0 100644 --- a/isPlainObject.js +++ b/src/isPlainObject.ts @@ -1,5 +1,5 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; /** * Checks if `value` is a plain object, that is, an object created by the @@ -28,17 +28,17 @@ import isObjectLike from './isObjectLike.js' * // => true */ function isPlainObject(value) { - if (!isObjectLike(value) || getTag(value) != '[object Object]') { - return false - } - if (Object.getPrototypeOf(value) === null) { - return true - } - let proto = value - while (Object.getPrototypeOf(proto) !== null) { - proto = Object.getPrototypeOf(proto) - } - return Object.getPrototypeOf(value) === proto + if (!isObjectLike(value) || getTag(value) != '[object Object]') { + return false; + } + if (Object.getPrototypeOf(value) === null) { + return true; + } + let proto = value; + while (Object.getPrototypeOf(proto) !== null) { + proto = Object.getPrototypeOf(proto); + } + return Object.getPrototypeOf(value) === proto; } -export default isPlainObject +export default isPlainObject; diff --git a/isRegExp.js b/src/isRegExp.ts similarity index 52% rename from isRegExp.js rename to src/isRegExp.ts index 42d567d68..c1f3364cf 100644 --- a/isRegExp.js +++ b/src/isRegExp.ts @@ -1,9 +1,9 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' -import nodeTypes from './.internal/nodeTypes.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; +import nodeTypes from './.internal/nodeTypes.js'; /* Node.js helper references. */ -const nodeIsRegExp = nodeTypes && nodeTypes.isRegExp +const nodeIsRegExp = nodeTypes && nodeTypes.isRegExp; /** * Checks if `value` is classified as a `RegExp` object. @@ -21,7 +21,7 @@ const nodeIsRegExp = nodeTypes && nodeTypes.isRegExp * // => false */ const isRegExp = nodeIsRegExp - ? (value) => nodeIsRegExp(value) - : (value) => isObjectLike(value) && getTag(value) == '[object RegExp]' + ? (value) => nodeIsRegExp(value) + : (value) => isObjectLike(value) && getTag(value) == '[object RegExp]'; -export default isRegExp +export default isRegExp; diff --git a/isSet.js b/src/isSet.ts similarity index 53% rename from isSet.js rename to src/isSet.ts index 51195abe6..51be99008 100644 --- a/isSet.js +++ b/src/isSet.ts @@ -1,9 +1,9 @@ -import getTag from './.internal/getTag.js' -import nodeTypes from './.internal/nodeTypes.js' -import isObjectLike from './isObjectLike.js' +import getTag from './.internal/getTag.js'; +import nodeTypes from './.internal/nodeTypes.js'; +import isObjectLike from './isObjectLike.js'; /* Node.js helper references. */ -const nodeIsSet = nodeTypes && nodeTypes.isSet +const nodeIsSet = nodeTypes && nodeTypes.isSet; /** * Checks if `value` is classified as a `Set` object. @@ -21,7 +21,7 @@ const nodeIsSet = nodeTypes && nodeTypes.isSet * // => false */ const isSet = nodeIsSet - ? (value) => nodeIsSet(value) - : (value) => isObjectLike(value) && getTag(value) == '[object Set]' + ? (value) => nodeIsSet(value) + : (value) => isObjectLike(value) && getTag(value) == '[object Set]'; -export default isSet +export default isSet; diff --git a/isString.js b/src/isString.ts similarity index 53% rename from isString.js rename to src/isString.ts index b5470a9cc..9a33d8c73 100644 --- a/isString.js +++ b/src/isString.ts @@ -1,4 +1,4 @@ -import getTag from './.internal/getTag.js' +import getTag from './.internal/getTag.js'; /** * Checks if `value` is classified as a `String` primitive or object. @@ -16,8 +16,14 @@ import getTag from './.internal/getTag.js' * // => false */ function isString(value) { - const type = typeof value - return type === 'string' || (type === 'object' && value != null && !Array.isArray(value) && getTag(value) == '[object String]') + const type = typeof value; + return ( + type === 'string' || + (type === 'object' && + value != null && + !Array.isArray(value) && + getTag(value) == '[object String]') + ); } -export default isString +export default isString; diff --git a/isSymbol.js b/src/isSymbol.ts similarity index 60% rename from isSymbol.js rename to src/isSymbol.ts index 0cf4c70e5..ed247c835 100644 --- a/isSymbol.js +++ b/src/isSymbol.ts @@ -1,4 +1,4 @@ -import getTag from './.internal/getTag.js' +import getTag from './.internal/getTag.js'; /** * Checks if `value` is classified as a `Symbol` primitive or object. @@ -16,8 +16,11 @@ import getTag from './.internal/getTag.js' * // => false */ function isSymbol(value) { - const type = typeof value - return type == 'symbol' || (type === 'object' && value != null && getTag(value) == '[object Symbol]') + const type = typeof value; + return ( + type == 'symbol' || + (type === 'object' && value != null && getTag(value) == '[object Symbol]') + ); } -export default isSymbol +export default isSymbol; diff --git a/isTypedArray.js b/src/isTypedArray.ts similarity index 57% rename from isTypedArray.js rename to src/isTypedArray.ts index 184bbe4b3..28db4518e 100644 --- a/isTypedArray.js +++ b/src/isTypedArray.ts @@ -1,12 +1,12 @@ -import getTag from './.internal/getTag.js' -import nodeTypes from './.internal/nodeTypes.js' -import isObjectLike from './isObjectLike.js' +import getTag from './.internal/getTag.js'; +import nodeTypes from './.internal/nodeTypes.js'; +import isObjectLike from './isObjectLike.js'; /** Used to match `toStringTag` values of typed arrays. */ -const reTypedTag = /^\[object (?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)Array\]$/ +const reTypedTag = /^\[object (?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)Array\]$/; /* Node.js helper references. */ -const nodeIsTypedArray = nodeTypes && nodeTypes.isTypedArray +const nodeIsTypedArray = nodeTypes && nodeTypes.isTypedArray; /** * Checks if `value` is classified as a typed array. @@ -24,7 +24,7 @@ const nodeIsTypedArray = nodeTypes && nodeTypes.isTypedArray * // => false */ const isTypedArray = nodeIsTypedArray - ? (value) => nodeIsTypedArray(value) - : (value) => isObjectLike(value) && reTypedTag.test(getTag(value)) + ? (value) => nodeIsTypedArray(value) + : (value) => isObjectLike(value) && reTypedTag.test(getTag(value)); -export default isTypedArray +export default isTypedArray; diff --git a/isUndefined.js b/src/isUndefined.ts similarity index 84% rename from isUndefined.js rename to src/isUndefined.ts index e92c558c8..b178950a9 100644 --- a/isUndefined.js +++ b/src/isUndefined.ts @@ -14,7 +14,7 @@ * // => false */ function isUndefined(value) { - return value === undefined + return value === undefined; } -export default isUndefined +export default isUndefined; diff --git a/isWeakMap.js b/src/isWeakMap.ts similarity index 64% rename from isWeakMap.js rename to src/isWeakMap.ts index 0271dca45..5a7c9637c 100644 --- a/isWeakMap.js +++ b/src/isWeakMap.ts @@ -1,5 +1,5 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; /** * Checks if `value` is classified as a `WeakMap` object. @@ -17,7 +17,7 @@ import isObjectLike from './isObjectLike.js' * // => false */ function isWeakMap(value) { - return isObjectLike(value) && getTag(value) == '[object WeakMap]' + return isObjectLike(value) && getTag(value) == '[object WeakMap]'; } -export default isWeakMap +export default isWeakMap; diff --git a/isWeakSet.js b/src/isWeakSet.ts similarity index 64% rename from isWeakSet.js rename to src/isWeakSet.ts index a14b57914..90e83b34a 100644 --- a/isWeakSet.js +++ b/src/isWeakSet.ts @@ -1,5 +1,5 @@ -import getTag from './.internal/getTag.js' -import isObjectLike from './isObjectLike.js' +import getTag from './.internal/getTag.js'; +import isObjectLike from './isObjectLike.js'; /** * Checks if `value` is classified as a `WeakSet` object. @@ -17,7 +17,7 @@ import isObjectLike from './isObjectLike.js' * // => false */ function isWeakSet(value) { - return isObjectLike(value) && getTag(value) == '[object WeakSet]' + return isObjectLike(value) && getTag(value) == '[object WeakSet]'; } -export default isWeakSet +export default isWeakSet; diff --git a/kebabCase.js b/src/kebabCase.ts similarity index 62% rename from kebabCase.js rename to src/kebabCase.ts index bc436b949..f1e0d30b1 100644 --- a/kebabCase.js +++ b/src/kebabCase.ts @@ -1,5 +1,5 @@ -import words from './words.js' -import toString from './toString.js' +import words from './words.js'; +import toString from './toString.js'; /** * Converts `string` to @@ -21,10 +21,10 @@ import toString from './toString.js' * kebabCase('__FOO_BAR__') * // => 'foo-bar' */ -const kebabCase = (string) => ( - words(toString(string).replace(/['\u2019]/g, '')).reduce((result, word, index) => ( - result + (index ? '-' : '') + word.toLowerCase() - ), '') -) +const kebabCase = (string) => + words(toString(string).replace(/['\u2019]/g, '')).reduce( + (result, word, index) => result + (index ? '-' : '') + word.toLowerCase(), + '', + ); -export default kebabCase +export default kebabCase; diff --git a/keyBy.js b/src/keyBy.ts similarity index 75% rename from keyBy.js rename to src/keyBy.ts index 2297565bb..f2d138ccd 100644 --- a/keyBy.js +++ b/src/keyBy.ts @@ -1,5 +1,5 @@ -import baseAssignValue from './.internal/baseAssignValue.js' -import reduce from './reduce.js' +import baseAssignValue from './.internal/baseAssignValue.js'; +import reduce from './reduce.js'; /** * Creates an object composed of keys generated from the results of running @@ -24,9 +24,11 @@ import reduce from './reduce.js' * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } */ function keyBy(collection, iteratee) { - return reduce(collection, (result, value, key) => ( - baseAssignValue(result, iteratee(value), value), result - ), {}) + return reduce( + collection, + (result, value, key) => (baseAssignValue(result, iteratee(value), value), result), + {}, + ); } -export default keyBy +export default keyBy; diff --git a/keys.js b/src/keys.ts similarity index 75% rename from keys.js rename to src/keys.ts index 43b241c11..af973bf16 100644 --- a/keys.js +++ b/src/keys.ts @@ -1,5 +1,5 @@ -import arrayLikeKeys from './.internal/arrayLikeKeys.js' -import isArrayLike from './isArrayLike.js' +import arrayLikeKeys from './.internal/arrayLikeKeys.js'; +import isArrayLike from './isArrayLike.js'; /** * Creates an array of the own enumerable property names of `object`. @@ -29,9 +29,7 @@ import isArrayLike from './isArrayLike.js' * // => ['0', '1'] */ function keys(object) { - return isArrayLike(object) - ? arrayLikeKeys(object) - : Object.keys(Object(object)) + return isArrayLike(object) ? arrayLikeKeys(object) : Object.keys(Object(object)); } -export default keys +export default keys; diff --git a/keysIn.js b/src/keysIn.ts similarity index 78% rename from keysIn.js rename to src/keysIn.ts index b426b3de0..367d775a8 100644 --- a/keysIn.js +++ b/src/keysIn.ts @@ -21,12 +21,11 @@ * // => ['a', 'b', 'c'] (iteration order is not guaranteed) */ function keysIn(object) { - const result = [] - for (const key in object) { - result.push(key) - } - return result + const result = []; + for (const key in object) { + result.push(key); + } + return result; } -export default keysIn - +export default keysIn; diff --git a/last.js b/src/last.ts similarity index 66% rename from last.js rename to src/last.ts index 3bb7dfd8b..465670437 100644 --- a/last.js +++ b/src/last.ts @@ -11,8 +11,8 @@ * // => 3 */ function last(array) { - const length = array == null ? 0 : array.length - return length ? array[length - 1] : undefined + const length = array == null ? 0 : array.length; + return length ? array[length - 1] : undefined; } -export default last +export default last; diff --git a/lastIndexOf.js b/src/lastIndexOf.ts similarity index 51% rename from lastIndexOf.js rename to src/lastIndexOf.ts index 23f3a76e7..7623b175c 100644 --- a/lastIndexOf.js +++ b/src/lastIndexOf.ts @@ -1,7 +1,7 @@ -import baseFindIndex from './.internal/baseFindIndex.js' -import baseIsNaN from './.internal/baseIsNaN.js' -import strictLastIndexOf from './.internal/strictLastIndexOf.js' -import toInteger from './toInteger.js' +import baseFindIndex from './.internal/baseFindIndex.js'; +import baseIsNaN from './.internal/baseIsNaN.js'; +import strictLastIndexOf from './.internal/strictLastIndexOf.js'; +import toInteger from './toInteger.js'; /** * This method is like `indexOf` except that it iterates over elements of @@ -23,18 +23,18 @@ import toInteger from './toInteger.js' * // => 1 */ function lastIndexOf(array, value, fromIndex) { - const length = array == null ? 0 : array.length - if (!length) { - return -1 - } - let index = length - if (fromIndex !== undefined) { - index = toInteger(fromIndex) - index = index < 0 ? Math.max(length + index, 0) : Math.min(index, length - 1) - } - return value === value - ? strictLastIndexOf(array, value, index) - : baseFindIndex(array, baseIsNaN, index, true) + const length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + let index = length; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = index < 0 ? Math.max(length + index, 0) : Math.min(index, length - 1); + } + return value === value + ? strictLastIndexOf(array, value, index) + : baseFindIndex(array, baseIsNaN, index, true); } -export default lastIndexOf +export default lastIndexOf; diff --git a/lowerCase.js b/src/lowerCase.ts similarity index 58% rename from lowerCase.js rename to src/lowerCase.ts index 3da8966cf..533c1e0a2 100644 --- a/lowerCase.js +++ b/src/lowerCase.ts @@ -1,7 +1,7 @@ -import words from './words.js' -import toString from './toString.js' +import words from './words.js'; +import toString from './toString.js'; -const reQuotes = /['\u2019]/g +const reQuotes = /['\u2019]/g; /** * Converts `string`, as space separated words, to lower case. @@ -22,10 +22,10 @@ const reQuotes = /['\u2019]/g * lowerCase('__FOO_BAR__') * // => 'foo bar' */ -const lowerCase = (string) => ( - words(toString(string).replace(reQuotes, '')).reduce((result, word, index) => ( - result + (index ? ' ' : '') + word.toLowerCase() - ), '') -) +const lowerCase = (string) => + words(toString(string).replace(reQuotes, '')).reduce( + (result, word, index) => result + (index ? ' ' : '') + word.toLowerCase(), + '', + ); -export default lowerCase +export default lowerCase; diff --git a/lowerFirst.js b/src/lowerFirst.ts similarity index 68% rename from lowerFirst.js rename to src/lowerFirst.ts index f56952191..ad63b84d5 100644 --- a/lowerFirst.js +++ b/src/lowerFirst.ts @@ -1,4 +1,4 @@ -import createCaseFirst from './.internal/createCaseFirst.js' +import createCaseFirst from './.internal/createCaseFirst.js'; /** * Converts the first character of `string` to lower case. @@ -15,6 +15,6 @@ import createCaseFirst from './.internal/createCaseFirst.js' * lowerFirst('FRED') * // => 'fRED' */ -const lowerFirst = createCaseFirst('toLowerCase') +const lowerFirst = createCaseFirst('toLowerCase'); -export default lowerFirst +export default lowerFirst; diff --git a/lt.js b/src/lt.ts similarity index 71% rename from lt.js rename to src/lt.ts index f2acbcdaa..29d7a2e77 100644 --- a/lt.js +++ b/src/lt.ts @@ -20,11 +20,11 @@ * // => false */ function lt(value, other) { - if (!(typeof value === 'string' && typeof other === 'string')) { - value = +value - other = +other - } - return value < other + if (!(typeof value === 'string' && typeof other === 'string')) { + value = +value; + other = +other; + } + return value < other; } -export default lt +export default lt; diff --git a/lte.js b/src/lte.ts similarity index 72% rename from lte.js rename to src/lte.ts index ef7ef451f..2bd548df9 100644 --- a/lte.js +++ b/src/lte.ts @@ -20,11 +20,11 @@ * // => false */ function lte(value, other) { - if (!(typeof value === 'string' && typeof other === 'string')) { - value = +value - other = +other - } - return value <= other + if (!(typeof value === 'string' && typeof other === 'string')) { + value = +value; + other = +other; + } + return value <= other; } -export default lte +export default lte; diff --git a/map.js b/src/map.ts similarity index 67% rename from map.js rename to src/map.ts index 3711d2b1d..04bc6a51a 100644 --- a/map.js +++ b/src/map.ts @@ -17,14 +17,14 @@ * // => [16, 64] */ function map(array, iteratee) { - let index = -1 - const length = array == null ? 0 : array.length - const result = new Array(length) + let index = -1; + const length = array == null ? 0 : array.length; + const result = new Array(length); - while (++index < length) { - result[index] = iteratee(array[index], index, array) - } - return result + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; } -export default map +export default map; diff --git a/mapKey.js b/src/mapKey.ts similarity index 74% rename from mapKey.js rename to src/mapKey.ts index a69e5b2d3..26bbce7c6 100644 --- a/mapKey.js +++ b/src/mapKey.ts @@ -18,14 +18,14 @@ * // => { 'a1': 1, 'b2': 2 } */ function mapKey(object, iteratee) { - object = Object(object) - const result = {} + object = Object(object); + const result = {}; - Object.keys(object).forEach((key) => { - const value = object[key] - result[iteratee(value, key, object)] = value - }) - return result + Object.keys(object).forEach((key) => { + const value = object[key]; + result[iteratee(value, key, object)] = value; + }); + return result; } -export default mapKey +export default mapKey; diff --git a/mapObject.js b/src/mapObject.ts similarity index 71% rename from mapObject.js rename to src/mapObject.ts index a817ca729..f474b0a67 100644 --- a/mapObject.js +++ b/src/mapObject.ts @@ -17,13 +17,13 @@ * // => [16, 64] (iteration order is not guaranteed) */ function mapObject(object, iteratee) { - const props = Object.keys(object) - const result = new Array(props.length) + const props = Object.keys(object); + const result = new Array(props.length); - props.forEach((key, index) => { - result[index] = iteratee(object[key], key, object) - }) - return result + props.forEach((key, index) => { + result[index] = iteratee(object[key], key, object); + }); + return result; } -export default mapObject +export default mapObject; diff --git a/mapValue.js b/src/mapValue.ts similarity index 78% rename from mapValue.js rename to src/mapValue.ts index d8d9aa779..05160f48e 100644 --- a/mapValue.js +++ b/src/mapValue.ts @@ -21,13 +21,13 @@ * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) */ function mapValue(object, iteratee) { - object = Object(object) - const result = {} + object = Object(object); + const result = {}; - Object.keys(object).forEach((key) => { - result[key] = iteratee(object[key], key, object) - }) - return result + Object.keys(object).forEach((key) => { + result[key] = iteratee(object[key], key, object); + }); + return result; } -export default mapValue +export default mapValue; diff --git a/matches.js b/src/matches.ts similarity index 81% rename from matches.js rename to src/matches.ts index a0ae76a84..1aa08732e 100644 --- a/matches.js +++ b/src/matches.ts @@ -1,8 +1,8 @@ -import baseClone from './.internal/baseClone.js' -import baseMatches from './.internal/baseMatches.js' +import baseClone from './.internal/baseClone.js'; +import baseMatches from './.internal/baseMatches.js'; /** Used to compose bitmasks for cloning. */ -const CLONE_DEEP_FLAG = 1 +const CLONE_DEEP_FLAG = 1; /** * Creates a function that performs a partial deep comparison between a given @@ -31,7 +31,7 @@ const CLONE_DEEP_FLAG = 1 * // => [{ 'a': 4, 'b': 5, 'c': 6 }] */ function matches(source) { - return baseMatches(baseClone(source, CLONE_DEEP_FLAG)) + return baseMatches(baseClone(source, CLONE_DEEP_FLAG)); } -export default matches +export default matches; diff --git a/matchesProperty.js b/src/matchesProperty.ts similarity index 83% rename from matchesProperty.js rename to src/matchesProperty.ts index cf6122e8f..5739637db 100644 --- a/matchesProperty.js +++ b/src/matchesProperty.ts @@ -1,8 +1,8 @@ -import baseClone from './.internal/baseClone.js' -import baseMatchesProperty from './.internal/baseMatchesProperty.js' +import baseClone from './.internal/baseClone.js'; +import baseMatchesProperty from './.internal/baseMatchesProperty.js'; /** Used to compose bitmasks for cloning. */ -const CLONE_DEEP_FLAG = 1 +const CLONE_DEEP_FLAG = 1; /** * Creates a function that performs a partial deep comparison between the @@ -29,7 +29,7 @@ const CLONE_DEEP_FLAG = 1 * // => { 'a': 4, 'b': 5, 'c': 6 } */ function matchesProperty(path, srcValue) { - return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG)) + return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG)); } -export default matchesProperty +export default matchesProperty; diff --git a/maxBy.js b/src/maxBy.ts similarity index 53% rename from maxBy.js rename to src/maxBy.ts index d8d9d5903..b3317edce 100644 --- a/maxBy.js +++ b/src/maxBy.ts @@ -1,4 +1,4 @@ -import isSymbol from './isSymbol.js' +import isSymbol from './isSymbol.js'; /** * This method is like `max` except that it accepts `iteratee` which is @@ -18,23 +18,25 @@ import isSymbol from './isSymbol.js' * // => { 'n': 2 } */ function maxBy(array, iteratee) { - let result - if (array == null) { - return result - } - let computed - for (const value of array) { - const current = iteratee(value) - - if (current != null && (computed === undefined - ? (current === current && !isSymbol(current)) - : (current > computed) - )) { - computed = current - result = value + let result; + if (array == null) { + return result; } - } - return result + let computed; + for (const value of array) { + const current = iteratee(value); + + if ( + current != null && + (computed === undefined + ? current === current && !isSymbol(current) + : current > computed) + ) { + computed = current; + result = value; + } + } + return result; } -export default maxBy +export default maxBy; diff --git a/mean.js b/src/mean.ts similarity index 71% rename from mean.js rename to src/mean.ts index 8f6d317f7..e0ac81ea7 100644 --- a/mean.js +++ b/src/mean.ts @@ -1,4 +1,4 @@ -import baseMean from './meanBy.js' +import baseMean from './meanBy.js'; /** * Computes the mean of the values in `array`. @@ -13,7 +13,7 @@ import baseMean from './meanBy.js' * // => 5 */ function mean(array) { - return baseMean(array, (value) => value) + return baseMean(array, (value) => value); } -export default mean +export default mean; diff --git a/meanBy.js b/src/meanBy.ts similarity index 75% rename from meanBy.js rename to src/meanBy.ts index d365c8972..af130b226 100644 --- a/meanBy.js +++ b/src/meanBy.ts @@ -1,7 +1,7 @@ -import baseSum from './.internal/baseSum.js' +import baseSum from './.internal/baseSum.js'; /** Used as references for various `Number` constants. */ -const NAN = 0 / 0 +const NAN = 0 / 0; /** * This method is like `mean` except that it accepts `iteratee` which is @@ -21,8 +21,8 @@ const NAN = 0 / 0 * // => 5 */ function meanBy(array, iteratee) { - const length = array == null ? 0 : array.length - return length ? (baseSum(array, iteratee) / length) : NAN + const length = array == null ? 0 : array.length; + return length ? baseSum(array, iteratee) / length : NAN; } -export default meanBy +export default meanBy; diff --git a/memoize.js b/src/memoize.ts similarity index 70% rename from memoize.js rename to src/memoize.ts index 8e41558ec..7a4da23dc 100644 --- a/memoize.js +++ b/src/memoize.ts @@ -41,24 +41,24 @@ * memoize.Cache = WeakMap */ function memoize(func, resolver) { - if (typeof func !== 'function' || (resolver != null && typeof resolver !== 'function')) { - throw new TypeError('Expected a function') - } - const memoized = function(...args) { - const key = resolver ? resolver.apply(this, args) : args[0] - const cache = memoized.cache - - if (cache.has(key)) { - return cache.get(key) + if (typeof func !== 'function' || (resolver != null && typeof resolver !== 'function')) { + throw new TypeError('Expected a function'); } - const result = func.apply(this, args) - memoized.cache = cache.set(key, result) || cache - return result - } - memoized.cache = new (memoize.Cache || Map) - return memoized + const memoized = function (...args) { + const key = resolver ? resolver.apply(this, args) : args[0]; + const cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + const result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || Map)(); + return memoized; } -memoize.Cache = Map +memoize.Cache = Map; -export default memoize +export default memoize; diff --git a/merge.js b/src/merge.ts similarity index 85% rename from merge.js rename to src/merge.ts index 730b29634..108385e87 100644 --- a/merge.js +++ b/src/merge.ts @@ -1,5 +1,5 @@ -import baseMerge from './.internal/baseMerge.js' -import createAssigner from './.internal/createAssigner.js' +import baseMerge from './.internal/baseMerge.js'; +import createAssigner from './.internal/createAssigner.js'; /** * This method is like `assign` except that it recursively merges own and @@ -31,7 +31,7 @@ import createAssigner from './.internal/createAssigner.js' * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } */ const merge = createAssigner((object, source, srcIndex) => { - baseMerge(object, source, srcIndex) -}) + baseMerge(object, source, srcIndex); +}); -export default merge +export default merge; diff --git a/mergeWith.js b/src/mergeWith.ts similarity index 84% rename from mergeWith.js rename to src/mergeWith.ts index dc930be41..149f8757a 100644 --- a/mergeWith.js +++ b/src/mergeWith.ts @@ -1,5 +1,5 @@ -import baseMerge from './.internal/baseMerge.js' -import createAssigner from './.internal/createAssigner.js' +import baseMerge from './.internal/baseMerge.js'; +import createAssigner from './.internal/createAssigner.js'; /** * This method is like `merge` except that it accepts `customizer` which @@ -31,7 +31,7 @@ import createAssigner from './.internal/createAssigner.js' * // => { 'a': [1, 3], 'b': [2, 4] } */ const mergeWith = createAssigner((object, source, srcIndex, customizer) => { - baseMerge(object, source, srcIndex, customizer) -}) + baseMerge(object, source, srcIndex, customizer); +}); -export default mergeWith +export default mergeWith; diff --git a/method.js b/src/method.ts similarity index 85% rename from method.js rename to src/method.ts index 3405e695c..5b66f54b0 100644 --- a/method.js +++ b/src/method.ts @@ -1,4 +1,4 @@ -import invoke from './invoke.js' +import invoke from './invoke.js'; /** * Creates a function that invokes the method at `path` of a given object. @@ -23,7 +23,7 @@ import invoke from './invoke.js' * // => [2, 1] */ function method(path, args) { - return (object) => invoke(object, path, args) + return (object) => invoke(object, path, args); } -export default method +export default method; diff --git a/methodOf.js b/src/methodOf.ts similarity index 86% rename from methodOf.js rename to src/methodOf.ts index ff39385b1..dda40ec75 100644 --- a/methodOf.js +++ b/src/methodOf.ts @@ -1,4 +1,4 @@ -import invoke from './invoke.js' +import invoke from './invoke.js'; /** * The opposite of `method` this method creates a function that invokes @@ -22,7 +22,7 @@ import invoke from './invoke.js' * // => [2, 0]f */ function methodOf(object, args) { - return (path) => invoke(object, path, args) + return (path) => invoke(object, path, args); } -export default methodOf +export default methodOf; diff --git a/minBy.js b/src/minBy.ts similarity index 53% rename from minBy.js rename to src/minBy.ts index cb0fe8233..4e5298981 100644 --- a/minBy.js +++ b/src/minBy.ts @@ -1,4 +1,4 @@ -import isSymbol from './isSymbol.js' +import isSymbol from './isSymbol.js'; /** * This method is like `min` except that it accepts `iteratee` which is @@ -18,23 +18,25 @@ import isSymbol from './isSymbol.js' * // => { 'n': 1 } */ function minBy(array, iteratee) { - let result - if (array == null) { - return result - } - let computed - for (const value of array) { - const current = iteratee(value) - - if (current != null && (computed === undefined - ? (current === current && !isSymbol(current)) - : (current < computed) - )) { - computed = current - result = value + let result; + if (array == null) { + return result; } - } - return result + let computed; + for (const value of array) { + const current = iteratee(value); + + if ( + current != null && + (computed === undefined + ? current === current && !isSymbol(current) + : current < computed) + ) { + computed = current; + result = value; + } + } + return result; } -export default minBy +export default minBy; diff --git a/multiply.js b/src/multiply.ts similarity index 86% rename from multiply.js rename to src/multiply.ts index 8ccba1406..5c6b8e40c 100644 --- a/multiply.js +++ b/src/multiply.ts @@ -1,4 +1,4 @@ -import createMathOperation from './.internal/createMathOperation.js' +import createMathOperation from './.internal/createMathOperation.js'; /** * Multiply two numbers. @@ -13,6 +13,6 @@ import createMathOperation from './.internal/createMathOperation.js' * multiply(6, 4) * // => 24 */ -const multiply = createMathOperation((multiplier, multiplicand) => multiplier * multiplicand, 1) +const multiply = createMathOperation((multiplier, multiplicand) => multiplier * multiplicand, 1); -export default multiply +export default multiply; diff --git a/negate.js b/src/negate.ts similarity index 70% rename from negate.js rename to src/negate.ts index 2e2f863f1..83c30c03a 100644 --- a/negate.js +++ b/src/negate.ts @@ -17,12 +17,12 @@ * // => [1, 3, 5] */ function negate(predicate) { - if (typeof predicate !== 'function') { - throw new TypeError('Expected a function') - } - return function(...args) { - return !predicate.apply(this, args) - } + if (typeof predicate !== 'function') { + throw new TypeError('Expected a function'); + } + return function (...args) { + return !predicate.apply(this, args); + }; } -export default negate +export default negate; diff --git a/nth.js b/src/nth.ts similarity index 65% rename from nth.js rename to src/nth.ts index b2425a7dd..30c94262d 100644 --- a/nth.js +++ b/src/nth.ts @@ -1,4 +1,4 @@ -import isIndex from './.internal/isIndex.js' +import isIndex from './.internal/isIndex.js'; /** * Gets the element at index `n` of `array`. If `n` is negative, the nth @@ -20,12 +20,12 @@ import isIndex from './.internal/isIndex.js' * // => 'c' */ function nth(array, n) { - const length = array == null ? 0 : array.length - if (!length) { - return - } - n += n < 0 ? length : 0 - return isIndex(n, length) ? array[n] : undefined + const length = array == null ? 0 : array.length; + if (!length) { + return; + } + n += n < 0 ? length : 0; + return isIndex(n, length) ? array[n] : undefined; } -export default nth +export default nth; diff --git a/nthArg.js b/src/nthArg.ts similarity index 84% rename from nthArg.js rename to src/nthArg.ts index f5da0cf51..70b340dde 100644 --- a/nthArg.js +++ b/src/nthArg.ts @@ -1,4 +1,4 @@ -import nth from './nth.js' +import nth from './nth.js'; /** * Creates a function that gets the argument at index `n`. If `n` is negative, @@ -19,7 +19,7 @@ import nth from './nth.js' * // => 'c' */ function nthArg(n) { - return (...args) => nth(args, n) + return (...args) => nth(args, n); } -export default nthArg +export default nthArg; diff --git a/once.js b/src/once.ts similarity index 86% rename from once.js rename to src/once.ts index 653000bea..f6a12ec2e 100644 --- a/once.js +++ b/src/once.ts @@ -1,4 +1,4 @@ -import before from './before.js' +import before from './before.js'; /** * Creates a function that is restricted to invoking `func` once. Repeat calls @@ -17,7 +17,7 @@ import before from './before.js' * // => `createApplication` is invoked once */ function once(func) { - return before(2, func) + return before(2, func); } -export default once +export default once; diff --git a/orderBy.js b/src/orderBy.ts similarity index 78% rename from orderBy.js rename to src/orderBy.ts index 4bb2112ef..0f439c7bf 100644 --- a/orderBy.js +++ b/src/orderBy.ts @@ -1,4 +1,4 @@ -import baseOrderBy from './.internal/baseOrderBy.js' +import baseOrderBy from './.internal/baseOrderBy.js'; /** * This method is like `sortBy` except that it allows specifying the sort @@ -36,16 +36,16 @@ import baseOrderBy from './.internal/baseOrderBy.js' * */ function orderBy(collection, iteratees, orders) { - if (collection == null) { - return [] - } - if (!Array.isArray(iteratees)) { - iteratees = iteratees == null ? [] : [iteratees] - } - if (!Array.isArray(orders)) { - orders = orders == null ? [] : [orders] - } - return baseOrderBy(collection, iteratees, orders) + if (collection == null) { + return []; + } + if (!Array.isArray(iteratees)) { + iteratees = iteratees == null ? [] : [iteratees]; + } + if (!Array.isArray(orders)) { + orders = orders == null ? [] : [orders]; + } + return baseOrderBy(collection, iteratees, orders); } -export default orderBy +export default orderBy; diff --git a/over.js b/src/over.ts similarity index 71% rename from over.js rename to src/over.ts index d4e41daa0..29ea14423 100644 --- a/over.js +++ b/src/over.ts @@ -1,4 +1,4 @@ -import map from './map.js' +import map from './map.js'; /** * Creates a function that invokes `iteratees` with the arguments it receives @@ -17,9 +17,9 @@ import map from './map.js' * // => [4, 1] */ function over(iteratees) { - return function(...args) { - return map(iteratees, (iteratee) => iteratee.apply(this, args)) - } + return function (...args) { + return map(iteratees, (iteratee) => iteratee.apply(this, args)); + }; } -export default over +export default over; diff --git a/overArgs.js b/src/overArgs.ts similarity index 63% rename from overArgs.js rename to src/overArgs.ts index 7a1479ec6..97572358d 100644 --- a/overArgs.js +++ b/src/overArgs.ts @@ -1,4 +1,3 @@ - /** * Creates a function that invokes `func` with its arguments transformed. * @@ -27,15 +26,15 @@ * // => [100, 10] */ function overArgs(func, transforms) { - const funcsLength = transforms.length - return function(...args) { - let index = -1 - const length = Math.min(args.length, funcsLength) - while (++index < length) { - args[index] = transforms[index].call(this, args[index]) - } - return func.apply(this, args) - } + const funcsLength = transforms.length; + return function (...args) { + let index = -1; + const length = Math.min(args.length, funcsLength); + while (++index < length) { + args[index] = transforms[index].call(this, args[index]); + } + return func.apply(this, args); + }; } -export default overArgs +export default overArgs; diff --git a/overEvery.js b/src/overEvery.ts similarity index 73% rename from overEvery.js rename to src/overEvery.ts index 4f22a9956..f4a9ecbc1 100644 --- a/overEvery.js +++ b/src/overEvery.ts @@ -1,4 +1,4 @@ -import every from './every.js' +import every from './every.js'; /** * Creates a function that checks if **all** of the `predicates` return @@ -23,9 +23,9 @@ import every from './every.js' * // => false */ function overEvery(iteratees) { - return function(...args) { - return every(iteratees, (iteratee) => iteratee.apply(this, args)) - } + return function (...args) { + return every(iteratees, (iteratee) => iteratee.apply(this, args)); + }; } -export default overEvery +export default overEvery; diff --git a/overSome.js b/src/overSome.ts similarity index 74% rename from overSome.js rename to src/overSome.ts index 6b2c0dcbb..573548e30 100644 --- a/overSome.js +++ b/src/overSome.ts @@ -1,4 +1,4 @@ -import some from './some.js' +import some from './some.js'; /** * Creates a function that checks if **any** of the `predicates` return @@ -23,9 +23,9 @@ import some from './some.js' * // => false */ function overSome(iteratees) { - return function(...args) { - return some(iteratees, (iteratee) => iteratee.apply(this, args)) - } + return function (...args) { + return some(iteratees, (iteratee) => iteratee.apply(this, args)); + }; } -export default overSome +export default overSome; diff --git a/pad.js b/src/pad.ts similarity index 59% rename from pad.js rename to src/pad.ts index 3cfd9131b..b2ad485d7 100644 --- a/pad.js +++ b/src/pad.ts @@ -1,5 +1,5 @@ -import createPadding from './.internal/createPadding.js' -import stringSize from './.internal/stringSize.js' +import createPadding from './.internal/createPadding.js'; +import stringSize from './.internal/stringSize.js'; /** * Pads `string` on the left and right sides if it's shorter than `length`. @@ -23,16 +23,12 @@ import stringSize from './.internal/stringSize.js' * // => 'abc' */ function pad(string, length, chars) { - const strLength = length ? stringSize(string) : 0 - if (!length || strLength >= length) { - return (string || '') - } - const mid = (length - strLength) / 2 - return ( - createPadding(Math.floor(mid), chars) + - string + - createPadding(Math.ceil(mid), chars) - ) + const strLength = length ? stringSize(string) : 0; + if (!length || strLength >= length) { + return string || ''; + } + const mid = (length - strLength) / 2; + return createPadding(Math.floor(mid), chars) + string + createPadding(Math.ceil(mid), chars); } -export default pad +export default pad; diff --git a/padEnd.js b/src/padEnd.ts similarity index 64% rename from padEnd.js rename to src/padEnd.ts index 0fe4ab188..fdbce6925 100644 --- a/padEnd.js +++ b/src/padEnd.ts @@ -1,5 +1,5 @@ -import createPadding from './.internal/createPadding.js' -import stringSize from './.internal/stringSize.js' +import createPadding from './.internal/createPadding.js'; +import stringSize from './.internal/stringSize.js'; /** * Pads `string` on the right side if it's shorter than `length`. Padding @@ -23,10 +23,10 @@ import stringSize from './.internal/stringSize.js' * // => 'abc' */ function padEnd(string, length, chars) { - const strLength = length ? stringSize(string) : 0 - return (length && strLength < length) - ? (string + createPadding(length - strLength, chars)) - : (string || '') + const strLength = length ? stringSize(string) : 0; + return length && strLength < length + ? string + createPadding(length - strLength, chars) + : string || ''; } -export default padEnd +export default padEnd; diff --git a/padStart.js b/src/padStart.ts similarity index 64% rename from padStart.js rename to src/padStart.ts index 025708384..fd45ce1e7 100644 --- a/padStart.js +++ b/src/padStart.ts @@ -1,5 +1,5 @@ -import createPadding from './.internal/createPadding.js' -import stringSize from './.internal/stringSize.js' +import createPadding from './.internal/createPadding.js'; +import stringSize from './.internal/stringSize.js'; /** * Pads `string` on the left side if it's shorter than `length`. Padding @@ -23,10 +23,10 @@ import stringSize from './.internal/stringSize.js' * // => 'abc' */ function padStart(string, length, chars) { - const strLength = length ? stringSize(string) : 0 - return (length && strLength < length) - ? (createPadding(length - strLength, chars) + string) - : (string || '') + const strLength = length ? stringSize(string) : 0; + return length && strLength < length + ? createPadding(length - strLength, chars) + string + : string || ''; } -export default padStart +export default padStart; diff --git a/parseInt.js b/src/parseInt.ts similarity index 71% rename from parseInt.js rename to src/parseInt.ts index b8975ccb5..2467e1f54 100644 --- a/parseInt.js +++ b/src/parseInt.ts @@ -1,10 +1,10 @@ -import root from './.internal/root.js' +import root from './.internal/root.js'; /** Used to match leading and trailing whitespace. */ -const reTrimStart = /^\s+/ +const reTrimStart = /^\s+/; /* Built-in method references for those with the same name as other `lodash` methods. */ -const nativeParseInt = root.parseInt +const nativeParseInt = root.parseInt; /** * Converts `string` to an integer of the specified radix. If `radix` is @@ -25,12 +25,12 @@ const nativeParseInt = root.parseInt * // => 8 */ function parseInt(string, radix) { - if (radix == null) { - radix = 0 - } else if (radix) { - radix = +radix - } - return nativeParseInt(`${string}`.replace(reTrimStart, ''), radix || 0) + if (radix == null) { + radix = 0; + } else if (radix) { + radix = +radix; + } + return nativeParseInt(`${string}`.replace(reTrimStart, ''), radix || 0); } -export default parseInt +export default parseInt; diff --git a/partition.js b/src/partition.ts similarity index 80% rename from partition.js rename to src/partition.ts index f7f937615..24989e16e 100644 --- a/partition.js +++ b/src/partition.ts @@ -1,4 +1,4 @@ -import reduce from './reduce.js' +import reduce from './reduce.js'; /** * Creates an array of elements split into two groups, the first of which @@ -24,9 +24,11 @@ import reduce from './reduce.js' * // => objects for [['fred'], ['barney', 'pebbles']] */ function partition(collection, predicate) { - return reduce(collection, (result, value, key) => ( - result[predicate(value) ? 0 : 1].push(value), result - ), [[], []]) + return reduce( + collection, + (result, value, key) => (result[predicate(value) ? 0 : 1].push(value), result), + [[], []], + ); } -export default partition +export default partition; diff --git a/pick.js b/src/pick.ts similarity index 77% rename from pick.js rename to src/pick.ts index 8878cb013..b9ab9a7d1 100644 --- a/pick.js +++ b/src/pick.ts @@ -1,4 +1,4 @@ -import basePick from './.internal/basePick.js' +import basePick from './.internal/basePick.js'; /** * Creates an object composed of the picked `object` properties. @@ -16,7 +16,7 @@ import basePick from './.internal/basePick.js' * // => { 'a': 1, 'c': 3 } */ function pick(object, ...paths) { - return object == null ? {} : basePick(object, paths) + return object == null ? {} : basePick(object, paths); } -export default pick +export default pick; diff --git a/pickBy.js b/src/pickBy.ts similarity index 59% rename from pickBy.js rename to src/pickBy.ts index 2b8b4dbdf..aaca9ea6f 100644 --- a/pickBy.js +++ b/src/pickBy.ts @@ -1,6 +1,6 @@ -import map from './map.js' -import basePickBy from './.internal/basePickBy.js' -import getAllKeysIn from './.internal/getAllKeysIn.js' +import map from './map.js'; +import basePickBy from './.internal/basePickBy.js'; +import getAllKeysIn from './.internal/getAllKeysIn.js'; /** * Creates an object composed of the `object` properties `predicate` returns @@ -19,11 +19,11 @@ import getAllKeysIn from './.internal/getAllKeysIn.js' * // => { 'a': 1, 'c': 3 } */ function pickBy(object, predicate) { - if (object == null) { - return {} - } - const props = map(getAllKeysIn(object), (prop) => [prop]) - return basePickBy(object, props, (value, path) => predicate(value, path[0])) + if (object == null) { + return {}; + } + const props = map(getAllKeysIn(object), (prop) => [prop]); + return basePickBy(object, props, (value, path) => predicate(value, path[0])); } -export default pickBy +export default pickBy; diff --git a/property.js b/src/property.ts similarity index 61% rename from property.js rename to src/property.ts index 20520c32a..3d9a99e60 100644 --- a/property.js +++ b/src/property.ts @@ -1,7 +1,7 @@ -import baseProperty from './.internal/baseProperty.js' -import basePropertyDeep from './.internal/basePropertyDeep.js' -import isKey from './.internal/isKey.js' -import toKey from './.internal/toKey.js' +import baseProperty from './.internal/baseProperty.js'; +import basePropertyDeep from './.internal/basePropertyDeep.js'; +import isKey from './.internal/isKey.js'; +import toKey from './.internal/toKey.js'; /** * Creates a function that returns the value at `path` of a given object. @@ -24,7 +24,7 @@ import toKey from './.internal/toKey.js' * // => [1, 2] */ function property(path) { - return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path) + return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path); } -export default property +export default property; diff --git a/propertyOf.js b/src/propertyOf.ts similarity index 78% rename from propertyOf.js rename to src/propertyOf.ts index ed6daac0b..990b09a75 100644 --- a/propertyOf.js +++ b/src/propertyOf.ts @@ -1,4 +1,4 @@ -import baseGet from './.internal/baseGet.js' +import baseGet from './.internal/baseGet.js'; /** * The opposite of `property`s method creates a function that returns @@ -20,7 +20,7 @@ import baseGet from './.internal/baseGet.js' * // => [2, 0] */ function propertyOf(object) { - return (path) => object == null ? undefined : baseGet(object, path) + return (path) => (object == null ? undefined : baseGet(object, path)); } -export default propertyOf +export default propertyOf; diff --git a/pull.js b/src/pull.ts similarity index 88% rename from pull.js rename to src/pull.ts index 8c4c3d7d5..3950734c0 100644 --- a/pull.js +++ b/src/pull.ts @@ -1,4 +1,4 @@ -import pullAll from './pullAll.js' +import pullAll from './pullAll.js'; /** * Removes all given values from `array` using @@ -23,7 +23,7 @@ import pullAll from './pullAll.js' * // => ['b', 'b'] */ function pull(array, ...values) { - return pullAll(array, values) + return pullAll(array, values); } -export default pull +export default pull; diff --git a/pullAll.js b/src/pullAll.ts similarity index 72% rename from pullAll.js rename to src/pullAll.ts index 1f320204b..2fe42f41b 100644 --- a/pullAll.js +++ b/src/pullAll.ts @@ -1,4 +1,4 @@ -import basePullAll from './.internal/basePullAll.js' +import basePullAll from './.internal/basePullAll.js'; /** * This method is like `pull` except that it accepts an array of values to remove. @@ -20,9 +20,9 @@ import basePullAll from './.internal/basePullAll.js' * // => ['b', 'b'] */ function pullAll(array, values) { - return (array != null && array.length && values != null && values.length) - ? basePullAll(array, values) - : array + return array != null && array.length && values != null && values.length + ? basePullAll(array, values) + : array; } -export default pullAll +export default pullAll; diff --git a/pullAllBy.js b/src/pullAllBy.ts similarity index 79% rename from pullAllBy.js rename to src/pullAllBy.ts index 863628d73..5d4a2beaa 100644 --- a/pullAllBy.js +++ b/src/pullAllBy.ts @@ -1,4 +1,4 @@ -import basePullAll from './.internal/basePullAll.js' +import basePullAll from './.internal/basePullAll.js'; /** * This method is like `pullAll` except that it accepts `iteratee` which is @@ -23,9 +23,9 @@ import basePullAll from './.internal/basePullAll.js' * // => [{ 'x': 2 }] */ function pullAllBy(array, values, iteratee) { - return (array != null && array.length && values != null && values.length) - ? basePullAll(array, values, iteratee) - : array + return array != null && array.length && values != null && values.length + ? basePullAll(array, values, iteratee) + : array; } -export default pullAllBy +export default pullAllBy; diff --git a/pullAllWith.js b/src/pullAllWith.ts similarity index 78% rename from pullAllWith.js rename to src/pullAllWith.ts index bd77c5849..69546ed20 100644 --- a/pullAllWith.js +++ b/src/pullAllWith.ts @@ -1,4 +1,4 @@ -import basePullAll from './.internal/basePullAll.js' +import basePullAll from './.internal/basePullAll.js'; /** * This method is like `pullAll` except that it accepts `comparator` which @@ -23,9 +23,9 @@ import basePullAll from './.internal/basePullAll.js' * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] */ function pullAllWith(array, values, comparator) { - return (array != null && array.length && values != null && values.length) - ? basePullAll(array, values, undefined, comparator) - : array + return array != null && array.length && values != null && values.length + ? basePullAll(array, values, undefined, comparator) + : array; } -export default pullAllWith +export default pullAllWith; diff --git a/pullAt.js b/src/pullAt.ts similarity index 57% rename from pullAt.js rename to src/pullAt.ts index 86a22707e..17e47dc91 100644 --- a/pullAt.js +++ b/src/pullAt.ts @@ -1,8 +1,8 @@ -import map from './map.js' -import baseAt from './.internal/baseAt.js' -import basePullAt from './.internal/basePullAt.js' -import compareAscending from './.internal/compareAscending.js' -import isIndex from './.internal/isIndex.js' +import map from './map.js'; +import baseAt from './.internal/baseAt.js'; +import basePullAt from './.internal/basePullAt.js'; +import compareAscending from './.internal/compareAscending.js'; +import isIndex from './.internal/isIndex.js'; /** * Removes elements from `array` corresponding to `indexes` and returns an @@ -28,11 +28,14 @@ import isIndex from './.internal/isIndex.js' * // => ['b', 'd'] */ function pullAt(array, ...indexes) { - const length = array == null ? 0 : array.length - const result = baseAt(array, indexes) + const length = array == null ? 0 : array.length; + const result = baseAt(array, indexes); - basePullAt(array, map(indexes, (index) => isIndex(index, length) ? +index : index).sort(compareAscending)) - return result + basePullAt( + array, + map(indexes, (index) => (isIndex(index, length) ? +index : index)).sort(compareAscending), + ); + return result; } -export default pullAt +export default pullAt; diff --git a/random.js b/src/random.ts similarity index 52% rename from random.js rename to src/random.ts index 7f2acc655..182b0c8f4 100644 --- a/random.js +++ b/src/random.ts @@ -1,7 +1,7 @@ -import toFinite from './toFinite.js' +import toFinite from './toFinite.js'; /** Built-in method references without a dependency on `root`. */ -const freeParseFloat = parseFloat +const freeParseFloat = parseFloat; /** * Produces a random number between the inclusive `lower` and `upper` bounds. @@ -34,40 +34,38 @@ const freeParseFloat = parseFloat * // => a floating-point number between 1.2 and 5.2 */ function random(lower, upper, floating) { - if (floating === undefined) { - if (typeof upper === 'boolean') { - floating = upper - upper = undefined + if (floating === undefined) { + if (typeof upper === 'boolean') { + floating = upper; + upper = undefined; + } else if (typeof lower === 'boolean') { + floating = lower; + lower = undefined; + } } - else if (typeof lower === 'boolean') { - floating = lower - lower = undefined - } - } - if (lower === undefined && upper === undefined) { - lower = 0 - upper = 1 - } - else { - lower = toFinite(lower) - if (upper === undefined) { - upper = lower - lower = 0 + if (lower === undefined && upper === undefined) { + lower = 0; + upper = 1; } else { - upper = toFinite(upper) + lower = toFinite(lower); + if (upper === undefined) { + upper = lower; + lower = 0; + } else { + upper = toFinite(upper); + } } - } - if (lower > upper) { - const temp = lower - lower = upper - upper = temp - } - if (floating || lower % 1 || upper % 1) { - const rand = Math.random() - const randLength = `${rand}`.length - 1 - return Math.min(lower + (rand * (upper - lower + freeParseFloat(`1e-${randLength}`))), upper) - } - return lower + Math.floor(Math.random() * (upper - lower + 1)) + if (lower > upper) { + const temp = lower; + lower = upper; + upper = temp; + } + if (floating || lower % 1 || upper % 1) { + const rand = Math.random(); + const randLength = `${rand}`.length - 1; + return Math.min(lower + rand * (upper - lower + freeParseFloat(`1e-${randLength}`)), upper); + } + return lower + Math.floor(Math.random() * (upper - lower + 1)); } -export default random +export default random; diff --git a/range.js b/src/range.ts similarity index 90% rename from range.js rename to src/range.ts index 8925c3d63..ebefffd02 100644 --- a/range.js +++ b/src/range.ts @@ -1,4 +1,4 @@ -import createRange from './.internal/createRange.js' +import createRange from './.internal/createRange.js'; /** * Creates an array of numbers (positive and/or negative) progressing from @@ -39,6 +39,6 @@ import createRange from './.internal/createRange.js' * range(0) * // => [] */ -const range = createRange() +const range = createRange(); -export default range +export default range; diff --git a/rangeRight.js b/src/rangeRight.ts similarity index 85% rename from rangeRight.js rename to src/rangeRight.ts index 139f14c43..8c3af926f 100644 --- a/rangeRight.js +++ b/src/rangeRight.ts @@ -1,4 +1,4 @@ -import createRange from './.internal/createRange.js' +import createRange from './.internal/createRange.js'; /** * This method is like `range` except that it populates values in @@ -34,6 +34,6 @@ import createRange from './.internal/createRange.js' * rangeRight(0) * // => [] */ -const rangeRight = createRange(true) +const rangeRight = createRange(true); -export default rangeRight +export default rangeRight; diff --git a/reduce.js b/src/reduce.ts similarity index 78% rename from reduce.js rename to src/reduce.ts index 0ad5dfe86..e8540b79f 100644 --- a/reduce.js +++ b/src/reduce.ts @@ -1,6 +1,6 @@ -import arrayReduce from './.internal/arrayReduce.js' -import baseEach from './.internal/baseEach.js' -import baseReduce from './.internal/baseReduce.js' +import arrayReduce from './.internal/arrayReduce.js'; +import baseEach from './.internal/baseEach.js'; +import baseReduce from './.internal/baseReduce.js'; /** * Reduces `collection` to a value which is the accumulated result of running @@ -36,9 +36,9 @@ import baseReduce from './.internal/baseReduce.js' * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) */ function reduce(collection, iteratee, accumulator) { - const func = Array.isArray(collection) ? arrayReduce : baseReduce - const initAccum = arguments.length < 3 - return func(collection, iteratee, accumulator, initAccum, baseEach) + const func = Array.isArray(collection) ? arrayReduce : baseReduce; + const initAccum = arguments.length < 3; + return func(collection, iteratee, accumulator, initAccum, baseEach); } -export default reduce +export default reduce; diff --git a/reduceRight.js b/src/reduceRight.ts similarity index 61% rename from reduceRight.js rename to src/reduceRight.ts index 810c96dae..e812f67eb 100644 --- a/reduceRight.js +++ b/src/reduceRight.ts @@ -1,6 +1,6 @@ -import arrayReduceRight from './.internal/arrayReduceRight.js' -import baseEachRight from './.internal/baseEachRight.js' -import baseReduce from './.internal/baseReduce.js' +import arrayReduceRight from './.internal/arrayReduceRight.js'; +import baseEachRight from './.internal/baseEachRight.js'; +import baseReduce from './.internal/baseReduce.js'; /** * This method is like `reduce` except that it iterates over elements of @@ -21,9 +21,9 @@ import baseReduce from './.internal/baseReduce.js' * // => [4, 5, 2, 3, 0, 1] */ function reduceRight(collection, iteratee, accumulator) { - const func = Array.isArray(collection) ? arrayReduceRight : baseReduce - const initAccum = arguments.length < 3 - return func(collection, iteratee, accumulator, initAccum, baseEachRight) + const func = Array.isArray(collection) ? arrayReduceRight : baseReduce; + const initAccum = arguments.length < 3; + return func(collection, iteratee, accumulator, initAccum, baseEachRight); } -export default reduceRight +export default reduceRight; diff --git a/reject.js b/src/reject.ts similarity index 72% rename from reject.js rename to src/reject.ts index 726d975ff..3b78a7142 100644 --- a/reject.js +++ b/src/reject.ts @@ -1,6 +1,6 @@ -import filter from './filter.js' -import filterObject from './filterObject.js' -import negate from './negate.js' +import filter from './filter.js'; +import filterObject from './filterObject.js'; +import negate from './negate.js'; /** * The opposite of `filter` this method returns the elements of `collection` @@ -23,8 +23,8 @@ import negate from './negate.js' * // => objects for ['fred'] */ function reject(collection, predicate) { - const func = Array.isArray(collection) ? filter : filterObject - return func(collection, negate(predicate)) + const func = Array.isArray(collection) ? filter : filterObject; + return func(collection, negate(predicate)); } -export default reject +export default reject; diff --git a/remove.js b/src/remove.ts similarity index 63% rename from remove.js rename to src/remove.ts index e09cd9ef2..5dcffb94f 100644 --- a/remove.js +++ b/src/remove.ts @@ -1,4 +1,4 @@ -import basePullAt from './.internal/basePullAt.js' +import basePullAt from './.internal/basePullAt.js'; /** * Removes all elements from `array` that `predicate` returns truthy for @@ -26,23 +26,23 @@ import basePullAt from './.internal/basePullAt.js' * // => [2, 4] */ function remove(array, predicate) { - const result = [] - if (!(array != null && array.length)) { - return result - } - let index = -1 - const indexes = [] - const { length } = array - - while (++index < length) { - const value = array[index] - if (predicate(value, index, array)) { - result.push(value) - indexes.push(index) + const result = []; + if (!(array != null && array.length)) { + return result; } - } - basePullAt(array, indexes) - return result + let index = -1; + const indexes = []; + const { length } = array; + + while (++index < length) { + const value = array[index]; + if (predicate(value, index, array)) { + result.push(value); + indexes.push(index); + } + } + basePullAt(array, indexes); + return result; } -export default remove +export default remove; diff --git a/src/repeat.ts b/src/repeat.ts new file mode 100644 index 000000000..fb5844014 --- /dev/null +++ b/src/repeat.ts @@ -0,0 +1,40 @@ +/** + * Repeats the given string `n` times. + * + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to repeat. + * @param {number} [n=1] 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) { + let result = ''; + if (!string || n < 1 || n > Number.MAX_SAFE_INTEGER) { + 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 = Math.floor(n / 2); + if (n) { + string += string; + } + } while (n); + + return result; +} + +export default repeat; diff --git a/replace.js b/src/replace.ts similarity index 81% rename from replace.js rename to src/replace.ts index d53d0fdb6..c2d0b49c2 100644 --- a/replace.js +++ b/src/replace.ts @@ -17,8 +17,8 @@ * // => 'Hi Barney' */ function replace(...args) { - const string = `${args[0]}` - return args.length < 3 ? string : string.replace(args[1], args[2]) + const string = `${args[0]}`; + return args.length < 3 ? string : string.replace(args[1], args[2]); } -export default replace +export default replace; diff --git a/result.js b/src/result.ts similarity index 56% rename from result.js rename to src/result.ts index e12178009..edf4f8c4f 100644 --- a/result.js +++ b/src/result.ts @@ -1,5 +1,5 @@ -import castPath from './.internal/castPath.js' -import toKey from './.internal/toKey.js' +import castPath from './.internal/castPath.js'; +import toKey from './.internal/toKey.js'; /** * This method is like `get` except that if the resolved value is a @@ -29,25 +29,25 @@ import toKey from './.internal/toKey.js' * // => 'default' */ function result(object, path, defaultValue) { - path = castPath(path, object) + path = castPath(path, object); - let index = -1 - let length = path.length + let index = -1; + let length = path.length; - // Ensure the loop is entered when path is empty. - if (!length) { - length = 1 - object = undefined - } - while (++index < length) { - let value = object == null ? undefined : object[toKey(path[index])] - if (value === undefined) { - index = length - value = defaultValue + // Ensure the loop is entered when path is empty. + if (!length) { + length = 1; + object = undefined; } - object = typeof value === 'function' ? value.call(object) : value - } - return object + while (++index < length) { + let value = object == null ? undefined : object[toKey(path[index])]; + if (value === undefined) { + index = length; + value = defaultValue; + } + object = typeof value === 'function' ? value.call(object) : value; + } + return object; } -export default result +export default result; diff --git a/round.js b/src/round.ts similarity index 76% rename from round.js rename to src/round.ts index b8be05621..b3e3f3322 100644 --- a/round.js +++ b/src/round.ts @@ -1,4 +1,4 @@ -import createRound from './.internal/createRound.js' +import createRound from './.internal/createRound.js'; /** * Computes `number` rounded to `precision`. @@ -19,6 +19,6 @@ import createRound from './.internal/createRound.js' * round(4060, -2) * // => 4100 */ -const round = createRound('round') +const round = createRound('round'); -export default round +export default round; diff --git a/sample.js b/src/sample.ts similarity index 62% rename from sample.js rename to src/sample.ts index 60e2d8921..268cd4ebd 100644 --- a/sample.js +++ b/src/sample.ts @@ -11,8 +11,8 @@ * // => 2 */ function sample(array) { - const length = array == null ? 0 : array.length - return length ? array[Math.floor(Math.random() * length)] : undefined + const length = array == null ? 0 : array.length; + return length ? array[Math.floor(Math.random() * length)] : undefined; } -export default sample +export default sample; diff --git a/src/sampleSize.ts b/src/sampleSize.ts new file mode 100644 index 000000000..2ea7ef556 --- /dev/null +++ b/src/sampleSize.ts @@ -0,0 +1,40 @@ +import copyArray from './.internal/copyArray.js'; +import slice from './slice.js'; + +/** + * Gets `n` random elements at unique keys from `array` up to the + * size of `array`. + * + * @since 4.0.0 + * @category Array + * @param {Array} array The array to sample. + * @param {number} [n=1] The number of elements to sample. + * @returns {Array} Returns the random elements. + * @example + * + * sampleSize([1, 2, 3], 2) + * // => [3, 1] + * + * sampleSize([1, 2, 3], 4) + * // => [2, 3, 1] + */ +function sampleSize(array, n) { + n = n == null ? 1 : n; + const length = array == null ? 0 : array.length; + if (!length || n < 1) { + return []; + } + n = n > length ? length : n; + let index = -1; + const lastIndex = length - 1; + const result = copyArray(array); + while (++index < n) { + const rand = index + Math.floor(Math.random() * (lastIndex - index + 1)); + const value = result[rand]; + result[rand] = result[index]; + result[index] = value; + } + return slice(result, 0, n); +} + +export default sampleSize; diff --git a/set.js b/src/set.ts similarity index 86% rename from set.js rename to src/set.ts index 3004ec5b9..1a3a75a91 100644 --- a/set.js +++ b/src/set.ts @@ -1,4 +1,4 @@ -import baseSet from './.internal/baseSet.js' +import baseSet from './.internal/baseSet.js'; /** * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, @@ -28,7 +28,7 @@ import baseSet from './.internal/baseSet.js' * // => 5 */ function set(object, path, value) { - return object == null ? object : baseSet(object, path, value) + return object == null ? object : baseSet(object, path, value); } -export default set +export default set; diff --git a/setWith.js b/src/setWith.ts similarity index 78% rename from setWith.js rename to src/setWith.ts index b070940ca..a7e55d714 100644 --- a/setWith.js +++ b/src/setWith.ts @@ -1,4 +1,4 @@ -import baseSet from './.internal/baseSet.js' +import baseSet from './.internal/baseSet.js'; /** * This method is like `set` except that it accepts `customizer` which is @@ -23,8 +23,8 @@ import baseSet from './.internal/baseSet.js' * // => { '0': { '1': 'a' } } */ function setWith(object, path, value, customizer) { - customizer = typeof customizer === 'function' ? customizer : undefined - return object == null ? object : baseSet(object, path, value, customizer) + customizer = typeof customizer === 'function' ? customizer : undefined; + return object == null ? object : baseSet(object, path, value, customizer); } -export default setWith +export default setWith; diff --git a/src/shuffle.ts b/src/shuffle.ts new file mode 100644 index 000000000..b378a7da2 --- /dev/null +++ b/src/shuffle.ts @@ -0,0 +1,33 @@ +import copyArray from './.internal/copyArray.js'; + +/** + * Creates an array of shuffled values, using a version of the + * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). + * + * @since 0.1.0 + * @category Array + * @param {Array} array The array to shuffle. + * @returns {Array} Returns the new shuffled array. + * @example + * + * shuffle([1, 2, 3, 4]) + * // => [4, 1, 3, 2] + */ +function shuffle(array) { + const length = array == null ? 0 : array.length; + if (!length) { + return []; + } + let index = -1; + const lastIndex = length - 1; + const result = copyArray(array); + while (++index < length) { + const rand = index + Math.floor(Math.random() * (lastIndex - index + 1)); + const value = result[rand]; + result[rand] = result[index]; + result[index] = value; + } + return result; +} + +export default shuffle; diff --git a/src/size.ts b/src/size.ts new file mode 100644 index 000000000..13464dc1a --- /dev/null +++ b/src/size.ts @@ -0,0 +1,43 @@ +import getTag from './.internal/getTag.js'; +import isArrayLike from './isArrayLike.js'; +import isString from './isString.js'; +import stringSize from './.internal/stringSize.js'; + +/** `Object#toString` result references. */ +const mapTag = '[object Map]'; +const setTag = '[object Set]'; + +/** + * Gets the size of `collection` by returning its length for array-like + * values or the number of own enumerable string keyed properties for objects. + * + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * size([1, 2, 3]) + * // => 3 + * + * size({ 'a': 1, 'b': 2 }) + * // => 2 + * + * size('pebbles') + * // => 7 + */ +function size(collection) { + if (collection == null) { + return 0; + } + if (isArrayLike(collection)) { + return isString(collection) ? stringSize(collection) : collection.length; + } + const tag = getTag(collection); + if (tag == mapTag || tag == setTag) { + return collection.size; + } + return Object.keys(collection).length; +} + +export default size; diff --git a/slice.js b/src/slice.ts similarity index 53% rename from slice.js rename to src/slice.ts index 9c24d4dc1..fa89ed900 100644 --- a/slice.js +++ b/src/slice.ts @@ -19,29 +19,29 @@ * // => [3, 4] */ function slice(array, start, end) { - let length = array == null ? 0 : array.length - if (!length) { - return [] - } - start = start == null ? 0 : start - end = end === undefined ? length : end + let length = array == null ? 0 : array.length; + if (!length) { + return []; + } + start = start == null ? 0 : start; + end = end === undefined ? length : end; - if (start < 0) { - start = -start > length ? 0 : (length + start) - } - end = end > length ? length : end - if (end < 0) { - end += length - } - length = start > end ? 0 : ((end - start) >>> 0) - start >>>= 0 + if (start < 0) { + start = -start > length ? 0 : length + start; + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : (end - start) >>> 0; + start >>>= 0; - let index = -1 - const result = new Array(length) - while (++index < length) { - result[index] = array[index + start] - } - return result + let index = -1; + const result = new Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; } -export default slice +export default slice; diff --git a/snakeCase.js b/src/snakeCase.ts similarity index 63% rename from snakeCase.js rename to src/snakeCase.ts index 8ddde6e41..8fb8988b5 100644 --- a/snakeCase.js +++ b/src/snakeCase.ts @@ -1,5 +1,5 @@ -import words from './words.js' -import toString from './toString.js' +import words from './words.js'; +import toString from './toString.js'; /** * Converts `string` to @@ -24,10 +24,10 @@ import toString from './toString.js' * snakeCase('foo2bar') * // => 'foo_2_bar' */ -const snakeCase = (string) => ( - words(toString(string).replace(/['\u2019]/g, '')).reduce((result, word, index) => ( - result + (index ? '_' : '') + word.toLowerCase() - ), '') -) +const snakeCase = (string) => + words(toString(string).replace(/['\u2019]/g, '')).reduce( + (result, word, index) => result + (index ? '_' : '') + word.toLowerCase(), + '', + ); -export default snakeCase +export default snakeCase; diff --git a/some.js b/src/some.ts similarity index 71% rename from some.js rename to src/some.ts index 6f8eebcad..94f1e632e 100644 --- a/some.js +++ b/src/some.ts @@ -15,15 +15,15 @@ * // => true */ function some(array, predicate) { - let index = -1 - const length = array == null ? 0 : array.length + let index = -1; + const length = array == null ? 0 : array.length; - while (++index < length) { - if (predicate(array[index], index, array)) { - return true + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } } - } - return false + return false; } -export default some +export default some; diff --git a/someValue.js b/src/someValue.ts similarity index 72% rename from someValue.js rename to src/someValue.ts index a85f0028a..7dd81b62b 100644 --- a/someValue.js +++ b/src/someValue.ts @@ -15,15 +15,15 @@ * // => true */ function someValues(object, predicate) { - object = Object(object) - const props = Object.keys(object) + object = Object(object); + const props = Object.keys(object); - for (const key of props) { - if (predicate(object[key], key, object)) { - return true + for (const key of props) { + if (predicate(object[key], key, object)) { + return true; + } } - } - return false + return false; } -export default someValues +export default someValues; diff --git a/sortedIndex.js b/src/sortedIndex.ts similarity index 78% rename from sortedIndex.js rename to src/sortedIndex.ts index fa84fe9b7..8b47c4667 100644 --- a/sortedIndex.js +++ b/src/sortedIndex.ts @@ -1,4 +1,4 @@ -import baseSortedIndex from './.internal/baseSortedIndex.js' +import baseSortedIndex from './.internal/baseSortedIndex.js'; /** * Uses a binary search to determine the lowest index at which `value` @@ -16,7 +16,7 @@ import baseSortedIndex from './.internal/baseSortedIndex.js' * // => 1 */ function sortedIndex(array, value) { - return baseSortedIndex(array, value) + return baseSortedIndex(array, value); } -export default sortedIndex +export default sortedIndex; diff --git a/sortedIndexBy.js b/src/sortedIndexBy.ts similarity index 89% rename from sortedIndexBy.js rename to src/sortedIndexBy.ts index 61c1c6fae..09ac15d49 100644 --- a/sortedIndexBy.js +++ b/src/sortedIndexBy.ts @@ -1,4 +1,4 @@ -import baseSortedIndexBy from './.internal/baseSortedIndexBy.js' +import baseSortedIndexBy from './.internal/baseSortedIndexBy.js'; /** * This method is like `sortedIndex` except that it accepts `iteratee` @@ -20,7 +20,7 @@ import baseSortedIndexBy from './.internal/baseSortedIndexBy.js' * // => 0 */ function sortedIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, iteratee) + return baseSortedIndexBy(array, value, iteratee); } -export default sortedIndexBy +export default sortedIndexBy; diff --git a/sortedIndexOf.js b/src/sortedIndexOf.ts similarity index 54% rename from sortedIndexOf.js rename to src/sortedIndexOf.ts index d30324091..8b9630122 100644 --- a/sortedIndexOf.js +++ b/src/sortedIndexOf.ts @@ -1,5 +1,5 @@ -import baseSortedIndex from './.internal/baseSortedIndex.js' -import eq from './eq.js' +import baseSortedIndex from './.internal/baseSortedIndex.js'; +import eq from './eq.js'; /** * This method is like `indexOf` except that it performs a binary @@ -16,14 +16,14 @@ import eq from './eq.js' * // => 1 */ function sortedIndexOf(array, value) { - const length = array == null ? 0 : array.length - if (length) { - const index = baseSortedIndex(array, value) - if (index < length && eq(array[index], value)) { - return index + const length = array == null ? 0 : array.length; + if (length) { + const index = baseSortedIndex(array, value); + if (index < length && eq(array[index], value)) { + return index; + } } - } - return -1 + return -1; } -export default sortedIndexOf +export default sortedIndexOf; diff --git a/sortedLastIndex.js b/src/sortedLastIndex.ts similarity index 78% rename from sortedLastIndex.js rename to src/sortedLastIndex.ts index aee639fca..addc8e0a2 100644 --- a/sortedLastIndex.js +++ b/src/sortedLastIndex.ts @@ -1,4 +1,4 @@ -import baseSortedIndex from './.internal/baseSortedIndex.js' +import baseSortedIndex from './.internal/baseSortedIndex.js'; /** * This method is like `sortedIndex` except that it returns the highest @@ -17,7 +17,7 @@ import baseSortedIndex from './.internal/baseSortedIndex.js' * // => 4 */ function sortedLastIndex(array, value) { - return baseSortedIndex(array, value, true) + return baseSortedIndex(array, value, true); } -export default sortedLastIndex +export default sortedLastIndex; diff --git a/sortedLastIndexBy.js b/src/sortedLastIndexBy.ts similarity index 88% rename from sortedLastIndexBy.js rename to src/sortedLastIndexBy.ts index a2a14dd06..e2d7260ec 100644 --- a/sortedLastIndexBy.js +++ b/src/sortedLastIndexBy.ts @@ -1,4 +1,4 @@ -import baseSortedIndexBy from './.internal/baseSortedIndexBy.js' +import baseSortedIndexBy from './.internal/baseSortedIndexBy.js'; /** * This method is like `sortedLastIndex` except that it accepts `iteratee` @@ -20,7 +20,7 @@ import baseSortedIndexBy from './.internal/baseSortedIndexBy.js' * // => 1 */ function sortedLastIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, iteratee, true) + return baseSortedIndexBy(array, value, iteratee, true); } -export default sortedLastIndexBy +export default sortedLastIndexBy; diff --git a/sortedLastIndexOf.js b/src/sortedLastIndexOf.ts similarity index 55% rename from sortedLastIndexOf.js rename to src/sortedLastIndexOf.ts index f4d4ea335..56d3e38b6 100644 --- a/sortedLastIndexOf.js +++ b/src/sortedLastIndexOf.ts @@ -1,5 +1,5 @@ -import baseSortedIndex from './.internal/baseSortedIndex.js' -import eq from './eq.js' +import baseSortedIndex from './.internal/baseSortedIndex.js'; +import eq from './eq.js'; /** * This method is like `lastIndexOf` except that it performs a binary @@ -16,14 +16,14 @@ import eq from './eq.js' * // => 3 */ function sortedLastIndexOf(array, value) { - const length = array == null ? 0 : array.length - if (length) { - const index = baseSortedIndex(array, value, true) - 1 - if (eq(array[index], value)) { - return index + const length = array == null ? 0 : array.length; + if (length) { + const index = baseSortedIndex(array, value, true) - 1; + if (eq(array[index], value)) { + return index; + } } - } - return -1 + return -1; } -export default sortedLastIndexOf +export default sortedLastIndexOf; diff --git a/sortedUniq.js b/src/sortedUniq.ts similarity index 71% rename from sortedUniq.js rename to src/sortedUniq.ts index 31d1e94bd..9b11abe9e 100644 --- a/sortedUniq.js +++ b/src/sortedUniq.ts @@ -1,4 +1,4 @@ -import baseSortedUniq from './.internal/baseSortedUniq.js' +import baseSortedUniq from './.internal/baseSortedUniq.js'; /** * This method is like `uniq` except that it only works @@ -16,9 +16,7 @@ import baseSortedUniq from './.internal/baseSortedUniq.js' * // => [1, 2] */ function sortedUniq(array) { - return (array != null && array.length) - ? baseSortedUniq(array) - : [] + return array != null && array.length ? baseSortedUniq(array) : []; } -export default sortedUniq +export default sortedUniq; diff --git a/sortedUniqBy.js b/src/sortedUniqBy.ts similarity index 71% rename from sortedUniqBy.js rename to src/sortedUniqBy.ts index 32ca129c8..e8ad62532 100644 --- a/sortedUniqBy.js +++ b/src/sortedUniqBy.ts @@ -1,4 +1,4 @@ -import baseSortedUniq from './.internal/baseSortedUniq.js' +import baseSortedUniq from './.internal/baseSortedUniq.js'; /** * This method is like `uniqBy` except that it's designed and optimized @@ -15,9 +15,7 @@ import baseSortedUniq from './.internal/baseSortedUniq.js' * // => [1.1, 2.3] */ function sortedUniqBy(array, iteratee) { - return (array != null && array.length) - ? baseSortedUniq(array, iteratee) - : [] + return array != null && array.length ? baseSortedUniq(array, iteratee) : []; } -export default sortedUniqBy +export default sortedUniqBy; diff --git a/src/split.ts b/src/split.ts new file mode 100644 index 000000000..4f0fad43d --- /dev/null +++ b/src/split.ts @@ -0,0 +1,39 @@ +import castSlice from './.internal/castSlice.js'; +import hasUnicode from './.internal/hasUnicode.js'; +import isRegExp from './isRegExp.js'; +import stringToArray from './.internal/stringToArray.js'; + +/** Used as references for the maximum length and index of an array. */ +const MAX_ARRAY_LENGTH = 4294967295; + +/** + * Splits `string` by `separator`. + * + * **Note:** This method is based on + * [`String#split`](https://mdn.io/String/split). + * + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to split. + * @param {RegExp|string} separator The separator pattern to split by. + * @param {number} [limit] The length to truncate results to. + * @returns {Array} Returns the string segments. + * @example + * + * split('a-b-c', '-', 2) + * // => ['a', 'b'] + */ +function split(string, separator, limit) { + limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; + if (!limit) { + return []; + } + if (string && (typeof separator === 'string' || (separator != null && !isRegExp(separator)))) { + if (!separator && hasUnicode(string)) { + return castSlice(stringToArray(string), 0, limit); + } + } + return string.split(separator, limit); +} + +export default split; diff --git a/startCase.js b/src/startCase.ts similarity index 63% rename from startCase.js rename to src/startCase.ts index 77190ff94..a5826ad64 100644 --- a/startCase.js +++ b/src/startCase.ts @@ -1,5 +1,5 @@ -import upperFirst from './upperFirst.js' -import words from './words.js' +import upperFirst from './upperFirst.js'; +import words from './words.js'; /** * Converts `string` to @@ -21,10 +21,10 @@ import words from './words.js' * startCase('__FOO_BAR__') * // => 'FOO BAR' */ -const startCase = (string) => ( - words(`${string}`.replace(/['\u2019]/g, '')).reduce((result, word, index) => ( - result + (index ? ' ' : '') + upperFirst(word) - ), '') -) +const startCase = (string) => + words(`${string}`.replace(/['\u2019]/g, '')).reduce( + (result, word, index) => result + (index ? ' ' : '') + upperFirst(word), + '', + ); -export default startCase +export default startCase; diff --git a/startsWith.js b/src/startsWith.ts similarity index 64% rename from startsWith.js rename to src/startsWith.ts index dfdbf551c..4bf245729 100644 --- a/startsWith.js +++ b/src/startsWith.ts @@ -21,16 +21,15 @@ * // => true */ function startsWith(string, target, position) { - const { length } = string - position = position == null ? 0 : position - if (position < 0) { - position = 0 - } - else if (position > length) { - position = length - } - target = `${target}` - return string.slice(position, position + target.length) == target + const { length } = string; + position = position == null ? 0 : position; + if (position < 0) { + position = 0; + } else if (position > length) { + position = length; + } + target = `${target}`; + return string.slice(position, position + target.length) == target; } -export default startsWith +export default startsWith; diff --git a/subtract.js b/src/subtract.ts similarity index 88% rename from subtract.js rename to src/subtract.ts index bf8ca6dce..e203066d0 100644 --- a/subtract.js +++ b/src/subtract.ts @@ -1,4 +1,4 @@ -import createMathOperation from './.internal/createMathOperation.js' +import createMathOperation from './.internal/createMathOperation.js'; /** * Subtract two numbers. @@ -13,6 +13,6 @@ import createMathOperation from './.internal/createMathOperation.js' * subtract(6, 4) * // => 2 */ -const subtract = createMathOperation((minuend, subtrahend) => minuend - subtrahend, 0) +const subtract = createMathOperation((minuend, subtrahend) => minuend - subtrahend, 0); -export default subtract +export default subtract; diff --git a/sum.js b/src/sum.ts similarity index 62% rename from sum.js rename to src/sum.ts index c9c0c277c..50237ea15 100644 --- a/sum.js +++ b/src/sum.ts @@ -1,4 +1,4 @@ -import baseSum from './.internal/baseSum.js' +import baseSum from './.internal/baseSum.js'; /** * Computes the sum of the values in `array`. @@ -13,9 +13,7 @@ import baseSum from './.internal/baseSum.js' * // => 20 */ function sum(array) { - return (array != null && array.length) - ? baseSum(array, (value) => value) - : 0 + return array != null && array.length ? baseSum(array, (value) => value) : 0; } -export default sum +export default sum; diff --git a/sumBy.js b/src/sumBy.ts similarity index 79% rename from sumBy.js rename to src/sumBy.ts index 5775bf595..723d6fca5 100644 --- a/sumBy.js +++ b/src/sumBy.ts @@ -1,4 +1,4 @@ -import baseSum from './.internal/baseSum.js' +import baseSum from './.internal/baseSum.js'; /** * This method is like `sum` except that it accepts `iteratee` which is @@ -18,9 +18,7 @@ import baseSum from './.internal/baseSum.js' * // => 20 */ function sumBy(array, iteratee) { - return (array != null && array.length) - ? baseSum(array, iteratee) - : 0 + return array != null && array.length ? baseSum(array, iteratee) : 0; } -export default sumBy +export default sumBy; diff --git a/tail.js b/src/tail.ts similarity index 60% rename from tail.js rename to src/tail.ts index ef837d408..fa8d28c9a 100644 --- a/tail.js +++ b/src/tail.ts @@ -11,12 +11,12 @@ * // => [2, 3] */ function tail(array) { - const length = array == null ? 0 : array.length - if (!length) { - return [] - } - const [, ...result] = array - return result + const length = array == null ? 0 : array.length; + if (!length) { + return []; + } + const [, ...result] = array; + return result; } -export default tail +export default tail; diff --git a/take.js b/src/take.ts similarity index 69% rename from take.js rename to src/take.ts index 890118b9b..e691671eb 100644 --- a/take.js +++ b/src/take.ts @@ -1,4 +1,4 @@ -import slice from './slice.js' +import slice from './slice.js'; /** * Creates a slice of `array` with `n` elements taken from the beginning. @@ -22,11 +22,11 @@ import slice from './slice.js' * take([1, 2, 3], 0) * // => [] */ -function take(array, n=1) { - if (!(array != null && array.length)) { - return [] - } - return slice(array, 0, n < 0 ? 0 : n) +function take(array, n = 1) { + if (!(array != null && array.length)) { + return []; + } + return slice(array, 0, n < 0 ? 0 : n); } -export default take +export default take; diff --git a/takeRight.js b/src/takeRight.ts similarity index 63% rename from takeRight.js rename to src/takeRight.ts index 3ad2a57a7..2768e9914 100644 --- a/takeRight.js +++ b/src/takeRight.ts @@ -1,4 +1,4 @@ -import slice from './slice.js' +import slice from './slice.js'; /** * Creates a slice of `array` with `n` elements taken from the end. @@ -22,13 +22,13 @@ import slice from './slice.js' * takeRight([1, 2, 3], 0) * // => [] */ -function takeRight(array, n=1) { - const length = array == null ? 0 : array.length - if (!length) { - return [] - } - n = length - n - return slice(array, n < 0 ? 0 : n, length) +function takeRight(array, n = 1) { + const length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = length - n; + return slice(array, n < 0 ? 0 : n, length); } -export default takeRight +export default takeRight; diff --git a/takeRightWhile.js b/src/takeRightWhile.ts similarity index 80% rename from takeRightWhile.js rename to src/takeRightWhile.ts index 01cccbe13..a1d9086d6 100644 --- a/takeRightWhile.js +++ b/src/takeRightWhile.ts @@ -1,4 +1,4 @@ -import baseWhile from './.internal/baseWhile.js' +import baseWhile from './.internal/baseWhile.js'; /** * Creates a slice of `array` with elements taken from the end. Elements are @@ -22,9 +22,7 @@ import baseWhile from './.internal/baseWhile.js' * // => objects for ['fred', 'pebbles'] */ function takeRightWhile(array, predicate) { - return (array != null && array.length) - ? baseWhile(array, predicate, false, true) - : [] + return array != null && array.length ? baseWhile(array, predicate, false, true) : []; } -export default takeRightWhile +export default takeRightWhile; diff --git a/takeWhile.js b/src/takeWhile.ts similarity index 81% rename from takeWhile.js rename to src/takeWhile.ts index ec24da5ed..3847e0af2 100644 --- a/takeWhile.js +++ b/src/takeWhile.ts @@ -1,4 +1,4 @@ -import baseWhile from './.internal/baseWhile.js' +import baseWhile from './.internal/baseWhile.js'; /** * Creates a slice of `array` with elements taken from the beginning. Elements @@ -22,9 +22,7 @@ import baseWhile from './.internal/baseWhile.js' * // => objects for ['barney', 'fred'] */ function takeWhile(array, predicate) { - return (array != null && array.length) - ? baseWhile(array, predicate) - : [] + return array != null && array.length ? baseWhile(array, predicate) : []; } -export default takeWhile +export default takeWhile; diff --git a/throttle.js b/src/throttle.ts similarity index 81% rename from throttle.js rename to src/throttle.ts index 6fa0ba8ca..c0f721f04 100644 --- a/throttle.js +++ b/src/throttle.ts @@ -1,5 +1,5 @@ -import debounce from './debounce.js' -import isObject from './isObject.js' +import debounce from './debounce.js'; +import isObject from './isObject.js'; /** * Creates a throttled function that only invokes `func` at most once per @@ -50,21 +50,21 @@ import isObject from './isObject.js' * jQuery(window).on('popstate', throttled.cancel) */ function throttle(func, wait, options) { - let leading = true - let trailing = true + let leading = true; + let trailing = true; - if (typeof func !== 'function') { - throw new TypeError('Expected a function') - } - if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading - trailing = 'trailing' in options ? !!options.trailing : trailing - } - return debounce(func, wait, { - leading, - trailing, - 'maxWait': wait - }) + if (typeof func !== 'function') { + throw new TypeError('Expected a function'); + } + if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + leading, + trailing, + maxWait: wait, + }); } -export default throttle +export default throttle; diff --git a/times.js b/src/times.ts similarity index 56% rename from times.js rename to src/times.ts index 47804627d..f779333cd 100644 --- a/times.js +++ b/src/times.ts @@ -1,8 +1,8 @@ /** Used as references for various `Number` constants. */ -const MAX_SAFE_INTEGER = 9007199254740991 +const MAX_SAFE_INTEGER = 9007199254740991; /** Used as references for the maximum length and index of an array. */ -const MAX_ARRAY_LENGTH = 4294967295 +const MAX_ARRAY_LENGTH = 4294967295; /** * Invokes the iteratee `n` times, returning an array of the results of @@ -22,21 +22,21 @@ const MAX_ARRAY_LENGTH = 4294967295 * // => [0, 0, 0, 0] */ function times(n, iteratee) { - if (n < 1 || n > MAX_SAFE_INTEGER) { - return [] - } - let index = -1 - const length = Math.min(n, MAX_ARRAY_LENGTH) - const result = new Array(length) - while (++index < length) { - result[index] = iteratee(index) - } - index = MAX_ARRAY_LENGTH - n -= MAX_ARRAY_LENGTH - while (++index < n) { - iteratee(index) - } - return result + if (n < 1 || n > MAX_SAFE_INTEGER) { + return []; + } + let index = -1; + const length = Math.min(n, MAX_ARRAY_LENGTH); + const result = new Array(length); + while (++index < length) { + result[index] = iteratee(index); + } + index = MAX_ARRAY_LENGTH; + n -= MAX_ARRAY_LENGTH; + while (++index < n) { + iteratee(index); + } + return result; } -export default times +export default times; diff --git a/src/toArray.ts b/src/toArray.ts new file mode 100644 index 000000000..af4f1c227 --- /dev/null +++ b/src/toArray.ts @@ -0,0 +1,55 @@ +import copyArray from './.internal/copyArray.js'; +import getTag from './.internal/getTag.js'; +import isArrayLike from './isArrayLike.js'; +import isString from './isString.js'; +import iteratorToArray from './.internal/iteratorToArray.js'; +import mapToArray from './.internal/mapToArray.js'; +import setToArray from './.internal/setToArray.js'; +import stringToArray from './.internal/stringToArray.js'; +import values from './values.js'; + +/** `Object#toString` result references. */ +const mapTag = '[object Map]'; +const setTag = '[object Set]'; + +/** Built-in value references. */ +const symIterator = Symbol.iterator; + +/** + * Converts `value` to an array. + * + * @since 0.1.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * toArray({ 'a': 1, 'b': 2 }) + * // => [1, 2] + * + * toArray('abc') + * // => ['a', 'b', 'c'] + * + * toArray(1) + * // => [] + * + * toArray(null) + * // => [] + */ +function toArray(value) { + if (!value) { + return []; + } + if (isArrayLike(value)) { + return isString(value) ? stringToArray(value) : copyArray(value); + } + if (symIterator && value[symIterator]) { + return iteratorToArray(value[symIterator]()); + } + const tag = getTag(value); + const func = tag == mapTag ? mapToArray : tag == setTag ? setToArray : values; + + return func(value); +} + +export default toArray; diff --git a/toFinite.js b/src/toFinite.ts similarity index 53% rename from toFinite.js rename to src/toFinite.ts index 7718142ea..7216c87fc 100644 --- a/toFinite.js +++ b/src/toFinite.ts @@ -1,8 +1,8 @@ -import toNumber from './toNumber.js' +import toNumber from './toNumber.js'; /** Used as references for various `Number` constants. */ -const INFINITY = 1 / 0 -const MAX_INTEGER = 1.7976931348623157e+308 +const INFINITY = 1 / 0; +const MAX_INTEGER = 1.7976931348623157e308; /** * Converts `value` to a finite number. @@ -26,15 +26,15 @@ const MAX_INTEGER = 1.7976931348623157e+308 * // => 3.2 */ function toFinite(value) { - if (!value) { - return value === 0 ? value : 0 - } - value = toNumber(value) - if (value === INFINITY || value === -INFINITY) { - const sign = (value < 0 ? -1 : 1) - return sign * MAX_INTEGER - } - return value === value ? value : 0 + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + const sign = value < 0 ? -1 : 1; + return sign * MAX_INTEGER; + } + return value === value ? value : 0; } -export default toFinite +export default toFinite; diff --git a/toInteger.js b/src/toInteger.ts similarity index 74% rename from toInteger.js rename to src/toInteger.ts index b09a8b982..c259ba18b 100644 --- a/toInteger.js +++ b/src/toInteger.ts @@ -1,4 +1,4 @@ -import toFinite from './toFinite.js' +import toFinite from './toFinite.js'; /** * Converts `value` to an integer. @@ -26,10 +26,10 @@ import toFinite from './toFinite.js' * // => 3 */ function toInteger(value) { - const result = toFinite(value) - const remainder = result % 1 + const result = toFinite(value); + const remainder = result % 1; - return remainder ? result - remainder : result + return remainder ? result - remainder : result; } -export default toInteger +export default toInteger; diff --git a/toLength.js b/src/toLength.ts similarity index 66% rename from toLength.js rename to src/toLength.ts index 4425c1075..a3b27c9fb 100644 --- a/toLength.js +++ b/src/toLength.ts @@ -1,7 +1,7 @@ -import toInteger from './toInteger.js' +import toInteger from './toInteger.js'; /** Used as references for the maximum length and index of an array. */ -const MAX_ARRAY_LENGTH = 4294967295 +const MAX_ARRAY_LENGTH = 4294967295; /** * Converts `value` to an integer suitable for use as the length of an @@ -29,17 +29,17 @@ const MAX_ARRAY_LENGTH = 4294967295 * // => 3 */ function toLength(value) { - if (!value) { - return 0 - } - value = toInteger(value) - if (value < 0) { - return 0 - } - if (value > MAX_ARRAY_LENGTH) { - return MAX_ARRAY_LENGTH - } - return value + if (!value) { + return 0; + } + value = toInteger(value); + if (value < 0) { + return 0; + } + if (value > MAX_ARRAY_LENGTH) { + return MAX_ARRAY_LENGTH; + } + return value; } -export default toLength +export default toLength; diff --git a/src/toNumber.ts b/src/toNumber.ts new file mode 100644 index 000000000..cc2f2ef33 --- /dev/null +++ b/src/toNumber.ts @@ -0,0 +1,67 @@ +import isObject from './isObject.js'; +import isSymbol from './isSymbol.js'; + +/** Used as references for various `Number` constants. */ +const NAN = 0 / 0; + +/** Used to match leading and trailing whitespace. */ +const reTrim = /^\s+|\s+$/g; + +/** Used to detect bad signed hexadecimal string values. */ +const reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + +/** Used to detect binary string values. */ +const reIsBinary = /^0b[01]+$/i; + +/** Used to detect octal string values. */ +const reIsOctal = /^0o[0-7]+$/i; + +/** Built-in method references without a dependency on `root`. */ +const freeParseInt = parseInt; + +/** + * Converts `value` to a number. + * + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @see isInteger, toInteger, isNumber + * @example + * + * toNumber(3.2) + * // => 3.2 + * + * toNumber(Number.MIN_VALUE) + * // => 5e-324 + * + * toNumber(Infinity) + * // => Infinity + * + * toNumber('3.2') + * // => 3.2 + */ +function toNumber(value) { + if (typeof value === 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + const other = typeof value.valueOf === 'function' ? value.valueOf() : value; + value = isObject(other) ? `${other}` : other; + } + if (typeof value !== 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + const isBinary = reIsBinary.test(value); + return isBinary || reIsOctal.test(value) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : reIsBadHex.test(value) + ? NAN + : +value; +} + +export default toNumber; diff --git a/src/toPath.ts b/src/toPath.ts new file mode 100644 index 000000000..c5a371ffe --- /dev/null +++ b/src/toPath.ts @@ -0,0 +1,29 @@ +import map from './map.js'; +import copyArray from './.internal/copyArray.js'; +import isSymbol from './isSymbol.js'; +import stringToPath from './.internal/stringToPath.js'; +import toKey from './.internal/toKey.js'; + +/** + * Converts `value` to a property path array. + * + * @since 4.0.0 + * @category Util + * @param {*} value The value to convert. + * @returns {Array} Returns the new property path array. + * @example + * + * toPath('a.b.c') + * // => ['a', 'b', 'c'] + * + * toPath('a[0].b.c') + * // => ['a', '0', 'b', 'c'] + */ +function toPath(value) { + if (Array.isArray(value)) { + return map(value, toKey); + } + return isSymbol(value) ? [value] : copyArray(stringToPath(value)); +} + +export default toPath; diff --git a/toPlainObject.js b/src/toPlainObject.ts similarity index 76% rename from toPlainObject.js rename to src/toPlainObject.ts index b19a251dc..46b903db0 100644 --- a/toPlainObject.js +++ b/src/toPlainObject.ts @@ -21,12 +21,12 @@ * // => { 'a': 1, 'b': 2, 'c': 3 } */ function toPlainObject(value) { - value = Object(value) - const result = {} - for (const key in value) { - result[key] = value[key] - } - return result + value = Object(value); + const result = {}; + for (const key in value) { + result[key] = value[key]; + } + return result; } -export default toPlainObject +export default toPlainObject; diff --git a/toSafeInteger.js b/src/toSafeInteger.ts similarity index 58% rename from toSafeInteger.js rename to src/toSafeInteger.ts index 2cf3ee94d..b3580694e 100644 --- a/toSafeInteger.js +++ b/src/toSafeInteger.ts @@ -1,7 +1,7 @@ -import toInteger from './toInteger.js' +import toInteger from './toInteger.js'; /** Used as references for various `Number` constants. */ -const MAX_SAFE_INTEGER = 9007199254740991 +const MAX_SAFE_INTEGER = 9007199254740991; /** * Converts `value` to a safe integer. A safe integer can be compared and @@ -26,17 +26,17 @@ const MAX_SAFE_INTEGER = 9007199254740991 * // => 3 */ function toSafeInteger(value) { - if (!value) { - return value === 0 ? value : 0 - } - value = toInteger(value) - if (value < -MAX_SAFE_INTEGER) { - return -MAX_SAFE_INTEGER - } - if (value > MAX_SAFE_INTEGER) { - return MAX_SAFE_INTEGER - } - return value + if (!value) { + return value === 0 ? value : 0; + } + value = toInteger(value); + if (value < -MAX_SAFE_INTEGER) { + return -MAX_SAFE_INTEGER; + } + if (value > MAX_SAFE_INTEGER) { + return MAX_SAFE_INTEGER; + } + return value; } -export default toSafeInteger +export default toSafeInteger; diff --git a/src/toString.ts b/src/toString.ts new file mode 100644 index 000000000..a729977de --- /dev/null +++ b/src/toString.ts @@ -0,0 +1,44 @@ +import isSymbol from './isSymbol.js'; + +/** Used as references for various `Number` constants. */ +const INFINITY = 1 / 0; + +/** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * toString(null) + * // => '' + * + * toString(-0) + * // => '-0' + * + * toString([1, 2, 3]) + * // => '1,2,3' + */ +function toString(value) { + if (value == null) { + return ''; + } + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value === 'string') { + return value; + } + if (Array.isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return `${value.map((other) => (other == null ? other : toString(other)))}`; + } + if (isSymbol(value)) { + return value.toString(); + } + const result = `${value}`; + return result == '0' && 1 / value == -INFINITY ? '-0' : result; +} + +export default toString; diff --git a/transform.js b/src/transform.ts similarity index 57% rename from transform.js rename to src/transform.ts index b421cb9be..83399e2d7 100644 --- a/transform.js +++ b/src/transform.ts @@ -1,8 +1,8 @@ -import arrayEach from './.internal/arrayEach.js' -import baseForOwn from './.internal/baseForOwn.js' -import isBuffer from './isBuffer.js' -import isObject from './isObject.js' -import isTypedArray from './isTypedArray.js' +import arrayEach from './.internal/arrayEach.js'; +import baseForOwn from './.internal/baseForOwn.js'; +import isBuffer from './isBuffer.js'; +import isObject from './isObject.js'; +import isTypedArray from './isTypedArray.js'; /** * An alternative to `reduce` this method transforms `object` to a new @@ -34,26 +34,24 @@ import isTypedArray from './isTypedArray.js' * // => { '1': ['a', 'c'], '2': ['b'] } */ function transform(object, iteratee, accumulator) { - const isArr = Array.isArray(object) - const isArrLike = isArr || isBuffer(object) || isTypedArray(object) + const isArr = Array.isArray(object); + const isArrLike = isArr || isBuffer(object) || isTypedArray(object); - if (accumulator == null) { - const Ctor = object && object.constructor - if (isArrLike) { - accumulator = isArr ? new Ctor : [] + if (accumulator == null) { + const Ctor = object && object.constructor; + if (isArrLike) { + accumulator = isArr ? new Ctor() : []; + } else if (isObject(object)) { + accumulator = + typeof Ctor === 'function' ? Object.create(Object.getPrototypeOf(object)) : {}; + } else { + accumulator = {}; + } } - else if (isObject(object)) { - accumulator = typeof Ctor === 'function' - ? Object.create(Object.getPrototypeOf(object)) - : {} - } - else { - accumulator = {} - } - } - (isArrLike ? arrayEach : baseForOwn)(object, (value, index, object) => - iteratee(accumulator, value, index, object)) - return accumulator + (isArrLike ? arrayEach : baseForOwn)(object, (value, index, object) => + iteratee(accumulator, value, index, object), + ); + return accumulator; } -export default transform +export default transform; diff --git a/src/trim.ts b/src/trim.ts new file mode 100644 index 000000000..4e1bc4a6c --- /dev/null +++ b/src/trim.ts @@ -0,0 +1,38 @@ +import castSlice from './.internal/castSlice.js'; +import charsEndIndex from './.internal/charsEndIndex.js'; +import charsStartIndex from './.internal/charsStartIndex.js'; +import stringToArray from './.internal/stringToArray.js'; + +/** + * Removes leading and trailing whitespace or specified characters from `string`. + * + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @returns {string} Returns the trimmed string. + * @see trimEnd, trimStart + * @example + * + * trim(' abc ') + * // => 'abc' + * + * trim('-_-abc-_-', '_-') + * // => 'abc' + */ +function trim(string, chars) { + if (string && chars === undefined) { + return string.trim(); + } + if (!string || !chars) { + return string || ''; + } + const strSymbols = stringToArray(string); + const chrSymbols = stringToArray(chars); + const start = charsStartIndex(strSymbols, chrSymbols); + const end = charsEndIndex(strSymbols, chrSymbols) + 1; + + return castSlice(strSymbols, start, end).join(''); +} + +export default trim; diff --git a/src/trimEnd.ts b/src/trimEnd.ts new file mode 100644 index 000000000..cedb58af3 --- /dev/null +++ b/src/trimEnd.ts @@ -0,0 +1,36 @@ +import castSlice from './.internal/castSlice.js'; +import charsEndIndex from './.internal/charsEndIndex.js'; +import stringToArray from './.internal/stringToArray.js'; + +const methodName = ''.trimRight ? 'trimRight' : 'trimEnd'; + +/** + * Removes trailing whitespace or specified characters from `string`. + * + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @returns {string} Returns the trimmed string. + * @see trim, trimStart + * @example + * + * trimEnd(' abc ') + * // => ' abc' + * + * trimEnd('-_-abc-_-', '_-') + * // => '-_-abc' + */ +function trimEnd(string, chars) { + if (string && chars === undefined) { + return string[methodName](); + } + if (!string || !chars) { + return string || ''; + } + const strSymbols = stringToArray(string); + const end = charsEndIndex(strSymbols, stringToArray(chars)) + 1; + return castSlice(strSymbols, 0, end).join(''); +} + +export default trimEnd; diff --git a/src/trimStart.ts b/src/trimStart.ts new file mode 100644 index 000000000..a96c88c5b --- /dev/null +++ b/src/trimStart.ts @@ -0,0 +1,36 @@ +import castSlice from './.internal/castSlice.js'; +import charsStartIndex from './.internal/charsStartIndex.js'; +import stringToArray from './.internal/stringToArray.js'; + +const methodName = ''.trimLeft ? 'trimLeft' : 'trimStart'; + +/** + * Removes leading whitespace or specified characters from `string`. + * + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @returns {string} Returns the trimmed string. + * @see trim, trimEnd + * @example + * + * trimStart(' abc ') + * // => 'abc ' + * + * trimStart('-_-abc-_-', '_-') + * // => 'abc-_-' + */ +function trimStart(string, chars) { + if (string && chars === undefined) { + return string[methodName](); + } + if (!string || !chars) { + return string || ''; + } + const strSymbols = stringToArray(string); + const start = charsStartIndex(strSymbols, stringToArray(chars)); + return castSlice(strSymbols, start).join(''); +} + +export default trimStart; diff --git a/src/truncate.ts b/src/truncate.ts new file mode 100644 index 000000000..c722ffc96 --- /dev/null +++ b/src/truncate.ts @@ -0,0 +1,111 @@ +import baseToString from './.internal/baseToString.js'; +import castSlice from './.internal/castSlice.js'; +import hasUnicode from './.internal/hasUnicode.js'; +import isObject from './isObject.js'; +import isRegExp from './isRegExp.js'; +import stringSize from './.internal/stringSize.js'; +import stringToArray from './.internal/stringToArray.js'; +import toString from './toString.js'; + +/** Used as default options for `truncate`. */ +const DEFAULT_TRUNC_LENGTH = 30; +const DEFAULT_TRUNC_OMISSION = '...'; + +/** Used to match `RegExp` flags from their coerced string values. */ +const reFlags = /\w*$/; + +/** + * Truncates `string` if it's longer than the given maximum string length. + * The last characters of the truncated string are replaced with the omission + * string which defaults to "...". + * + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to truncate. + * @param {Object} [options={}] The options object. + * @param {number} [options.length=30] The maximum string length. + * @param {string} [options.omission='...'] The string to indicate text is omitted. + * @param {RegExp|string} [options.separator] The separator pattern to truncate to. + * @returns {string} Returns the truncated string. + * @see replace + * @example + * + * truncate('hi-diddly-ho there, neighborino') + * // => 'hi-diddly-ho there, neighbo...' + * + * truncate('hi-diddly-ho there, neighborino', { + * 'length': 24, + * 'separator': ' ' + * }) + * // => 'hi-diddly-ho there,...' + * + * truncate('hi-diddly-ho there, neighborino', { + * 'length': 24, + * 'separator': /,? +/ + * }) + * // => 'hi-diddly-ho there...' + * + * truncate('hi-diddly-ho there, neighborino', { + * 'omission': ' [...]' + * }) + * // => 'hi-diddly-ho there, neig [...]' + */ +function truncate(string, options) { + let separator; + let length = DEFAULT_TRUNC_LENGTH; + let omission = DEFAULT_TRUNC_OMISSION; + + if (isObject(options)) { + separator = 'separator' in options ? options.separator : separator; + length = 'length' in options ? options.length : length; + omission = 'omission' in options ? baseToString(options.omission) : omission; + } + + string = toString(string); + + let strSymbols; + let strLength = string.length; + if (hasUnicode(string)) { + strSymbols = stringToArray(string); + strLength = strSymbols.length; + } + if (length >= strLength) { + return string; + } + let end = length - stringSize(omission); + if (end < 1) { + return omission; + } + let result = strSymbols ? castSlice(strSymbols, 0, end).join('') : string.slice(0, end); + + if (separator === undefined) { + return result + omission; + } + if (strSymbols) { + end += result.length - end; + } + if (isRegExp(separator)) { + if (string.slice(end).search(separator)) { + let match; + let newEnd; + const substring = result; + + if (!separator.global) { + separator = RegExp(separator.source, `${reFlags.exec(separator) || ''}g`); + } + separator.lastIndex = 0; + while ((match = separator.exec(substring))) { + newEnd = match.index; + } + result = result.slice(0, newEnd === undefined ? end : newEnd); + } + } else if (string.indexOf(baseToString(separator), end) != end) { + const index = result.lastIndexOf(separator); + if (index > -1) { + result = result.slice(0, index); + } + } + return result + omission; +} + +export default truncate; diff --git a/unescape.js b/src/unescape.ts similarity index 66% rename from unescape.js rename to src/unescape.ts index f28d0b3ff..c6c63f2ed 100644 --- a/unescape.js +++ b/src/unescape.ts @@ -1,15 +1,15 @@ /** Used to map HTML entities to characters. */ const htmlUnescapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'" -} + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'", +}; /** Used to match HTML entities and HTML characters. */ -const reEscapedHtml = /&(?:amp|lt|gt|quot|#(0+)?39);/g -const reHasEscapedHtml = RegExp(reEscapedHtml.source) +const reEscapedHtml = /&(?:amp|lt|gt|quot|#(0+)?39);/g; +const reHasEscapedHtml = RegExp(reEscapedHtml.source); /** * The inverse of `escape`this method converts the HTML entities @@ -30,9 +30,9 @@ const reHasEscapedHtml = RegExp(reEscapedHtml.source) * // => 'fred, barney, & pebbles' */ function unescape(string) { - return (string && reHasEscapedHtml.test(string)) - ? string.replace(reEscapedHtml, (entity) => (htmlUnescapes[entity] || "'")) - : (string || '') + return string && reHasEscapedHtml.test(string) + ? string.replace(reEscapedHtml, (entity) => htmlUnescapes[entity] || "'") + : string || ''; } -export default unescape +export default unescape; diff --git a/union.js b/src/union.ts similarity index 66% rename from union.js rename to src/union.ts index 77b3b6b72..380a83f5f 100644 --- a/union.js +++ b/src/union.ts @@ -1,6 +1,6 @@ -import baseFlatten from './.internal/baseFlatten.js' -import baseUniq from './.internal/baseUniq.js' -import isArrayLikeObject from './isArrayLikeObject.js' +import baseFlatten from './.internal/baseFlatten.js'; +import baseUniq from './.internal/baseUniq.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; /** * Creates an array of unique values, in order, from all given arrays using @@ -18,7 +18,7 @@ import isArrayLikeObject from './isArrayLikeObject.js' * // => [2, 3, 1] */ function union(...arrays) { - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)) + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); } -export default union +export default union; diff --git a/unionBy.js b/src/unionBy.ts similarity index 63% rename from unionBy.js rename to src/unionBy.ts index 893433907..dd02ba2d8 100644 --- a/unionBy.js +++ b/src/unionBy.ts @@ -1,7 +1,7 @@ -import baseFlatten from './.internal/baseFlatten.js' -import baseUniq from './.internal/baseUniq.js' -import isArrayLikeObject from './isArrayLikeObject.js' -import last from './last.js' +import baseFlatten from './.internal/baseFlatten.js'; +import baseUniq from './.internal/baseUniq.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; +import last from './last.js'; /** * This method is like `union` except that it accepts `iteratee` which is @@ -22,11 +22,11 @@ import last from './last.js' * // => [2.1, 1.2] */ function unionBy(...arrays) { - let iteratee = last(arrays) - if (isArrayLikeObject(iteratee)) { - iteratee = undefined - } - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), iteratee) + let iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), iteratee); } -export default unionBy +export default unionBy; diff --git a/unionWith.js b/src/unionWith.ts similarity index 66% rename from unionWith.js rename to src/unionWith.ts index c5c3be932..023758040 100644 --- a/unionWith.js +++ b/src/unionWith.ts @@ -1,7 +1,7 @@ -import baseFlatten from './.internal/baseFlatten.js' -import baseUniq from './.internal/baseUniq.js' -import isArrayLikeObject from './isArrayLikeObject.js' -import last from './last.js' +import baseFlatten from './.internal/baseFlatten.js'; +import baseUniq from './.internal/baseUniq.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; +import last from './last.js'; /** * This method is like `union` except that it accepts `comparator` which @@ -24,9 +24,9 @@ import last from './last.js' * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] */ function unionWith(...arrays) { - let comparator = last(arrays) - comparator = typeof comparator === 'function' ? comparator : undefined - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator) + let comparator = last(arrays); + comparator = typeof comparator === 'function' ? comparator : undefined; + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); } -export default unionWith +export default unionWith; diff --git a/uniq.js b/src/uniq.ts similarity index 80% rename from uniq.js rename to src/uniq.ts index 68be2d0fd..acb6f351f 100644 --- a/uniq.js +++ b/src/uniq.ts @@ -1,4 +1,4 @@ -import baseUniq from './.internal/baseUniq.js' +import baseUniq from './.internal/baseUniq.js'; /** * Creates a duplicate-free version of an array, using @@ -18,9 +18,7 @@ import baseUniq from './.internal/baseUniq.js' * // => [2, 1] */ function uniq(array) { - return (array != null && array.length) - ? baseUniq(array) - : [] + return array != null && array.length ? baseUniq(array) : []; } -export default uniq +export default uniq; diff --git a/uniqBy.js b/src/uniqBy.ts similarity index 81% rename from uniqBy.js rename to src/uniqBy.ts index dc24a7ce3..a65d45c59 100644 --- a/uniqBy.js +++ b/src/uniqBy.ts @@ -1,4 +1,4 @@ -import baseUniq from './.internal/baseUniq.js' +import baseUniq from './.internal/baseUniq.js'; /** * This method is like `uniq` except that it accepts `iteratee` which is @@ -19,9 +19,7 @@ import baseUniq from './.internal/baseUniq.js' * // => [2.1, 1.2] */ function uniqBy(array, iteratee) { - return (array != null && array.length) - ? baseUniq(array, iteratee) - : [] + return array != null && array.length ? baseUniq(array, iteratee) : []; } -export default uniqBy +export default uniqBy; diff --git a/uniqWith.js b/src/uniqWith.ts similarity index 75% rename from uniqWith.js rename to src/uniqWith.ts index 77feac13f..9fe627082 100644 --- a/uniqWith.js +++ b/src/uniqWith.ts @@ -1,4 +1,4 @@ -import baseUniq from './.internal/baseUniq.js' +import baseUniq from './.internal/baseUniq.js'; /** * This method is like `uniq` except that it accepts `comparator` which @@ -20,10 +20,8 @@ import baseUniq from './.internal/baseUniq.js' * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] */ function uniqWith(array, comparator) { - comparator = typeof comparator === 'function' ? comparator : undefined - return (array != null && array.length) - ? baseUniq(array, undefined, comparator) - : [] + comparator = typeof comparator === 'function' ? comparator : undefined; + return array != null && array.length ? baseUniq(array, undefined, comparator) : []; } -export default uniqWith +export default uniqWith; diff --git a/uniqueId.js b/src/uniqueId.ts similarity index 57% rename from uniqueId.js rename to src/uniqueId.ts index 934ece290..7e04b38cb 100644 --- a/uniqueId.js +++ b/src/uniqueId.ts @@ -1,5 +1,5 @@ /** Used to generate unique IDs. */ -const idCounter = {} +const idCounter = {}; /** * Generates a unique ID. If `prefix` is given, the ID is appended to it. @@ -17,17 +17,17 @@ const idCounter = {} * uniqueId() * // => '105' */ -function uniqueId(prefix='$lodash$') { - if (!idCounter[prefix]) { - idCounter[prefix] = 0 - } +function uniqueId(prefix = '$lodash$') { + if (!idCounter[prefix]) { + idCounter[prefix] = 0; + } - const id =++idCounter[prefix] - if (prefix === '$lodash$') { - return `${id}` - } + const id = ++idCounter[prefix]; + if (prefix === '$lodash$') { + return `${id}`; + } - return `${prefix}${id}` + return `${prefix}${id}`; } -export default uniqueId +export default uniqueId; diff --git a/unset.js b/src/unset.ts similarity index 83% rename from unset.js rename to src/unset.ts index 15ddd563d..3736aef9c 100644 --- a/unset.js +++ b/src/unset.ts @@ -1,4 +1,4 @@ -import baseUnset from './.internal/baseUnset.js' +import baseUnset from './.internal/baseUnset.js'; /** * Removes the property at `path` of `object`. @@ -27,7 +27,7 @@ import baseUnset from './.internal/baseUnset.js' * // => { 'a': [{ 'b': {} }] } */ function unset(object, path) { - return object == null ? true : baseUnset(object, path) + return object == null ? true : baseUnset(object, path); } -export default unset +export default unset; diff --git a/src/unzip.ts b/src/unzip.ts new file mode 100644 index 000000000..8a2c084dc --- /dev/null +++ b/src/unzip.ts @@ -0,0 +1,43 @@ +import filter from './filter.js'; +import map from './map.js'; +import baseProperty from './.internal/baseProperty.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; + +/** + * 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. + * + * @since 1.2.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @see unzipWith, zip, zipObject, zipObjectDeep, zipWith + * @example + * + * const zipped = zip(['a', 'b'], [1, 2], [true, false]) + * // => [['a', 1, true], ['b', 2, false]] + * + * unzip(zipped) + * // => [['a', 'b'], [1, 2], [true, false]] + */ +function unzip(array) { + if (!(array != null && array.length)) { + return []; + } + let length = 0; + array = filter(array, (group) => { + if (isArrayLikeObject(group)) { + length = Math.max(group.length, length); + return true; + } + }); + let index = -1; + const result = new Array(length); + while (++index < length) { + result[index] = map(array, baseProperty(index)); + } + return result; +} + +export default unzip; diff --git a/unzipWith.js b/src/unzipWith.ts similarity index 71% rename from unzipWith.js rename to src/unzipWith.ts index 7c2aeef28..763fe13aa 100644 --- a/unzipWith.js +++ b/src/unzipWith.ts @@ -1,5 +1,5 @@ -import map from './map.js' -import unzip from './unzip.js' +import map from './map.js'; +import unzip from './unzip.js'; /** * This method is like `unzip` except that it accepts `iteratee` to specify @@ -21,11 +21,11 @@ import unzip from './unzip.js' * // => [3, 30, 300] */ function unzipWith(array, iteratee) { - if (!(array != null && array.length)) { - return [] - } - const result = unzip(array) - return map(result, (group) => iteratee.apply(undefined, group)) + if (!(array != null && array.length)) { + return []; + } + const result = unzip(array); + return map(result, (group) => iteratee.apply(undefined, group)); } -export default unzipWith +export default unzipWith; diff --git a/update.js b/src/update.ts similarity index 84% rename from update.js rename to src/update.ts index 75d3a94b6..645c2c8cd 100644 --- a/update.js +++ b/src/update.ts @@ -1,4 +1,4 @@ -import baseUpdate from './.internal/baseUpdate.js' +import baseUpdate from './.internal/baseUpdate.js'; /** * This method is like `set` except that it accepts `updater` to produce the @@ -26,7 +26,7 @@ import baseUpdate from './.internal/baseUpdate.js' * // => 0 */ function update(object, path, updater) { - return object == null ? object : baseUpdate(object, path, updater) + return object == null ? object : baseUpdate(object, path, updater); } -export default update +export default update; diff --git a/updateWith.js b/src/updateWith.ts similarity index 78% rename from updateWith.js rename to src/updateWith.ts index 60a37e147..c8abd91fb 100644 --- a/updateWith.js +++ b/src/updateWith.ts @@ -1,4 +1,4 @@ -import baseUpdate from './.internal/baseUpdate.js' +import baseUpdate from './.internal/baseUpdate.js'; /** * This method is like `update` except that it accepts `customizer` which is @@ -23,8 +23,8 @@ import baseUpdate from './.internal/baseUpdate.js' * // => { '0': { '1': 'a' } } */ function updateWith(object, path, updater, customizer) { - customizer = typeof customizer === 'function' ? customizer : undefined - return object == null ? object : baseUpdate(object, path, updater, customizer) + customizer = typeof customizer === 'function' ? customizer : undefined; + return object == null ? object : baseUpdate(object, path, updater, customizer); } -export default updateWith +export default updateWith; diff --git a/upperCase.js b/src/upperCase.ts similarity index 60% rename from upperCase.js rename to src/upperCase.ts index db14da836..636ad01fb 100644 --- a/upperCase.js +++ b/src/upperCase.ts @@ -1,5 +1,5 @@ -import words from './words.js' -import toString from './toString.js' +import words from './words.js'; +import toString from './toString.js'; /** * Converts `string`, as space separated words, to upper case. @@ -20,10 +20,10 @@ import toString from './toString.js' * upperCase('__foo_bar__') * // => 'FOO BAR' */ -const upperCase = (string) => ( - words(toString(string).replace(/['\u2019]/g, '')).reduce((result, word, index) => ( - result + (index ? ' ' : '') + word.toUpperCase() - ), '') -) +const upperCase = (string) => + words(toString(string).replace(/['\u2019]/g, '')).reduce( + (result, word, index) => result + (index ? ' ' : '') + word.toUpperCase(), + '', + ); -export default upperCase +export default upperCase; diff --git a/upperFirst.js b/src/upperFirst.ts similarity index 73% rename from upperFirst.js rename to src/upperFirst.ts index 2c07717cc..8a41d18e1 100644 --- a/upperFirst.js +++ b/src/upperFirst.ts @@ -1,4 +1,4 @@ -import createCaseFirst from './.internal/createCaseFirst.js' +import createCaseFirst from './.internal/createCaseFirst.js'; /** * Converts the first character of `string` to upper case. @@ -16,6 +16,6 @@ import createCaseFirst from './.internal/createCaseFirst.js' * upperFirst('FRED') * // => 'FRED' */ -const upperFirst = createCaseFirst('toUpperCase') +const upperFirst = createCaseFirst('toUpperCase'); -export default upperFirst +export default upperFirst; diff --git a/values.js b/src/values.ts similarity index 76% rename from values.js rename to src/values.ts index 8d111807e..b648d309f 100644 --- a/values.js +++ b/src/values.ts @@ -1,5 +1,5 @@ -import baseValues from './.internal/baseValues.js' -import keys from './keys.js' +import baseValues from './.internal/baseValues.js'; +import keys from './keys.js'; /** * Creates an array of the own enumerable string keyed property values of `object`. @@ -27,7 +27,7 @@ import keys from './keys.js' * // => ['h', 'i'] */ function values(object) { - return object == null ? [] : baseValues(object, keys(object)) + return object == null ? [] : baseValues(object, keys(object)); } -export default values +export default values; diff --git a/without.js b/src/without.ts similarity index 73% rename from without.js rename to src/without.ts index 60d506b37..02ea17e85 100644 --- a/without.js +++ b/src/without.ts @@ -1,5 +1,5 @@ -import baseDifference from './.internal/baseDifference.js' -import isArrayLikeObject from './isArrayLikeObject.js' +import baseDifference from './.internal/baseDifference.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; /** * Creates an array excluding all given values using @@ -20,7 +20,7 @@ import isArrayLikeObject from './isArrayLikeObject.js' * // => [3] */ function without(array, ...values) { - return isArrayLikeObject(array) ? baseDifference(array, values) : [] + return isArrayLikeObject(array) ? baseDifference(array, values) : []; } -export default without +export default without; diff --git a/words.js b/src/words.ts similarity index 58% rename from words.js rename to src/words.ts index fef05f80a..028c1912b 100644 --- a/words.js +++ b/src/words.ts @@ -1,14 +1,14 @@ -import unicodeWords from './.internal/unicodeWords.js' +import unicodeWords from './.internal/unicodeWords.js'; const hasUnicodeWord = RegExp.prototype.test.bind( - /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/ -) + /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/, +); /** Used to match words composed of alphanumeric characters. */ -const reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g +const reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; function asciiWords(string) { - return string.match(reAsciiWord) + return string.match(reAsciiWord); } /** @@ -28,11 +28,11 @@ function asciiWords(string) { * // => ['fred', 'barney', '&', 'pebbles'] */ function words(string, pattern) { - if (pattern === undefined) { - const result = hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string) - return result || [] - } - return string.match(pattern) || [] + if (pattern === undefined) { + const result = hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string); + return result || []; + } + return string.match(pattern) || []; } -export default words +export default words; diff --git a/xor.js b/src/xor.ts similarity index 75% rename from xor.js rename to src/xor.ts index 8b5e8688e..19bfce71f 100644 --- a/xor.js +++ b/src/xor.ts @@ -1,5 +1,5 @@ -import baseXor from './.internal/baseXor.js' -import isArrayLikeObject from './isArrayLikeObject.js' +import baseXor from './.internal/baseXor.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; /** * Creates an array of unique values that is the @@ -18,7 +18,7 @@ import isArrayLikeObject from './isArrayLikeObject.js' * // => [1, 3] */ function xor(...arrays) { - return baseXor(arrays.filter(isArrayLikeObject)) + return baseXor(arrays.filter(isArrayLikeObject)); } -export default xor +export default xor; diff --git a/xorBy.js b/src/xorBy.ts similarity index 68% rename from xorBy.js rename to src/xorBy.ts index 87b75a355..900597287 100644 --- a/xorBy.js +++ b/src/xorBy.ts @@ -1,6 +1,6 @@ -import baseXor from './.internal/baseXor.js' -import isArrayLikeObject from './isArrayLikeObject.js' -import last from './last.js' +import baseXor from './.internal/baseXor.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; +import last from './last.js'; /** * This method is like `xor` except that it accepts `iteratee` which is @@ -21,11 +21,11 @@ import last from './last.js' * // => [1.2, 3.4] */ function xorBy(...arrays) { - let iteratee = last(arrays) - if (isArrayLikeObject(iteratee)) { - iteratee = undefined - } - return baseXor(arrays.filter(isArrayLikeObject), iteratee) + let iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseXor(arrays.filter(isArrayLikeObject), iteratee); } -export default xorBy +export default xorBy; diff --git a/xorWith.js b/src/xorWith.ts similarity index 70% rename from xorWith.js rename to src/xorWith.ts index 97775d706..1d5cb4f26 100644 --- a/xorWith.js +++ b/src/xorWith.ts @@ -1,6 +1,6 @@ -import baseXor from './.internal/baseXor.js' -import isArrayLikeObject from './isArrayLikeObject.js' -import last from './last.js' +import baseXor from './.internal/baseXor.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; +import last from './last.js'; /** * This method is like `xor` except that it accepts `comparator` which is @@ -23,9 +23,9 @@ import last from './last.js' * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] */ function xorWith(...arrays) { - let comparator = last(arrays) - comparator = typeof comparator === 'function' ? comparator : undefined - return baseXor(arrays.filter(isArrayLikeObject), undefined, comparator) + let comparator = last(arrays); + comparator = typeof comparator === 'function' ? comparator : undefined; + return baseXor(arrays.filter(isArrayLikeObject), undefined, comparator); } -export default xorWith +export default xorWith; diff --git a/zip.js b/src/zip.ts similarity index 87% rename from zip.js rename to src/zip.ts index 905c82cec..7c988ecd7 100644 --- a/zip.js +++ b/src/zip.ts @@ -1,4 +1,4 @@ -import unzip from './unzip.js' +import unzip from './unzip.js'; /** * Creates an array of grouped elements, the first of which contains the @@ -16,7 +16,7 @@ import unzip from './unzip.js' * // => [['a', 1, true], ['b', 2, false]] */ function zip(...arrays) { - return unzip(arrays) + return unzip(arrays); } -export default zip +export default zip; diff --git a/zipObject.js b/src/zipObject.ts similarity index 71% rename from zipObject.js rename to src/zipObject.ts index 309da74f4..cb62d9d05 100644 --- a/zipObject.js +++ b/src/zipObject.ts @@ -1,5 +1,5 @@ -import assignValue from './.internal/assignValue.js' -import baseZipObject from './.internal/baseZipObject.js' +import assignValue from './.internal/assignValue.js'; +import baseZipObject from './.internal/baseZipObject.js'; /** * This method is like `fromPairs` except that it accepts two arrays, @@ -17,7 +17,7 @@ import baseZipObject from './.internal/baseZipObject.js' * // => { 'a': 1, 'b': 2 } */ function zipObject(props, values) { - return baseZipObject(props || [], values || [], assignValue) + return baseZipObject(props || [], values || [], assignValue); } -export default zipObject +export default zipObject; diff --git a/zipObjectDeep.js b/src/zipObjectDeep.ts similarity index 71% rename from zipObjectDeep.js rename to src/zipObjectDeep.ts index 07eec2cda..3d92bd23b 100644 --- a/zipObjectDeep.js +++ b/src/zipObjectDeep.ts @@ -1,5 +1,5 @@ -import baseSet from './.internal/baseSet.js' -import baseZipObject from './.internal/baseZipObject.js' +import baseSet from './.internal/baseSet.js'; +import baseZipObject from './.internal/baseZipObject.js'; /** * This method is like `zipObject` except that it supports property paths. @@ -16,7 +16,7 @@ import baseZipObject from './.internal/baseZipObject.js' * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } */ function zipObjectDeep(props, values) { - return baseZipObject(props || [], values || [], baseSet) + return baseZipObject(props || [], values || [], baseSet); } -export default zipObjectDeep +export default zipObjectDeep; diff --git a/zipWith.js b/src/zipWith.ts similarity index 72% rename from zipWith.js rename to src/zipWith.ts index 30989ac59..d840a9c00 100644 --- a/zipWith.js +++ b/src/zipWith.ts @@ -1,4 +1,4 @@ -import unzipWith from './unzipWith.js' +import unzipWith from './unzipWith.js'; /** * This method is like `zip` except that it accepts `iteratee` to specify @@ -18,10 +18,10 @@ import unzipWith from './unzipWith.js' * // => [111, 222] */ function zipWith(...arrays) { - const length = arrays.length - let iteratee = length > 1 ? arrays[length - 1] : undefined - iteratee = typeof iteratee === 'function' ? (arrays.pop(), iteratee) : undefined - return unzipWith(arrays, iteratee) + const length = arrays.length; + let iteratee = length > 1 ? arrays[length - 1] : undefined; + iteratee = typeof iteratee === 'function' ? (arrays.pop(), iteratee) : undefined; + return unzipWith(arrays, iteratee); } -export default zipWith +export default zipWith; diff --git a/test/.eslintrc.cjs b/test/.eslintrc.cjs new file mode 100644 index 000000000..a79516b6e --- /dev/null +++ b/test/.eslintrc.cjs @@ -0,0 +1,22 @@ +'use strict'; + +const path = require('node:path'); + +module.exports = { + globals: { + describe: 'readonly', + expect: 'readonly', + it: 'readonly', + xdescribe: 'readonly', + xit: 'readonly' + }, + overrides: [ + { + files: ['**/*.{ts}'], + rules: { + 'import/no-unresolved': 'off', + 'import/no-extraneous-dependencies': 'off', + }, + }, + ], +}; diff --git a/test/Arrays-category-methods.js b/test/Arrays-category-methods.js deleted file mode 100644 index 79cd15954..000000000 --- a/test/Arrays-category-methods.js +++ /dev/null @@ -1,97 +0,0 @@ -import assert from 'assert'; -import { args, toArgs, identity } from './utils.js'; -import difference from '../difference.js'; -import union from '../union.js'; -import compact from '../compact.js'; -import drop from '../drop.js'; -import dropRight from '../dropRight.js'; -import dropRightWhile from '../dropRightWhile.js'; -import dropWhile from '../dropWhile.js'; -import findIndex from '../findIndex.js'; -import findLastIndex from '../findLastIndex.js'; -import flatten from '../flatten.js'; -import head from '../head.js'; -import indexOf from '../indexOf.js'; -import initial from '../initial.js'; -import intersection from '../intersection.js'; -import last from '../last.js'; -import lastIndexOf from '../lastIndexOf.js'; -import sortedIndex from '../sortedIndex.js'; -import sortedIndexOf from '../sortedIndexOf.js'; -import sortedLastIndex from '../sortedLastIndex.js'; -import sortedLastIndexOf from '../sortedLastIndexOf.js'; -import tail from '../tail.js'; -import take from '../take.js'; -import takeRight from '../takeRight.js'; -import takeRightWhile from '../takeRightWhile.js'; -import takeWhile from '../takeWhile.js'; -import uniq from '../uniq.js'; -import without from '../without.js'; -import zip from '../zip.js'; -import xor from '../xor.js'; - -describe('"Arrays" category methods', function() { - var args = toArgs([1, null, [3], null, 5]), - sortedArgs = toArgs([1, [3], 5, null, null]), - array = [1, 2, 3, 4, 5, 6]; - - it('should work with `arguments` objects', function() { - function message(methodName) { - return '`_.' + methodName + '` should work with `arguments` objects'; - } - - assert.deepStrictEqual(difference(args, [null]), [1, [3], 5], message('difference')); - assert.deepStrictEqual(difference(array, args), [2, 3, 4, 6], '_.difference should work with `arguments` objects as secondary arguments'); - - assert.deepStrictEqual(union(args, [null, 6]), [1, null, [3], 5, 6], message('union')); - assert.deepStrictEqual(union(array, args), array.concat([null, [3]]), '_.union should work with `arguments` objects as secondary arguments'); - - assert.deepStrictEqual(compact(args), [1, [3], 5], message('compact')); - assert.deepStrictEqual(drop(args, 3), [null, 5], message('drop')); - assert.deepStrictEqual(dropRight(args, 3), [1, null], message('dropRight')); - assert.deepStrictEqual(dropRightWhile(args,identity), [1, null, [3], null], message('dropRightWhile')); - assert.deepStrictEqual(dropWhile(args,identity), [null, [3], null, 5], message('dropWhile')); - assert.deepStrictEqual(findIndex(args, identity), 0, message('findIndex')); - assert.deepStrictEqual(findLastIndex(args, identity), 4, message('findLastIndex')); - assert.deepStrictEqual(flatten(args), [1, null, 3, null, 5], message('flatten')); - assert.deepStrictEqual(head(args), 1, message('head')); - assert.deepStrictEqual(indexOf(args, 5), 4, message('indexOf')); - assert.deepStrictEqual(initial(args), [1, null, [3], null], message('initial')); - assert.deepStrictEqual(intersection(args, [1]), [1], message('intersection')); - assert.deepStrictEqual(last(args), 5, message('last')); - assert.deepStrictEqual(lastIndexOf(args, 1), 0, message('lastIndexOf')); - assert.deepStrictEqual(sortedIndex(sortedArgs, 6), 3, message('sortedIndex')); - assert.deepStrictEqual(sortedIndexOf(sortedArgs, 5), 2, message('sortedIndexOf')); - assert.deepStrictEqual(sortedLastIndex(sortedArgs, 5), 3, message('sortedLastIndex')); - assert.deepStrictEqual(sortedLastIndexOf(sortedArgs, 1), 0, message('sortedLastIndexOf')); - assert.deepStrictEqual(tail(args, 4), [null, [3], null, 5], message('tail')); - assert.deepStrictEqual(take(args, 2), [1, null], message('take')); - assert.deepStrictEqual(takeRight(args, 1), [5], message('takeRight')); - assert.deepStrictEqual(takeRightWhile(args, identity), [5], message('takeRightWhile')); - assert.deepStrictEqual(takeWhile(args, identity), [1], message('takeWhile')); - assert.deepStrictEqual(uniq(args), [1, null, [3], 5], message('uniq')); - assert.deepStrictEqual(without(args, null), [1, [3], 5], message('without')); - assert.deepStrictEqual(zip(args, args), [[1, 1], [null, null], [[3], [3]], [null, null], [5, 5]], message('zip')); - }); - - it('should accept falsey primary arguments', function() { - function message(methodName) { - return '`_.' + methodName + '` should accept falsey primary arguments'; - } - - assert.deepStrictEqual(difference(null, array), [], message('difference')); - assert.deepStrictEqual(intersection(null, array), [], message('intersection')); - assert.deepStrictEqual(union(null, array), array, message('union')); - assert.deepStrictEqual(xor(null, array), array, message('xor')); - }); - - it('should accept falsey secondary arguments', function() { - function message(methodName) { - return '`_.' + methodName + '` should accept falsey secondary arguments'; - } - - assert.deepStrictEqual(difference(array, null), array, message('difference')); - assert.deepStrictEqual(intersection(array, null), [], message('intersection')); - assert.deepStrictEqual(union(array, null), array, message('union')); - }); -}); diff --git a/test/Arrays-category-methods.spec.ts b/test/Arrays-category-methods.spec.ts new file mode 100644 index 000000000..58d2e5a2f --- /dev/null +++ b/test/Arrays-category-methods.spec.ts @@ -0,0 +1,123 @@ +import assert from 'node:assert'; +import { args, toArgs, identity } from './utils'; +import difference from '../src/difference'; +import union from '../src/union'; +import compact from '../src/compact'; +import drop from '../src/drop'; +import dropRight from '../src/dropRight'; +import dropRightWhile from '../src/dropRightWhile'; +import dropWhile from '../src/dropWhile'; +import findIndex from '../src/findIndex'; +import findLastIndex from '../src/findLastIndex'; +import flatten from '../src/flatten'; +import head from '../src/head'; +import indexOf from '../src/indexOf'; +import initial from '../src/initial'; +import intersection from '../src/intersection'; +import last from '../src/last'; +import lastIndexOf from '../src/lastIndexOf'; +import sortedIndex from '../src/sortedIndex'; +import sortedIndexOf from '../src/sortedIndexOf'; +import sortedLastIndex from '../src/sortedLastIndex'; +import sortedLastIndexOf from '../src/sortedLastIndexOf'; +import tail from '../src/tail'; +import take from '../src/take'; +import takeRight from '../src/takeRight'; +import takeRightWhile from '../src/takeRightWhile'; +import takeWhile from '../src/takeWhile'; +import uniq from '../src/uniq'; +import without from '../src/without'; +import zip from '../src/zip'; +import xor from '../src/xor'; + +describe('"Arrays" category methods', () => { + const args = toArgs([1, null, [3], null, 5]), + sortedArgs = toArgs([1, [3], 5, null, null]), + array = [1, 2, 3, 4, 5, 6]; + + it('should work with `arguments` objects', () => { + function message(methodName) { + return `\`_.${methodName}\` should work with \`arguments\` objects`; + } + + assert.deepStrictEqual(difference(args, [null]), [1, [3], 5], message('difference')); + assert.deepStrictEqual( + difference(array, args), + [2, 3, 4, 6], + '_.difference should work with `arguments` objects as secondary arguments', + ); + + assert.deepStrictEqual(union(args, [null, 6]), [1, null, [3], 5, 6], message('union')); + assert.deepStrictEqual( + union(array, args), + array.concat([null, [3]]), + '_.union should work with `arguments` objects as secondary arguments', + ); + + assert.deepStrictEqual(compact(args), [1, [3], 5], message('compact')); + assert.deepStrictEqual(drop(args, 3), [null, 5], message('drop')); + assert.deepStrictEqual(dropRight(args, 3), [1, null], message('dropRight')); + assert.deepStrictEqual( + dropRightWhile(args, identity), + [1, null, [3], null], + message('dropRightWhile'), + ); + assert.deepStrictEqual( + dropWhile(args, identity), + [null, [3], null, 5], + message('dropWhile'), + ); + assert.deepStrictEqual(findIndex(args, identity), 0, message('findIndex')); + assert.deepStrictEqual(findLastIndex(args, identity), 4, message('findLastIndex')); + assert.deepStrictEqual(flatten(args), [1, null, 3, null, 5], message('flatten')); + assert.deepStrictEqual(head(args), 1, message('head')); + assert.deepStrictEqual(indexOf(args, 5), 4, message('indexOf')); + assert.deepStrictEqual(initial(args), [1, null, [3], null], message('initial')); + assert.deepStrictEqual(intersection(args, [1]), [1], message('intersection')); + assert.deepStrictEqual(last(args), 5, message('last')); + assert.deepStrictEqual(lastIndexOf(args, 1), 0, message('lastIndexOf')); + assert.deepStrictEqual(sortedIndex(sortedArgs, 6), 3, message('sortedIndex')); + assert.deepStrictEqual(sortedIndexOf(sortedArgs, 5), 2, message('sortedIndexOf')); + assert.deepStrictEqual(sortedLastIndex(sortedArgs, 5), 3, message('sortedLastIndex')); + assert.deepStrictEqual(sortedLastIndexOf(sortedArgs, 1), 0, message('sortedLastIndexOf')); + assert.deepStrictEqual(tail(args, 4), [null, [3], null, 5], message('tail')); + assert.deepStrictEqual(take(args, 2), [1, null], message('take')); + assert.deepStrictEqual(takeRight(args, 1), [5], message('takeRight')); + assert.deepStrictEqual(takeRightWhile(args, identity), [5], message('takeRightWhile')); + assert.deepStrictEqual(takeWhile(args, identity), [1], message('takeWhile')); + assert.deepStrictEqual(uniq(args), [1, null, [3], 5], message('uniq')); + assert.deepStrictEqual(without(args, null), [1, [3], 5], message('without')); + assert.deepStrictEqual( + zip(args, args), + [ + [1, 1], + [null, null], + [[3], [3]], + [null, null], + [5, 5], + ], + message('zip'), + ); + }); + + it('should accept falsey primary arguments', () => { + function message(methodName) { + return `\`_.${methodName}\` should accept falsey primary arguments`; + } + + assert.deepStrictEqual(difference(null, array), [], message('difference')); + assert.deepStrictEqual(intersection(null, array), [], message('intersection')); + assert.deepStrictEqual(union(null, array), array, message('union')); + assert.deepStrictEqual(xor(null, array), array, message('xor')); + }); + + it('should accept falsey secondary arguments', () => { + function message(methodName) { + return `\`_.${methodName}\` should accept falsey secondary arguments`; + } + + assert.deepStrictEqual(difference(array, null), array, message('difference')); + assert.deepStrictEqual(intersection(array, null), [], message('intersection')); + assert.deepStrictEqual(union(array, null), array, message('union')); + }); +}); diff --git a/test/Strings-category-methods.spec.ts b/test/Strings-category-methods.spec.ts new file mode 100644 index 000000000..27f7c8774 --- /dev/null +++ b/test/Strings-category-methods.spec.ts @@ -0,0 +1,81 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubString } from './utils'; + +import camelCase from '../src/camelCase'; +import capitalize from '../src/capitalize'; +import escape from '../src/escape'; +import kebabCase from '../src/kebabCase'; +import lowerCase from '../src/lowerCase'; +import lowerFirst from '../src/lowerFirst'; +import pad from '../src/pad'; +import padEnd from '../src/padEnd'; +import padStart from '../src/padStart'; +import repeat from '../src/repeat'; +import snakeCase from '../src/snakeCase'; +import trim from '../src/trim'; +import trimStart from '../src/trimStart'; +import trimEnd from '../src/trimEnd'; +import truncate from '../src/truncate'; +import unescape from '../src/unescape'; +import upperCase from '../src/upperCase'; +import upperFirst from '../src/upperFirst'; + +const methods = { + camelCase, + capitalize, + escape, + kebabCase, + lowerCase, + lowerFirst, + pad, + padEnd, + padStart, + repeat, + snakeCase, + trim, + trimStart, + trimEnd, + truncate, + unescape, + upperCase, + upperFirst, +}; + +describe('"Strings" category methods', () => { + const stringMethods = [ + 'camelCase', + 'capitalize', + 'escape', + 'kebabCase', + 'lowerCase', + 'lowerFirst', + 'pad', + 'padEnd', + 'padStart', + 'repeat', + 'snakeCase', + 'trim', + 'trimEnd', + 'trimStart', + 'truncate', + 'unescape', + 'upperCase', + 'upperFirst', + ]; + + lodashStable.each(stringMethods, (methodName) => { + const func = methods[methodName]; + + it(`\`_.${methodName}\` should return an empty string for empty values`, () => { + const values = [, null, undefined, ''], + expected = lodashStable.map(values, stubString); + + const actual = lodashStable.map(values, (value, index) => + index ? func(value) : func(), + ); + + assert.deepStrictEqual(actual, expected); + }); + }); +}); diff --git a/test/Strings-category-methods.test.js b/test/Strings-category-methods.test.js deleted file mode 100644 index 781a050ef..000000000 --- a/test/Strings-category-methods.test.js +++ /dev/null @@ -1,83 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubString } from './utils.js'; - -import camelCase from '../camelCase.js'; -import capitalize from '../capitalize.js'; -import escape from '../escape.js'; -import kebabCase from '../kebabCase.js'; -import lowerCase from '../lowerCase.js'; -import lowerFirst from '../lowerFirst.js'; -import pad from '../pad.js'; -import padEnd from '../padEnd.js'; -import padStart from '../padStart.js'; -import repeat from '../repeat.js'; -import snakeCase from '../snakeCase.js'; -import trim from '../trim.js'; -import trimStart from '../trimStart.js'; -import trimEnd from '../trimEnd.js'; -import truncate from '../truncate.js'; -import unescape from '../unescape.js'; -import upperCase from '../upperCase.js'; -import upperFirst from '../upperFirst'; - - -const methods = { - camelCase, - capitalize, - escape, - kebabCase, - lowerCase, - lowerFirst, - pad, - padEnd, - padStart, - repeat, - snakeCase, - trim, - trimStart, - trimEnd, - truncate, - unescape, - upperCase, - upperFirst -} - - -describe('"Strings" category methods', function() { - var stringMethods = [ - 'camelCase', - 'capitalize', - 'escape', - 'kebabCase', - 'lowerCase', - 'lowerFirst', - 'pad', - 'padEnd', - 'padStart', - 'repeat', - 'snakeCase', - 'trim', - 'trimEnd', - 'trimStart', - 'truncate', - 'unescape', - 'upperCase', - 'upperFirst' - ]; - - lodashStable.each(stringMethods, function(methodName) { - var func = methods[methodName]; - - it('`_.' + methodName + '` should return an empty string for empty values', function() { - var values = [, null, undefined, ''], - expected = lodashStable.map(values, stubString); - - var actual = lodashStable.map(values, function(value, index) { - return index ? func(value) : func(); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/__proto__-property-bugs.js b/test/__proto__-property-bugs.js deleted file mode 100644 index 4814e441d..000000000 --- a/test/__proto__-property-bugs.js +++ /dev/null @@ -1,87 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE, isEven, _, create, stubFalse, objectProto, funcProto } from './utils.js'; -import difference from '../difference.js'; -import intersection from '../intersection.js'; -import uniq from '../uniq.js'; -import without from '../without.js'; -import groupBy from '../groupBy.js'; -import merge from '../merge.js'; - -describe('`__proto__` property bugs', function() { - it('should work with the "__proto__" key in internal data objects', function() { - var stringLiteral = '__proto__', - stringObject = Object(stringLiteral), - expected = [stringLiteral, stringObject]; - - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, function(count) { - return isEven(count) ? stringLiteral : stringObject; - }); - - assert.deepStrictEqual(difference(largeArray, largeArray), []); - assert.deepStrictEqual(intersection(largeArray, largeArray), expected); - assert.deepStrictEqual(uniq(largeArray), expected); - assert.deepStrictEqual(without.apply(_, [largeArray].concat(largeArray)), []); - }); - - it('should treat "__proto__" as a regular key in assignments', function() { - var methods = [ - 'assign', - 'assignIn', - 'defaults', - 'defaultsDeep', - 'merge' - ]; - - var source = create(null); - source.__proto__ = []; - - var expected = lodashStable.map(methods, stubFalse); - - var actual = lodashStable.map(methods, function(methodName) { - var result = _[methodName]({}, source); - return result instanceof Array; - }); - - assert.deepStrictEqual(actual, expected); - - actual = groupBy([{ 'a': '__proto__' }], 'a'); - assert.ok(!(actual instanceof Array)); - }); - - it('should not merge "__proto__" properties', function() { - if (JSON) { - merge({}, JSON.parse('{"__proto__":{"a":1}}')); - - var actual = 'a' in objectProto; - delete objectProto.a; - - assert.ok(!actual); - } - }); - - it('should not indirectly merge builtin prototype properties', function() { - merge({}, { 'toString': { 'constructor': { 'prototype': { 'a': 1 } } } }); - - var actual = 'a' in funcProto; - delete funcProto.a; - - assert.ok(!actual); - - merge({}, { 'constructor': { 'prototype': { 'a': 1 } } }); - - actual = 'a' in objectProto; - delete objectProto.a; - - assert.ok(!actual); - }); - - it('should not indirectly merge `Object` properties', function() { - merge({}, { 'constructor': { 'a': 1 } }); - - var actual = 'a' in Object; - delete Object.a; - - assert.ok(!actual); - }); -}); diff --git a/test/__proto__-property-bugs.spec.ts b/test/__proto__-property-bugs.spec.ts new file mode 100644 index 000000000..ae6dec7e2 --- /dev/null +++ b/test/__proto__-property-bugs.spec.ts @@ -0,0 +1,81 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE, isEven, _, create, stubFalse, objectProto, funcProto } from './utils'; +import difference from '../src/difference'; +import intersection from '../src/intersection'; +import uniq from '../src/uniq'; +import without from '../src/without'; +import groupBy from '../src/groupBy'; +import merge from '../src/merge'; + +describe('`__proto__` property bugs', () => { + it('should work with the "__proto__" key in internal data objects', () => { + const stringLiteral = '__proto__', + stringObject = Object(stringLiteral), + expected = [stringLiteral, stringObject]; + + const largeArray = lodashStable.times(LARGE_ARRAY_SIZE, (count) => + isEven(count) ? stringLiteral : stringObject, + ); + + assert.deepStrictEqual(difference(largeArray, largeArray), []); + assert.deepStrictEqual(intersection(largeArray, largeArray), expected); + assert.deepStrictEqual(uniq(largeArray), expected); + assert.deepStrictEqual(without.apply(_, [largeArray].concat(largeArray)), []); + }); + + it('should treat "__proto__" as a regular key in assignments', () => { + const methods = ['assign', 'assignIn', 'defaults', 'defaultsDeep', 'merge']; + + const source = create(null); + source.__proto__ = []; + + const expected = lodashStable.map(methods, stubFalse); + + let actual = lodashStable.map(methods, (methodName) => { + const result = _[methodName]({}, source); + return result instanceof Array; + }); + + assert.deepStrictEqual(actual, expected); + + actual = groupBy([{ a: '__proto__' }], 'a'); + assert.ok(!(actual instanceof Array)); + }); + + it('should not merge "__proto__" properties', () => { + if (JSON) { + merge({}, JSON.parse('{"__proto__":{"a":1}}')); + + const actual = 'a' in objectProto; + delete objectProto.a; + + assert.ok(!actual); + } + }); + + it('should not indirectly merge builtin prototype properties', () => { + merge({}, { toString: { constructor: { prototype: { a: 1 } } } }); + + let actual = 'a' in funcProto; + delete funcProto.a; + + assert.ok(!actual); + + merge({}, { constructor: { prototype: { a: 1 } } }); + + actual = 'a' in objectProto; + delete objectProto.a; + + assert.ok(!actual); + }); + + it('should not indirectly merge `Object` properties', () => { + merge({}, { constructor: { a: 1 } }); + + const actual = 'a' in Object; + delete Object.a; + + assert.ok(!actual); + }); +}); diff --git a/test/add.spec.ts b/test/add.spec.ts new file mode 100644 index 000000000..fb70e6515 --- /dev/null +++ b/test/add.spec.ts @@ -0,0 +1,15 @@ +import assert from 'node:assert'; +import add from '../src/add'; + +describe('add', () => { + it('should add two numbers', () => { + assert.strictEqual(add(6, 4), 10); + assert.strictEqual(add(-6, 4), -2); + assert.strictEqual(add(-6, -4), -10); + }); + + it('should not coerce arguments to numbers', () => { + assert.strictEqual(add('6', '4'), '64'); + assert.strictEqual(add('x', 'y'), 'xy'); + }); +}); diff --git a/test/add.test.js b/test/add.test.js deleted file mode 100644 index cbc12a0bc..000000000 --- a/test/add.test.js +++ /dev/null @@ -1,15 +0,0 @@ -import assert from 'assert'; -import add from '../add.js'; - -describe('add', function() { - it('should add two numbers', function() { - assert.strictEqual(add(6, 4), 10); - assert.strictEqual(add(-6, 4), -2); - assert.strictEqual(add(-6, -4), -10); - }); - - it('should not coerce arguments to numbers', function() { - assert.strictEqual(add('6', '4'), '64'); - assert.strictEqual(add('x', 'y'), 'xy'); - }); -}); diff --git a/test/after.spec.ts b/test/after.spec.ts new file mode 100644 index 000000000..0e9171d21 --- /dev/null +++ b/test/after.spec.ts @@ -0,0 +1,46 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import after from '../src/after'; + +describe('after', () => { + function testAfter(n, times) { + let count = 0; + lodashStable.times( + times, + after(n, () => { + count++; + }), + ); + return count; + } + + it('should create a function that invokes `func` after `n` calls', () => { + assert.strictEqual( + testAfter(5, 5), + 1, + 'after(n) should invoke `func` after being called `n` times', + ); + assert.strictEqual( + testAfter(5, 4), + 0, + 'after(n) should not invoke `func` before being called `n` times', + ); + assert.strictEqual(testAfter(0, 0), 0, 'after(0) should not invoke `func` immediately'); + assert.strictEqual(testAfter(0, 1), 1, 'after(0) should invoke `func` when called once'); + }); + + it('should coerce `n` values of `NaN` to `0`', () => { + assert.strictEqual(testAfter(NaN, 1), 1); + }); + + it('should use `this` binding of function', () => { + const afterFn = after(1, function () { + return ++this.count; + }), + object = { after: afterFn, count: 0 }; + + object.after(); + assert.strictEqual(object.after(), 2); + assert.strictEqual(object.count, 2); + }); +}); diff --git a/test/after.test.js b/test/after.test.js deleted file mode 100644 index ab509ecd1..000000000 --- a/test/after.test.js +++ /dev/null @@ -1,31 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import after from '../after.js'; - -describe('after', function() { - function testAfter(n, times) { - var count = 0; - lodashStable.times(times, after(n, function() { count++; })); - return count; - } - - it('should create a function that invokes `func` after `n` calls', function() { - assert.strictEqual(testAfter(5, 5), 1, 'after(n) should invoke `func` after being called `n` times'); - assert.strictEqual(testAfter(5, 4), 0, 'after(n) should not invoke `func` before being called `n` times'); - assert.strictEqual(testAfter(0, 0), 0, 'after(0) should not invoke `func` immediately'); - assert.strictEqual(testAfter(0, 1), 1, 'after(0) should invoke `func` when called once'); - }); - - it('should coerce `n` values of `NaN` to `0`', function() { - assert.strictEqual(testAfter(NaN, 1), 1); - }); - - it('should use `this` binding of function', function() { - var afterFn = after(1, function() { return ++this.count; }), - object = { 'after': afterFn, 'count': 0 }; - - object.after(); - assert.strictEqual(object.after(), 2); - assert.strictEqual(object.count, 2); - }); -}); diff --git a/test/ary.js b/test/ary.js deleted file mode 100644 index 80e5fb286..000000000 --- a/test/ary.js +++ /dev/null @@ -1,91 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, _ } from './utils.js'; -import ary from '../ary.js'; -import curry from '../curry.js'; -import rearg from '../rearg.js'; - -describe('ary', function() { - function fn(a, b, c) { - return slice.call(arguments); - } - - it('should cap the number of arguments provided to `func`', function() { - var actual = lodashStable.map(['6', '8', '10'], ary(parseInt, 1)); - assert.deepStrictEqual(actual, [6, 8, 10]); - - var capped = ary(fn, 2); - assert.deepStrictEqual(capped('a', 'b', 'c', 'd'), ['a', 'b']); - }); - - it('should use `func.length` if `n` is not given', function() { - var capped = ary(fn); - assert.deepStrictEqual(capped('a', 'b', 'c', 'd'), ['a', 'b', 'c']); - }); - - it('should treat a negative `n` as `0`', function() { - var capped = ary(fn, -1); - - try { - var actual = capped('a'); - } catch (e) {} - - assert.deepStrictEqual(actual, []); - }); - - it('should coerce `n` to an integer', function() { - var values = ['1', 1.6, 'xyz'], - expected = [['a'], ['a'], []]; - - var actual = lodashStable.map(values, function(n) { - var capped = ary(fn, n); - return capped('a', 'b'); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should not force a minimum argument count', function() { - var args = ['a', 'b', 'c'], - capped = ary(fn, 3); - - var expected = lodashStable.map(args, function(arg, index) { - return args.slice(0, index); - }); - - var actual = lodashStable.map(expected, function(array) { - return capped.apply(undefined, array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should use `this` binding of function', function() { - var capped = ary(function(a, b) { return this; }, 1), - object = { 'capped': capped }; - - assert.strictEqual(object.capped(), object); - }); - - it('should use the existing `ary` if smaller', function() { - var capped = ary(ary(fn, 1), 2); - assert.deepStrictEqual(capped('a', 'b', 'c'), ['a']); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var funcs = lodashStable.map([fn], ary), - actual = funcs[0]('a', 'b', 'c'); - - assert.deepStrictEqual(actual, ['a', 'b', 'c']); - }); - - it('should work when combined with other methods that use metadata', function() { - var array = ['a', 'b', 'c'], - includes = curry(rearg(ary(_.includes, 2), 1, 0), 2); - - assert.strictEqual(includes('b')(array, 2), true); - - includes = _(_.includes).ary(2).rearg(1, 0).curry(2).value(); - assert.strictEqual(includes('b')(array, 2), true); - }); -}); diff --git a/test/ary.spec.ts b/test/ary.spec.ts new file mode 100644 index 000000000..d68710f33 --- /dev/null +++ b/test/ary.spec.ts @@ -0,0 +1,89 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, _ } from './utils'; +import ary from '../src/ary'; +import curry from '../src/curry'; +import rearg from '../src/rearg'; + +describe('ary', () => { + function fn(a, b, c) { + return slice.call(arguments); + } + + it('should cap the number of arguments provided to `func`', () => { + const actual = lodashStable.map(['6', '8', '10'], ary(parseInt, 1)); + assert.deepStrictEqual(actual, [6, 8, 10]); + + const capped = ary(fn, 2); + assert.deepStrictEqual(capped('a', 'b', 'c', 'd'), ['a', 'b']); + }); + + it('should use `func.length` if `n` is not given', () => { + const capped = ary(fn); + assert.deepStrictEqual(capped('a', 'b', 'c', 'd'), ['a', 'b', 'c']); + }); + + it('should treat a negative `n` as `0`', () => { + const capped = ary(fn, -1); + + try { + var actual = capped('a'); + } catch (e) {} + + assert.deepStrictEqual(actual, []); + }); + + it('should coerce `n` to an integer', () => { + const values = ['1', 1.6, 'xyz'], + expected = [['a'], ['a'], []]; + + const actual = lodashStable.map(values, (n) => { + const capped = ary(fn, n); + return capped('a', 'b'); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should not force a minimum argument count', () => { + const args = ['a', 'b', 'c'], + capped = ary(fn, 3); + + const expected = lodashStable.map(args, (arg, index) => args.slice(0, index)); + + const actual = lodashStable.map(expected, (array) => capped.apply(undefined, array)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should use `this` binding of function', () => { + const capped = ary(function (a, b) { + return this; + }, 1), + object = { capped: capped }; + + assert.strictEqual(object.capped(), object); + }); + + it('should use the existing `ary` if smaller', () => { + const capped = ary(ary(fn, 1), 2); + assert.deepStrictEqual(capped('a', 'b', 'c'), ['a']); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const funcs = lodashStable.map([fn], ary), + actual = funcs[0]('a', 'b', 'c'); + + assert.deepStrictEqual(actual, ['a', 'b', 'c']); + }); + + it('should work when combined with other methods that use metadata', () => { + let array = ['a', 'b', 'c'], + includes = curry(rearg(ary(_.includes, 2), 1, 0), 2); + + assert.strictEqual(includes('b')(array, 2), true); + + includes = _(_.includes).ary(2).rearg(1, 0).curry(2).value(); + assert.strictEqual(includes('b')(array, 2), true); + }); +}); diff --git a/test/assign-and-assignIn.js b/test/assign-and-assignIn.js deleted file mode 100644 index 251d199ce..000000000 --- a/test/assign-and-assignIn.js +++ /dev/null @@ -1,88 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, defineProperty, stubOne, noop, stubNaN } from './utils.js'; - -describe('assign and assignIn', function() { - lodashStable.each(['assign', 'assignIn'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should assign source properties to `object`', function() { - assert.deepStrictEqual(func({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 }); - }); - - it('`_.' + methodName + '` should accept multiple sources', function() { - var expected = { 'a': 1, 'b': 2, 'c': 3 }; - assert.deepStrictEqual(func({ 'a': 1 }, { 'b': 2 }, { 'c': 3 }), expected); - assert.deepStrictEqual(func({ 'a': 1 }, { 'b': 2, 'c': 2 }, { 'c': 3 }), expected); - }); - - it('`_.' + methodName + '` should overwrite destination properties', function() { - var expected = { 'a': 3, 'b': 2, 'c': 1 }; - assert.deepStrictEqual(func({ 'a': 1, 'b': 2 }, expected), expected); - }); - - it('`_.' + methodName + '` should assign source properties with nullish values', function() { - var expected = { 'a': null, 'b': undefined, 'c': null }; - assert.deepStrictEqual(func({ 'a': 1, 'b': 2 }, expected), expected); - }); - - it('`_.' + methodName + '` should skip assignments if values are the same', function() { - var object = {}; - - var descriptor = { - 'configurable': true, - 'enumerable': true, - 'set': function() { throw new Error; } - }; - - var source = { - 'a': 1, - 'b': undefined, - 'c': NaN, - 'd': undefined, - 'constructor': Object, - 'toString': lodashStable.constant('source') - }; - - defineProperty(object, 'a', lodashStable.assign({}, descriptor, { - 'get': stubOne - })); - - defineProperty(object, 'b', lodashStable.assign({}, descriptor, { - 'get': noop - })); - - defineProperty(object, 'c', lodashStable.assign({}, descriptor, { - 'get': stubNaN - })); - - defineProperty(object, 'constructor', lodashStable.assign({}, descriptor, { - 'get': lodashStable.constant(Object) - })); - - try { - var actual = func(object, source); - } catch (e) {} - - assert.deepStrictEqual(actual, source); - }); - - it('`_.' + methodName + '` should treat sparse array sources as dense', function() { - var array = [1]; - array[2] = 3; - - assert.deepStrictEqual(func({}, array), { '0': 1, '1': undefined, '2': 3 }); - }); - - it('`_.' + methodName + '` should assign values of prototype objects', function() { - function Foo() {} - Foo.prototype.a = 1; - - assert.deepStrictEqual(func({}, Foo.prototype), { 'a': 1 }); - }); - - it('`_.' + methodName + '` should coerce string sources to objects', function() { - assert.deepStrictEqual(func({}, 'a'), { '0': 'a' }); - }); - }); -}); diff --git a/test/assign-and-assignIn.spec.ts b/test/assign-and-assignIn.spec.ts new file mode 100644 index 000000000..dfeb05ee2 --- /dev/null +++ b/test/assign-and-assignIn.spec.ts @@ -0,0 +1,106 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, defineProperty, stubOne, noop, stubNaN } from './utils'; + +describe('assign and assignIn', () => { + lodashStable.each(['assign', 'assignIn'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should assign source properties to \`object\``, () => { + assert.deepStrictEqual(func({ a: 1 }, { b: 2 }), { a: 1, b: 2 }); + }); + + it(`\`_.${methodName}\` should accept multiple sources`, () => { + const expected = { a: 1, b: 2, c: 3 }; + assert.deepStrictEqual(func({ a: 1 }, { b: 2 }, { c: 3 }), expected); + assert.deepStrictEqual(func({ a: 1 }, { b: 2, c: 2 }, { c: 3 }), expected); + }); + + it(`\`_.${methodName}\` should overwrite destination properties`, () => { + const expected = { a: 3, b: 2, c: 1 }; + assert.deepStrictEqual(func({ a: 1, b: 2 }, expected), expected); + }); + + it(`\`_.${methodName}\` should assign source properties with nullish values`, () => { + const expected = { a: null, b: undefined, c: null }; + assert.deepStrictEqual(func({ a: 1, b: 2 }, expected), expected); + }); + + it(`\`_.${methodName}\` should skip assignments if values are the same`, () => { + const object = {}; + + const descriptor = { + configurable: true, + enumerable: true, + set: function () { + throw new Error(); + }, + }; + + const source = { + a: 1, + b: undefined, + c: NaN, + d: undefined, + constructor: Object, + toString: lodashStable.constant('source'), + }; + + defineProperty( + object, + 'a', + lodashStable.assign({}, descriptor, { + get: stubOne, + }), + ); + + defineProperty( + object, + 'b', + lodashStable.assign({}, descriptor, { + get: noop, + }), + ); + + defineProperty( + object, + 'c', + lodashStable.assign({}, descriptor, { + get: stubNaN, + }), + ); + + defineProperty( + object, + 'constructor', + lodashStable.assign({}, descriptor, { + get: lodashStable.constant(Object), + }), + ); + + try { + var actual = func(object, source); + } catch (e) {} + + assert.deepStrictEqual(actual, source); + }); + + it(`\`_.${methodName}\` should treat sparse array sources as dense`, () => { + const array = [1]; + array[2] = 3; + + assert.deepStrictEqual(func({}, array), { '0': 1, '1': undefined, '2': 3 }); + }); + + it(`\`_.${methodName}\` should assign values of prototype objects`, () => { + function Foo() {} + Foo.prototype.a = 1; + + assert.deepStrictEqual(func({}, Foo.prototype), { a: 1 }); + }); + + it(`\`_.${methodName}\` should coerce string sources to objects`, () => { + assert.deepStrictEqual(func({}, 'a'), { '0': 'a' }); + }); + }); +}); diff --git a/test/assignIn.js b/test/assignIn.js deleted file mode 100644 index 03a93beab..000000000 --- a/test/assignIn.js +++ /dev/null @@ -1,9 +0,0 @@ -import assert from 'assert'; -import extend from '../extend.js'; -import assignIn from '../assignIn.js'; - -describe('assignIn', function() { - it('should be aliased', function() { - assert.strictEqual(extend, assignIn); - }); -}); diff --git a/test/assignIn.spec.ts b/test/assignIn.spec.ts new file mode 100644 index 000000000..254779ec4 --- /dev/null +++ b/test/assignIn.spec.ts @@ -0,0 +1,9 @@ +import assert from 'node:assert'; +import extend from '../src/extend'; +import assignIn from '../src/assignIn'; + +describe('assignIn', () => { + it('should be aliased', () => { + assert.strictEqual(extend, assignIn); + }); +}); diff --git a/test/assignInWith.js b/test/assignInWith.js deleted file mode 100644 index e253b3f1e..000000000 --- a/test/assignInWith.js +++ /dev/null @@ -1,9 +0,0 @@ -import assert from 'assert'; -import extendWith from '../extendWith.js'; -import assignInWith from '../assignInWith.js'; - -describe('assignInWith', function() { - it('should be aliased', function() { - assert.strictEqual(extendWith, assignInWith); - }); -}); diff --git a/test/assignInWith.spec.ts b/test/assignInWith.spec.ts new file mode 100644 index 000000000..4b3efe77c --- /dev/null +++ b/test/assignInWith.spec.ts @@ -0,0 +1,9 @@ +import assert from 'node:assert'; +import extendWith from '../src/extendWith'; +import assignInWith from '../src/assignInWith'; + +describe('assignInWith', () => { + it('should be aliased', () => { + assert.strictEqual(extendWith, assignInWith); + }); +}); diff --git a/test/assignWith-and-assignInWith.js b/test/assignWith-and-assignInWith.js deleted file mode 100644 index 70ec24a6b..000000000 --- a/test/assignWith-and-assignInWith.js +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, noop } from './utils.js'; - -describe('assignWith and assignInWith', function() { - lodashStable.each(['assignWith', 'assignInWith'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should work with a `customizer` callback', function() { - var actual = func({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) { - return a === undefined ? b : a; - }); - - assert.deepStrictEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); - }); - - it('`_.' + methodName + '` should work with a `customizer` that returns `undefined`', function() { - var expected = { 'a': 1 }; - assert.deepStrictEqual(func({}, expected, noop), expected); - }); - }); -}); diff --git a/test/assignWith-and-assignInWith.spec.ts b/test/assignWith-and-assignInWith.spec.ts new file mode 100644 index 000000000..cd18a4308 --- /dev/null +++ b/test/assignWith-and-assignInWith.spec.ts @@ -0,0 +1,22 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, noop } from './utils'; + +describe('assignWith and assignInWith', () => { + lodashStable.each(['assignWith', 'assignInWith'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should work with a \`customizer\` callback`, () => { + const actual = func({ a: 1, b: 2 }, { a: 3, c: 3 }, (a, b) => + a === undefined ? b : a, + ); + + assert.deepStrictEqual(actual, { a: 1, b: 2, c: 3 }); + }); + + it(`\`_.${methodName}\` should work with a \`customizer\` that returns \`undefined\``, () => { + const expected = { a: 1 }; + assert.deepStrictEqual(func({}, expected, noop), expected); + }); + }); +}); diff --git a/test/at.spec.ts b/test/at.spec.ts new file mode 100644 index 000000000..9ad130e2f --- /dev/null +++ b/test/at.spec.ts @@ -0,0 +1,131 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { empties, stubOne, falsey, args, LARGE_ARRAY_SIZE, square, identity } from './utils'; +import at from '../src/at'; + +describe('at', () => { + const array = ['a', 'b', 'c'], + object = { a: [{ b: { c: 3 } }, 4] }; + + it('should return the elements corresponding to the specified keys', () => { + const actual = at(array, [0, 2]); + assert.deepStrictEqual(actual, ['a', 'c']); + }); + + it('should return `undefined` for nonexistent keys', () => { + const actual = at(array, [2, 4, 0]); + assert.deepStrictEqual(actual, ['c', undefined, 'a']); + }); + + it('should work with non-index keys on array values', () => { + const values = lodashStable + .reject(empties, (value) => value === 0 || lodashStable.isArray(value)) + .concat(-1, 1.1); + + const array = lodashStable.transform( + values, + (result, value) => { + result[value] = 1; + }, + [], + ); + + const expected = lodashStable.map(values, stubOne), + actual = at(array, values); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return an empty array when no keys are given', () => { + assert.deepStrictEqual(at(array), []); + assert.deepStrictEqual(at(array, [], []), []); + }); + + it('should accept multiple key arguments', () => { + const actual = at(['a', 'b', 'c', 'd'], 3, 0, 2); + assert.deepStrictEqual(actual, ['d', 'a', 'c']); + }); + + it('should work with a falsey `object` when keys are given', () => { + const expected = lodashStable.map(falsey, lodashStable.constant(Array(4).fill(undefined))); + + const actual = lodashStable.map(falsey, (object) => { + try { + return at(object, 0, 1, 'pop', 'push'); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with an `arguments` object for `object`', () => { + const actual = at(args, [2, 0]); + assert.deepStrictEqual(actual, [3, 1]); + }); + + it('should work with `arguments` object as secondary arguments', () => { + const actual = at([1, 2, 3, 4, 5], args); + assert.deepStrictEqual(actual, [2, 3, 4]); + }); + + it('should work with an object for `object`', () => { + const actual = at(object, ['a[0].b.c', 'a[1]']); + assert.deepStrictEqual(actual, [3, 4]); + }); + + it('should pluck inherited property values', () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const actual = at(new Foo(), 'b'); + assert.deepStrictEqual(actual, [2]); + }); + + it('should work in a lazy sequence', () => { + const largeArray = lodashStable.range(LARGE_ARRAY_SIZE), + smallArray = array; + + lodashStable.each([[2], ['2'], [2, 1]], (paths) => { + lodashStable.times(2, (index) => { + const array = index ? largeArray : smallArray, + wrapped = _(array).map(identity).at(paths); + + assert.deepEqual(wrapped.value(), at(_.map(array, identity), paths)); + }); + }); + }); + + it('should support shortcut fusion', () => { + let array = lodashStable.range(LARGE_ARRAY_SIZE), + count = 0, + iteratee = function (value) { + count++; + return square(value); + }, + lastIndex = LARGE_ARRAY_SIZE - 1; + + lodashStable.each([lastIndex, `${lastIndex}`, LARGE_ARRAY_SIZE, []], (n, index) => { + count = 0; + let actual = _(array).map(iteratee).at(n).value(), + expected = index < 2 ? 1 : 0; + + assert.strictEqual(count, expected); + + expected = index == 3 ? [] : [index == 2 ? undefined : square(lastIndex)]; + assert.deepEqual(actual, expected); + }); + }); + + it('work with an object for `object` when chaining', () => { + let paths = ['a[0].b.c', 'a[1]'], + actual = _(object).map(identity).at(paths).value(); + + assert.deepEqual(actual, at(_.map(object, identity), paths)); + + const indexObject = { '0': 1 }; + actual = _(indexObject).at(0).value(); + assert.deepEqual(actual, at(indexObject, 0)); + }); +}); diff --git a/test/at.test.js b/test/at.test.js deleted file mode 100644 index c466829f2..000000000 --- a/test/at.test.js +++ /dev/null @@ -1,124 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { empties, stubOne, falsey, args, LARGE_ARRAY_SIZE, square, identity } from './utils.js'; -import at from '../at.js'; - -describe('at', function() { - var array = ['a', 'b', 'c'], - object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - - it('should return the elements corresponding to the specified keys', function() { - var actual = at(array, [0, 2]); - assert.deepStrictEqual(actual, ['a', 'c']); - }); - - it('should return `undefined` for nonexistent keys', function() { - var actual = at(array, [2, 4, 0]); - assert.deepStrictEqual(actual, ['c', undefined, 'a']); - }); - - it('should work with non-index keys on array values', function() { - var values = lodashStable.reject(empties, function(value) { - return (value === 0) || lodashStable.isArray(value); - }).concat(-1, 1.1); - - var array = lodashStable.transform(values, function(result, value) { - result[value] = 1; - }, []); - - var expected = lodashStable.map(values, stubOne), - actual = at(array, values); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return an empty array when no keys are given', function() { - assert.deepStrictEqual(at(array), []); - assert.deepStrictEqual(at(array, [], []), []); - }); - - it('should accept multiple key arguments', function() { - var actual = at(['a', 'b', 'c', 'd'], 3, 0, 2); - assert.deepStrictEqual(actual, ['d', 'a', 'c']); - }); - - it('should work with a falsey `object` when keys are given', function() { - var expected = lodashStable.map(falsey, lodashStable.constant(Array(4).fill(undefined))); - - var actual = lodashStable.map(falsey, function(object) { - try { - return at(object, 0, 1, 'pop', 'push'); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with an `arguments` object for `object`', function() { - var actual = at(args, [2, 0]); - assert.deepStrictEqual(actual, [3, 1]); - }); - - it('should work with `arguments` object as secondary arguments', function() { - var actual = at([1, 2, 3, 4, 5], args); - assert.deepStrictEqual(actual, [2, 3, 4]); - }); - - it('should work with an object for `object`', function() { - var actual = at(object, ['a[0].b.c', 'a[1]']); - assert.deepStrictEqual(actual, [3, 4]); - }); - - it('should pluck inherited property values', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var actual = at(new Foo, 'b'); - assert.deepStrictEqual(actual, [2]); - }); - - it('should work in a lazy sequence', function() { - var largeArray = lodashStable.range(LARGE_ARRAY_SIZE), - smallArray = array; - - lodashStable.each([[2], ['2'], [2, 1]], function(paths) { - lodashStable.times(2, function(index) { - var array = index ? largeArray : smallArray, - wrapped = _(array).map(identity).at(paths); - - assert.deepEqual(wrapped.value(), at(_.map(array, identity), paths)); - }); - }); - }); - - it('should support shortcut fusion', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE), - count = 0, - iteratee = function(value) { count++; return square(value); }, - lastIndex = LARGE_ARRAY_SIZE - 1; - - lodashStable.each([lastIndex, lastIndex + '', LARGE_ARRAY_SIZE, []], function(n, index) { - count = 0; - var actual = _(array).map(iteratee).at(n).value(), - expected = index < 2 ? 1 : 0; - - assert.strictEqual(count, expected); - - expected = index == 3 ? [] : [index == 2 ? undefined : square(lastIndex)]; - assert.deepEqual(actual, expected); - }); - }); - - it('work with an object for `object` when chaining', function() { - var paths = ['a[0].b.c', 'a[1]'], - actual = _(object).map(identity).at(paths).value(); - - assert.deepEqual(actual, at(_.map(object, identity), paths)); - - var indexObject = { '0': 1 }; - actual = _(indexObject).at(0).value(); - assert.deepEqual(actual, at(indexObject, 0)); - }); -}); diff --git a/test/attempt.spec.ts b/test/attempt.spec.ts new file mode 100644 index 000000000..dc58dd70e --- /dev/null +++ b/test/attempt.spec.ts @@ -0,0 +1,73 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, errors, stubTrue, CustomError, realm } from './utils'; +import attempt from '../src/attempt'; + +describe('attempt', () => { + it('should return the result of `func`', () => { + assert.strictEqual(attempt(lodashStable.constant('x')), 'x'); + }); + + it('should provide additional arguments to `func`', () => { + const actual = attempt( + function () { + return slice.call(arguments); + }, + 1, + 2, + ); + assert.deepStrictEqual(actual, [1, 2]); + }); + + it('should return the caught error', () => { + const expected = lodashStable.map(errors, stubTrue); + + const actual = lodashStable.map( + errors, + (error) => + attempt(() => { + throw error; + }) === error, + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should coerce errors to error objects', () => { + const actual = attempt(() => { + throw 'x'; + }); + assert.ok(lodashStable.isEqual(actual, Error('x'))); + }); + + it('should preserve custom errors', () => { + const actual = attempt(() => { + throw new CustomError('x'); + }); + assert.ok(actual instanceof CustomError); + }); + + it('should work with an error object from another realm', () => { + if (realm.errors) { + const expected = lodashStable.map(realm.errors, stubTrue); + + const actual = lodashStable.map( + realm.errors, + (error) => + attempt(() => { + throw error; + }) === error, + ); + + assert.deepStrictEqual(actual, expected); + } + }); + + it('should return an unwrapped value when implicitly chaining', () => { + assert.strictEqual(_(lodashStable.constant('x')).attempt(), 'x'); + }); + + it('should return a wrapped value when explicitly chaining', () => { + assert.ok(_(lodashStable.constant('x')).chain().attempt() instanceof _); + }); +}); diff --git a/test/attempt.test.js b/test/attempt.test.js deleted file mode 100644 index d453ce0ac..000000000 --- a/test/attempt.test.js +++ /dev/null @@ -1,55 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, errors, stubTrue, CustomError, realm } from './utils.js'; -import attempt from '../attempt.js'; - -describe('attempt', function() { - it('should return the result of `func`', function() { - assert.strictEqual(attempt(lodashStable.constant('x')), 'x'); - }); - - it('should provide additional arguments to `func`', function() { - var actual = attempt(function() { return slice.call(arguments); }, 1, 2); - assert.deepStrictEqual(actual, [1, 2]); - }); - - it('should return the caught error', function() { - var expected = lodashStable.map(errors, stubTrue); - - var actual = lodashStable.map(errors, function(error) { - return attempt(function() { throw error; }) === error; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should coerce errors to error objects', function() { - var actual = attempt(function() { throw 'x'; }); - assert.ok(lodashStable.isEqual(actual, Error('x'))); - }); - - it('should preserve custom errors', function() { - var actual = attempt(function() { throw new CustomError('x'); }); - assert.ok(actual instanceof CustomError); - }); - - it('should work with an error object from another realm', function() { - if (realm.errors) { - var expected = lodashStable.map(realm.errors, stubTrue); - - var actual = lodashStable.map(realm.errors, function(error) { - return attempt(function() { throw error; }) === error; - }); - - assert.deepStrictEqual(actual, expected); - } - }); - - it('should return an unwrapped value when implicitly chaining', function() { - assert.strictEqual(_(lodashStable.constant('x')).attempt(), 'x'); - }); - - it('should return a wrapped value when explicitly chaining', function() { - assert.ok(_(lodashStable.constant('x')).chain().attempt() instanceof _); - }); -}); diff --git a/test/basename.js b/test/basename.js deleted file mode 100644 index e60f93796..000000000 --- a/test/basename.js +++ /dev/null @@ -1,151 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - basename, - amd, - ui, - Worker, - QUnit, - lodashBizarro, - LARGE_ARRAY_SIZE, - symbol, - setProperty, -} from './utils.js'; - -import _VERSION from '../.internal/VERSION.js'; -import VERSION from '../VERSION.js'; - -describe(basename, function() { - it('should support loading ' + basename + ' as the "lodash" module', function() { - if (amd) { - assert.strictEqual((lodashModule || {}).moduleName, 'lodash'); - } - }); - - it('should support loading ' + basename + ' with the Require.js "shim" configuration option', function() { - if (amd && lodashStable.includes(ui.loaderPath, 'requirejs')) { - assert.strictEqual((shimmedModule || {}).moduleName, 'shimmed'); - } - }); - - it('should support loading ' + basename + ' as the "underscore" module', function() { - if (amd) { - assert.strictEqual((underscoreModule || {}).moduleName, 'underscore'); - } - }); - - it('should support loading ' + basename + ' in a web worker', function(done) { - if (Worker) { - var limit = 30000 / QUnit.config.asyncRetries, - start = +new Date; - - var attempt = function() { - var actual = _VERSION; - if ((new Date - start) < limit && typeof actual !== 'string') { - setTimeout(attempt, 16); - return; - } - assert.strictEqual(actual, VERSION); - done(); - }; - - attempt(); - } - else { - done(); - } - }); - - it('should not add `Function.prototype` extensions to lodash', function() { - if (lodashBizarro) { - assert.ok(!('_method' in lodashBizarro)); - } - }); - - it('should avoid non-native built-ins', function() { - function message(lodashMethod, nativeMethod) { - return '`' + lodashMethod + '` should avoid overwritten native `' + nativeMethod + '`'; - } - - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var object = { 'a': 1 }, - otherObject = { 'b': 2 }, - largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object)); - - if (lodashBizarro) { - try { - var actual = lodashBizarro.create(Foo.prototype); - } catch (e) { - actual = null; - } - var label = message('_.create', 'Object.create'); - assert.ok(actual instanceof Foo, label); - - try { - actual = [ - lodashBizarro.difference([object, otherObject], largeArray), - lodashBizarro.intersection(largeArray, [object]), - lodashBizarro.uniq(largeArray) - ]; - } catch (e) { - actual = null; - } - label = message('_.difference`, `_.intersection`, and `_.uniq', 'Map'); - assert.deepStrictEqual(actual, [[otherObject], [object], [object]], label); - - try { - if (Symbol) { - object[symbol] = {}; - } - actual = [ - lodashBizarro.clone(object), - lodashBizarro.cloneDeep(object) - ]; - } catch (e) { - actual = null; - } - label = message('_.clone` and `_.cloneDeep', 'Object.getOwnPropertySymbols'); - assert.deepStrictEqual(actual, [object, object], label); - - try { - // Avoid buggy symbol detection in Babel's `_typeof` helper. - var symObject = setProperty(Object(symbol), 'constructor', Object); - actual = [ - Symbol ? lodashBizarro.clone(symObject) : {}, - Symbol ? lodashBizarro.isEqual(symObject, Object(symbol)) : false, - Symbol ? lodashBizarro.toString(symObject) : '' - ]; - } catch (e) { - actual = null; - } - label = message('_.clone`, `_.isEqual`, and `_.toString', 'Symbol'); - assert.deepStrictEqual(actual, [{}, false, ''], label); - - try { - var map = new lodashBizarro.memoize.Cache; - actual = map.set('a', 1).get('a'); - } catch (e) { - actual = null; - } - label = message('_.memoize.Cache', 'Map'); - assert.deepStrictEqual(actual, 1, label); - - try { - map = new (Map || Object); - if (Symbol && Symbol.iterator) { - map[Symbol.iterator] = null; - } - actual = lodashBizarro.toArray(map); - } catch (e) { - actual = null; - } - label = message('_.toArray', 'Map'); - assert.deepStrictEqual(actual, [], label); - } - }); -}); diff --git a/test/basename.spec.ts b/test/basename.spec.ts new file mode 100644 index 000000000..7ed8cb991 --- /dev/null +++ b/test/basename.spec.ts @@ -0,0 +1,147 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + basename, + amd, + ui, + Worker, + QUnit, + lodashBizarro, + LARGE_ARRAY_SIZE, + symbol, + setProperty, +} from './utils'; + +import _VERSION from '../.internal/VERSION'; +import VERSION from '../src/VERSION'; + +describe(basename, () => { + it(`should support loading ${basename} as the "lodash" module`, () => { + if (amd) { + assert.strictEqual((lodashModule || {}).moduleName, 'lodash'); + } + }); + + it(`should support loading ${basename} with the Require.js "shim" configuration option`, () => { + if (amd && lodashStable.includes(ui.loaderPath, 'requirejs')) { + assert.strictEqual((shimmedModule || {}).moduleName, 'shimmed'); + } + }); + + it(`should support loading ${basename} as the "underscore" module`, () => { + if (amd) { + assert.strictEqual((underscoreModule || {}).moduleName, 'underscore'); + } + }); + + it(`should support loading ${basename} in a web worker`, (done) => { + if (Worker) { + const limit = 30000 / QUnit.config.asyncRetries, + start = +new Date(); + + const attempt = function () { + const actual = _VERSION; + if (new Date() - start < limit && typeof actual !== 'string') { + setTimeout(attempt, 16); + return; + } + assert.strictEqual(actual, VERSION); + done(); + }; + + attempt(); + } else { + done(); + } + }); + + it('should not add `Function.prototype` extensions to lodash', () => { + if (lodashBizarro) { + assert.ok(!('_method' in lodashBizarro)); + } + }); + + it('should avoid non-native built-ins', () => { + function message(lodashMethod, nativeMethod) { + return `\`${lodashMethod}\` should avoid overwritten native \`${nativeMethod}\``; + } + + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const object = { a: 1 }, + otherObject = { b: 2 }, + largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object)); + + if (lodashBizarro) { + try { + var actual = lodashBizarro.create(Foo.prototype); + } catch (e) { + actual = null; + } + let label = message('_.create', 'Object.create'); + assert.ok(actual instanceof Foo, label); + + try { + actual = [ + lodashBizarro.difference([object, otherObject], largeArray), + lodashBizarro.intersection(largeArray, [object]), + lodashBizarro.uniq(largeArray), + ]; + } catch (e) { + actual = null; + } + label = message('_.difference`, `_.intersection`, and `_.uniq', 'Map'); + assert.deepStrictEqual(actual, [[otherObject], [object], [object]], label); + + try { + if (Symbol) { + object[symbol] = {}; + } + actual = [lodashBizarro.clone(object), lodashBizarro.cloneDeep(object)]; + } catch (e) { + actual = null; + } + label = message('_.clone` and `_.cloneDeep', 'Object.getOwnPropertySymbols'); + assert.deepStrictEqual(actual, [object, object], label); + + try { + // Avoid buggy symbol detection in Babel's `_typeof` helper. + const symObject = setProperty(Object(symbol), 'constructor', Object); + actual = [ + Symbol ? lodashBizarro.clone(symObject) : {}, + Symbol ? lodashBizarro.isEqual(symObject, Object(symbol)) : false, + Symbol ? lodashBizarro.toString(symObject) : '', + ]; + } catch (e) { + actual = null; + } + label = message('_.clone`, `_.isEqual`, and `_.toString', 'Symbol'); + assert.deepStrictEqual(actual, [{}, false, ''], label); + + try { + var map = new lodashBizarro.memoize.Cache(); + actual = map.set('a', 1).get('a'); + } catch (e) { + actual = null; + } + label = message('_.memoize.Cache', 'Map'); + assert.deepStrictEqual(actual, 1, label); + + try { + map = new (Map || Object)(); + if (Symbol && Symbol.iterator) { + map[Symbol.iterator] = null; + } + actual = lodashBizarro.toArray(map); + } catch (e) { + actual = null; + } + label = message('_.toArray', 'Map'); + assert.deepStrictEqual(actual, [], label); + } + }); +}); diff --git a/test/before.js b/test/before.js deleted file mode 100644 index d1a678b1e..000000000 --- a/test/before.js +++ /dev/null @@ -1,31 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('before', function() { - function before(n, times) { - var count = 0; - lodashStable.times(times, _.before(n, function() { count++; })); - return count; - } - - it('should create a function that invokes `func` after `n` calls', function() { - assert.strictEqual(before(5, 4), 4, 'before(n) should invoke `func` before being called `n` times'); - assert.strictEqual(before(5, 6), 4, 'before(n) should not invoke `func` after being called `n - 1` times'); - assert.strictEqual(before(0, 0), 0, 'before(0) should not invoke `func` immediately'); - assert.strictEqual(before(0, 1), 0, 'before(0) should not invoke `func` when called'); - }); - - it('should coerce `n` values of `NaN` to `0`', function() { - assert.strictEqual(before(NaN, 1), 0); - }); - - it('should use `this` binding of function', function() { - var before = _.before(2, function() { return ++this.count; }), - object = { 'before': before, 'count': 0 }; - - object.before(); - assert.strictEqual(object.before(), 1); - assert.strictEqual(object.count, 1); - }); -}); diff --git a/test/before.spec.ts b/test/before.spec.ts new file mode 100644 index 000000000..408f12d6e --- /dev/null +++ b/test/before.spec.ts @@ -0,0 +1,46 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('before', () => { + function before(n, times) { + let count = 0; + lodashStable.times( + times, + _.before(n, () => { + count++; + }), + ); + return count; + } + + it('should create a function that invokes `func` after `n` calls', () => { + assert.strictEqual( + before(5, 4), + 4, + 'before(n) should invoke `func` before being called `n` times', + ); + assert.strictEqual( + before(5, 6), + 4, + 'before(n) should not invoke `func` after being called `n - 1` times', + ); + assert.strictEqual(before(0, 0), 0, 'before(0) should not invoke `func` immediately'); + assert.strictEqual(before(0, 1), 0, 'before(0) should not invoke `func` when called'); + }); + + it('should coerce `n` values of `NaN` to `0`', () => { + assert.strictEqual(before(NaN, 1), 0); + }); + + it('should use `this` binding of function', () => { + const before = _.before(2, function () { + return ++this.count; + }), + object = { before: before, count: 0 }; + + object.before(); + assert.strictEqual(object.before(), 1); + assert.strictEqual(object.count, 1); + }); +}); diff --git a/test/bind.js b/test/bind.js deleted file mode 100644 index 384ddd9b3..000000000 --- a/test/bind.js +++ /dev/null @@ -1,231 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { push, falsey, stubTrue } from './utils.js'; -import bind from '../bind.js'; -import placeholder from '../placeholder.js'; - -describe('bind', function() { - function fn() { - var result = [this]; - push.apply(result, arguments); - return result; - } - - it('should bind a function to an object', function() { - var object = {}, - bound = bind(fn, object); - - assert.deepStrictEqual(bound('a'), [object, 'a']); - }); - - it('should accept a falsey `thisArg`', function() { - var values = lodashStable.reject(falsey.slice(1), function(value) { return value == null; }), - expected = lodashStable.map(values, function(value) { return [value]; }); - - var actual = lodashStable.map(values, function(value) { - try { - var bound = bind(fn, value); - return bound(); - } catch (e) {} - }); - - assert.ok(lodashStable.every(actual, function(value, index) { - return lodashStable.isEqual(value, expected[index]); - })); - }); - - it('should bind a function to nullish values', function() { - var bound = bind(fn, null), - actual = bound('a'); - - assert.ok((actual[0] === null) || (actual[0] && actual[0].Array)); - assert.strictEqual(actual[1], 'a'); - - lodashStable.times(2, function(index) { - bound = index ? bind(fn, undefined) : bind(fn); - actual = bound('b'); - - assert.ok((actual[0] === undefined) || (actual[0] && actual[0].Array)); - assert.strictEqual(actual[1], 'b'); - }); - }); - - it('should partially apply arguments ', function() { - var object = {}, - bound = bind(fn, object, 'a'); - - assert.deepStrictEqual(bound(), [object, 'a']); - - bound = bind(fn, object, 'a'); - assert.deepStrictEqual(bound('b'), [object, 'a', 'b']); - - bound = bind(fn, object, 'a', 'b'); - assert.deepStrictEqual(bound(), [object, 'a', 'b']); - assert.deepStrictEqual(bound('c', 'd'), [object, 'a', 'b', 'c', 'd']); - }); - - it('should support placeholders', function() { - var object = {}, - ph = bind.placeholder, - bound = bind(fn, object, ph, 'b', ph); - - assert.deepStrictEqual(bound('a', 'c'), [object, 'a', 'b', 'c']); - assert.deepStrictEqual(bound('a'), [object, 'a', 'b', undefined]); - assert.deepStrictEqual(bound('a', 'c', 'd'), [object, 'a', 'b', 'c', 'd']); - assert.deepStrictEqual(bound(), [object, undefined, 'b', undefined]); - }); - - it('should use `_.placeholder` when set', function() { - var _ph = placeholder = {}, - ph = bind.placeholder, - object = {}, - bound = bind(fn, object, _ph, 'b', ph); - - assert.deepEqual(bound('a', 'c'), [object, 'a', 'b', ph, 'c']); - delete placeholder; - }); - - it('should create a function with a `length` of `0`', function() { - var fn = function(a, b, c) {}, - bound = bind(fn, {}); - - assert.strictEqual(bound.length, 0); - - bound = bind(fn, {}, 1); - assert.strictEqual(bound.length, 0); - }); - - it('should ignore binding when called with the `new` operator', function() { - function Foo() { - return this; - } - - var bound = bind(Foo, { 'a': 1 }), - newBound = new bound; - - assert.strictEqual(bound().a, 1); - assert.strictEqual(newBound.a, undefined); - assert.ok(newBound instanceof Foo); - }); - - it('should handle a number of arguments when called with the `new` operator', function() { - function Foo() { - return this; - } - - function Bar() {} - - var thisArg = { 'a': 1 }, - boundFoo = bind(Foo, thisArg), - boundBar = bind(Bar, thisArg), - count = 9, - expected = lodashStable.times(count, lodashStable.constant([undefined, undefined])); - - var actual = lodashStable.times(count, function(index) { - try { - switch (index) { - case 0: return [new boundFoo().a, new boundBar().a]; - case 1: return [new boundFoo(1).a, new boundBar(1).a]; - case 2: return [new boundFoo(1, 2).a, new boundBar(1, 2).a]; - case 3: return [new boundFoo(1, 2, 3).a, new boundBar(1, 2, 3).a]; - case 4: return [new boundFoo(1, 2, 3, 4).a, new boundBar(1, 2, 3, 4).a]; - case 5: return [new boundFoo(1, 2, 3, 4, 5).a, new boundBar(1, 2, 3, 4, 5).a]; - case 6: return [new boundFoo(1, 2, 3, 4, 5, 6).a, new boundBar(1, 2, 3, 4, 5, 6).a]; - case 7: return [new boundFoo(1, 2, 3, 4, 5, 6, 7).a, new boundBar(1, 2, 3, 4, 5, 6, 7).a]; - case 8: return [new boundFoo(1, 2, 3, 4, 5, 6, 7, 8).a, new boundBar(1, 2, 3, 4, 5, 6, 7, 8).a]; - } - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should ensure `new bound` is an instance of `func`', function() { - function Foo(value) { - return value && object; - } - - var bound = bind(Foo), - object = {}; - - assert.ok(new bound instanceof Foo); - assert.strictEqual(new bound(true), object); - }); - - it('should append array arguments to partially applied arguments', function() { - var object = {}, - bound = bind(fn, object, 'a'); - - assert.deepStrictEqual(bound(['b'], 'c'), [object, 'a', ['b'], 'c']); - }); - - it('should not rebind functions', function() { - var object1 = {}, - object2 = {}, - object3 = {}; - - var bound1 = bind(fn, object1), - bound2 = bind(bound1, object2, 'a'), - bound3 = bind(bound1, object3, 'b'); - - assert.deepStrictEqual(bound1(), [object1]); - assert.deepStrictEqual(bound2(), [object1, 'a']); - assert.deepStrictEqual(bound3(), [object1, 'b']); - }); - - it('should not error when instantiating bound built-ins', function() { - var Ctor = bind(Date, null), - expected = new Date(2012, 4, 23, 0, 0, 0, 0); - - try { - var actual = new Ctor(2012, 4, 23, 0, 0, 0, 0); - } catch (e) {} - - assert.deepStrictEqual(actual, expected); - - Ctor = bind(Date, null, 2012, 4, 23); - - try { - actual = new Ctor(0, 0, 0, 0); - } catch (e) {} - - assert.deepStrictEqual(actual, expected); - }); - - it('should not error when calling bound class constructors with the `new` operator', function() { - var createCtor = lodashStable.attempt(Function, '"use strict";return class A{}'); - - if (typeof createCtor === 'function') { - var bound = bind(createCtor()), - count = 8, - expected = lodashStable.times(count, stubTrue); - - var actual = lodashStable.times(count, function(index) { - try { - switch (index) { - case 0: return !!(new bound); - case 1: return !!(new bound(1)); - case 2: return !!(new bound(1, 2)); - case 3: return !!(new bound(1, 2, 3)); - case 4: return !!(new bound(1, 2, 3, 4)); - case 5: return !!(new bound(1, 2, 3, 4, 5)); - case 6: return !!(new bound(1, 2, 3, 4, 5, 6)); - case 7: return !!(new bound(1, 2, 3, 4, 5, 6, 7)); - } - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - } - }); - - it('should return a wrapped value when chaining', function() { - var object = {}, - bound = _(fn).bind({}, 'a', 'b'); - - assert.ok(bound instanceof _); - - var actual = bound.value()('c'); - assert.deepEqual(actual, [object, 'a', 'b', 'c']); - }); -}); diff --git a/test/bind.spec.ts b/test/bind.spec.ts new file mode 100644 index 000000000..e652246cd --- /dev/null +++ b/test/bind.spec.ts @@ -0,0 +1,256 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { push, falsey, stubTrue } from './utils'; +import bind from '../src/bind'; +import placeholder from '../src/placeholder'; + +describe('bind', () => { + function fn() { + const result = [this]; + push.apply(result, arguments); + return result; + } + + it('should bind a function to an object', () => { + const object = {}, + bound = bind(fn, object); + + assert.deepStrictEqual(bound('a'), [object, 'a']); + }); + + it('should accept a falsey `thisArg`', () => { + const values = lodashStable.reject(falsey.slice(1), (value) => value == null), + expected = lodashStable.map(values, (value) => [value]); + + const actual = lodashStable.map(values, (value) => { + try { + const bound = bind(fn, value); + return bound(); + } catch (e) {} + }); + + assert.ok( + lodashStable.every(actual, (value, index) => + lodashStable.isEqual(value, expected[index]), + ), + ); + }); + + it('should bind a function to nullish values', () => { + let bound = bind(fn, null), + actual = bound('a'); + + assert.ok(actual[0] === null || (actual[0] && actual[0].Array)); + assert.strictEqual(actual[1], 'a'); + + lodashStable.times(2, (index) => { + bound = index ? bind(fn, undefined) : bind(fn); + actual = bound('b'); + + assert.ok(actual[0] === undefined || (actual[0] && actual[0].Array)); + assert.strictEqual(actual[1], 'b'); + }); + }); + + it('should partially apply arguments ', () => { + let object = {}, + bound = bind(fn, object, 'a'); + + assert.deepStrictEqual(bound(), [object, 'a']); + + bound = bind(fn, object, 'a'); + assert.deepStrictEqual(bound('b'), [object, 'a', 'b']); + + bound = bind(fn, object, 'a', 'b'); + assert.deepStrictEqual(bound(), [object, 'a', 'b']); + assert.deepStrictEqual(bound('c', 'd'), [object, 'a', 'b', 'c', 'd']); + }); + + it('should support placeholders', () => { + const object = {}, + ph = bind.placeholder, + bound = bind(fn, object, ph, 'b', ph); + + assert.deepStrictEqual(bound('a', 'c'), [object, 'a', 'b', 'c']); + assert.deepStrictEqual(bound('a'), [object, 'a', 'b', undefined]); + assert.deepStrictEqual(bound('a', 'c', 'd'), [object, 'a', 'b', 'c', 'd']); + assert.deepStrictEqual(bound(), [object, undefined, 'b', undefined]); + }); + + it('should use `_.placeholder` when set', () => { + const _ph = (placeholder = {}), + ph = bind.placeholder, + object = {}, + bound = bind(fn, object, _ph, 'b', ph); + + assert.deepEqual(bound('a', 'c'), [object, 'a', 'b', ph, 'c']); + delete placeholder; + }); + + it('should create a function with a `length` of `0`', () => { + let fn = function (a, b, c) {}, + bound = bind(fn, {}); + + assert.strictEqual(bound.length, 0); + + bound = bind(fn, {}, 1); + assert.strictEqual(bound.length, 0); + }); + + it('should ignore binding when called with the `new` operator', () => { + function Foo() { + return this; + } + + const bound = bind(Foo, { a: 1 }), + newBound = new bound(); + + assert.strictEqual(bound().a, 1); + assert.strictEqual(newBound.a, undefined); + assert.ok(newBound instanceof Foo); + }); + + it('should handle a number of arguments when called with the `new` operator', () => { + function Foo() { + return this; + } + + function Bar() {} + + const thisArg = { a: 1 }, + boundFoo = bind(Foo, thisArg), + boundBar = bind(Bar, thisArg), + count = 9, + expected = lodashStable.times(count, lodashStable.constant([undefined, undefined])); + + const actual = lodashStable.times(count, (index) => { + try { + switch (index) { + case 0: + return [new boundFoo().a, new boundBar().a]; + case 1: + return [new boundFoo(1).a, new boundBar(1).a]; + case 2: + return [new boundFoo(1, 2).a, new boundBar(1, 2).a]; + case 3: + return [new boundFoo(1, 2, 3).a, new boundBar(1, 2, 3).a]; + case 4: + return [new boundFoo(1, 2, 3, 4).a, new boundBar(1, 2, 3, 4).a]; + case 5: + return [new boundFoo(1, 2, 3, 4, 5).a, new boundBar(1, 2, 3, 4, 5).a]; + case 6: + return [new boundFoo(1, 2, 3, 4, 5, 6).a, new boundBar(1, 2, 3, 4, 5, 6).a]; + case 7: + return [ + new boundFoo(1, 2, 3, 4, 5, 6, 7).a, + new boundBar(1, 2, 3, 4, 5, 6, 7).a, + ]; + case 8: + return [ + new boundFoo(1, 2, 3, 4, 5, 6, 7, 8).a, + new boundBar(1, 2, 3, 4, 5, 6, 7, 8).a, + ]; + } + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should ensure `new bound` is an instance of `func`', () => { + function Foo(value) { + return value && object; + } + + var bound = bind(Foo), + object = {}; + + assert.ok(new bound() instanceof Foo); + assert.strictEqual(new bound(true), object); + }); + + it('should append array arguments to partially applied arguments', () => { + const object = {}, + bound = bind(fn, object, 'a'); + + assert.deepStrictEqual(bound(['b'], 'c'), [object, 'a', ['b'], 'c']); + }); + + it('should not rebind functions', () => { + const object1 = {}, + object2 = {}, + object3 = {}; + + const bound1 = bind(fn, object1), + bound2 = bind(bound1, object2, 'a'), + bound3 = bind(bound1, object3, 'b'); + + assert.deepStrictEqual(bound1(), [object1]); + assert.deepStrictEqual(bound2(), [object1, 'a']); + assert.deepStrictEqual(bound3(), [object1, 'b']); + }); + + it('should not error when instantiating bound built-ins', () => { + let Ctor = bind(Date, null), + expected = new Date(2012, 4, 23, 0, 0, 0, 0); + + try { + var actual = new Ctor(2012, 4, 23, 0, 0, 0, 0); + } catch (e) {} + + assert.deepStrictEqual(actual, expected); + + Ctor = bind(Date, null, 2012, 4, 23); + + try { + actual = new Ctor(0, 0, 0, 0); + } catch (e) {} + + assert.deepStrictEqual(actual, expected); + }); + + it('should not error when calling bound class constructors with the `new` operator', () => { + const createCtor = lodashStable.attempt(Function, '"use strict";return class A{}'); + + if (typeof createCtor === 'function') { + const bound = bind(createCtor()), + count = 8, + expected = lodashStable.times(count, stubTrue); + + const actual = lodashStable.times(count, (index) => { + try { + switch (index) { + case 0: + return !!new bound(); + case 1: + return !!new bound(1); + case 2: + return !!new bound(1, 2); + case 3: + return !!new bound(1, 2, 3); + case 4: + return !!new bound(1, 2, 3, 4); + case 5: + return !!new bound(1, 2, 3, 4, 5); + case 6: + return !!new bound(1, 2, 3, 4, 5, 6); + case 7: + return !!new bound(1, 2, 3, 4, 5, 6, 7); + } + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + } + }); + + it('should return a wrapped value when chaining', () => { + const object = {}, + bound = _(fn).bind({}, 'a', 'b'); + + assert.ok(bound instanceof _); + + const actual = bound.value()('c'); + assert.deepEqual(actual, [object, 'a', 'b', 'c']); + }); +}); diff --git a/test/bindAll.js b/test/bindAll.js deleted file mode 100644 index a085bd97b..000000000 --- a/test/bindAll.js +++ /dev/null @@ -1,74 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, toArgs, arrayProto } from './utils.js'; -import bindAll from '../bindAll.js'; - -describe('bindAll', function() { - var args = toArgs(['a']); - - var source = { - '_n0': -2, - '_p0': -1, - '_a': 1, - '_b': 2, - '_c': 3, - '_d': 4, - '-0': function() { return this._n0; }, - '0': function() { return this._p0; }, - 'a': function() { return this._a; }, - 'b': function() { return this._b; }, - 'c': function() { return this._c; }, - 'd': function() { return this._d; } - }; - - it('should accept individual method names', function() { - var object = lodashStable.cloneDeep(source); - bindAll(object, 'a', 'b'); - - var actual = lodashStable.map(['a', 'b', 'c'], function(key) { - return object[key].call({}); - }); - - assert.deepStrictEqual(actual, [1, 2, undefined]); - }); - - it('should accept arrays of method names', function() { - var object = lodashStable.cloneDeep(source); - bindAll(object, ['a', 'b'], ['c']); - - var actual = lodashStable.map(['a', 'b', 'c', 'd'], function(key) { - return object[key].call({}); - }); - - assert.deepStrictEqual(actual, [1, 2, 3, undefined]); - }); - - it('should preserve the sign of `0`', function() { - var props = [-0, Object(-0), 0, Object(0)]; - - var actual = lodashStable.map(props, function(key) { - var object = lodashStable.cloneDeep(source); - bindAll(object, key); - return object[lodashStable.toString(key)].call({}); - }); - - assert.deepStrictEqual(actual, [-2, -2, -1, -1]); - }); - - it('should work with an array `object`', function() { - var array = ['push', 'pop']; - bindAll(array); - assert.strictEqual(array.pop, arrayProto.pop); - }); - - it('should work with `arguments` objects as secondary arguments', function() { - var object = lodashStable.cloneDeep(source); - bindAll(object, args); - - var actual = lodashStable.map(args, function(key) { - return object[key].call({}); - }); - - assert.deepStrictEqual(actual, [1]); - }); -}); diff --git a/test/bindAll.spec.ts b/test/bindAll.spec.ts new file mode 100644 index 000000000..e9cc93c1a --- /dev/null +++ b/test/bindAll.spec.ts @@ -0,0 +1,80 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, toArgs, arrayProto } from './utils'; +import bindAll from '../src/bindAll'; + +describe('bindAll', () => { + const args = toArgs(['a']); + + const source = { + _n0: -2, + _p0: -1, + _a: 1, + _b: 2, + _c: 3, + _d: 4, + '-0': function () { + return this._n0; + }, + '0': function () { + return this._p0; + }, + a: function () { + return this._a; + }, + b: function () { + return this._b; + }, + c: function () { + return this._c; + }, + d: function () { + return this._d; + }, + }; + + it('should accept individual method names', () => { + const object = lodashStable.cloneDeep(source); + bindAll(object, 'a', 'b'); + + const actual = lodashStable.map(['a', 'b', 'c'], (key) => object[key].call({})); + + assert.deepStrictEqual(actual, [1, 2, undefined]); + }); + + it('should accept arrays of method names', () => { + const object = lodashStable.cloneDeep(source); + bindAll(object, ['a', 'b'], ['c']); + + const actual = lodashStable.map(['a', 'b', 'c', 'd'], (key) => object[key].call({})); + + assert.deepStrictEqual(actual, [1, 2, 3, undefined]); + }); + + it('should preserve the sign of `0`', () => { + const props = [-0, Object(-0), 0, Object(0)]; + + const actual = lodashStable.map(props, (key) => { + const object = lodashStable.cloneDeep(source); + bindAll(object, key); + return object[lodashStable.toString(key)].call({}); + }); + + assert.deepStrictEqual(actual, [-2, -2, -1, -1]); + }); + + it('should work with an array `object`', () => { + const array = ['push', 'pop']; + bindAll(array); + assert.strictEqual(array.pop, arrayProto.pop); + }); + + it('should work with `arguments` objects as secondary arguments', () => { + const object = lodashStable.cloneDeep(source); + bindAll(object, args); + + const actual = lodashStable.map(args, (key) => object[key].call({})); + + assert.deepStrictEqual(actual, [1]); + }); +}); diff --git a/test/bindKey.js b/test/bindKey.js deleted file mode 100644 index 1489f30d3..000000000 --- a/test/bindKey.js +++ /dev/null @@ -1,66 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import bindKey from '../bindKey.js'; - -describe('bindKey', function() { - it('should work when the target function is overwritten', function() { - var object = { - 'user': 'fred', - 'greet': function(greeting) { - return this.user + ' says: ' + greeting; - } - }; - - var bound = bindKey(object, 'greet', 'hi'); - assert.strictEqual(bound(), 'fred says: hi'); - - object.greet = function(greeting) { - return this.user + ' says: ' + greeting + '!'; - }; - - assert.strictEqual(bound(), 'fred says: hi!'); - }); - - it('should support placeholders', function() { - var object = { - 'fn': function() { - return slice.call(arguments); - } - }; - - var ph = bindKey.placeholder, - bound = bindKey(object, 'fn', ph, 'b', ph); - - assert.deepStrictEqual(bound('a', 'c'), ['a', 'b', 'c']); - assert.deepStrictEqual(bound('a'), ['a', 'b', undefined]); - assert.deepStrictEqual(bound('a', 'c', 'd'), ['a', 'b', 'c', 'd']); - assert.deepStrictEqual(bound(), [undefined, 'b', undefined]); - }); - - it('should use `_.placeholder` when set', function() { - var object = { - 'fn': function() { - return slice.call(arguments); - } - }; - - var _ph = _.placeholder = {}, - ph = bindKey.placeholder, - bound = bindKey(object, 'fn', _ph, 'b', ph); - - assert.deepEqual(bound('a', 'c'), ['a', 'b', ph, 'c']); - delete _.placeholder; - }); - - it('should ensure `new bound` is an instance of `object[key]`', function() { - function Foo(value) { - return value && object; - } - - var object = { 'Foo': Foo }, - bound = bindKey(object, 'Foo'); - - assert.ok(new bound instanceof Foo); - assert.strictEqual(new bound(true), object); - }); -}); diff --git a/test/bindKey.spec.ts b/test/bindKey.spec.ts new file mode 100644 index 000000000..42d91e7cb --- /dev/null +++ b/test/bindKey.spec.ts @@ -0,0 +1,66 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import bindKey from '../src/bindKey'; + +describe('bindKey', () => { + it('should work when the target function is overwritten', () => { + const object = { + user: 'fred', + greet: function (greeting) { + return `${this.user} says: ${greeting}`; + }, + }; + + const bound = bindKey(object, 'greet', 'hi'); + assert.strictEqual(bound(), 'fred says: hi'); + + object.greet = function (greeting) { + return `${this.user} says: ${greeting}!`; + }; + + assert.strictEqual(bound(), 'fred says: hi!'); + }); + + it('should support placeholders', () => { + const object = { + fn: function () { + return slice.call(arguments); + }, + }; + + const ph = bindKey.placeholder, + bound = bindKey(object, 'fn', ph, 'b', ph); + + assert.deepStrictEqual(bound('a', 'c'), ['a', 'b', 'c']); + assert.deepStrictEqual(bound('a'), ['a', 'b', undefined]); + assert.deepStrictEqual(bound('a', 'c', 'd'), ['a', 'b', 'c', 'd']); + assert.deepStrictEqual(bound(), [undefined, 'b', undefined]); + }); + + it('should use `_.placeholder` when set', () => { + const object = { + fn: function () { + return slice.call(arguments); + }, + }; + + const _ph = (_.placeholder = {}), + ph = bindKey.placeholder, + bound = bindKey(object, 'fn', _ph, 'b', ph); + + assert.deepEqual(bound('a', 'c'), ['a', 'b', ph, 'c']); + delete _.placeholder; + }); + + it('should ensure `new bound` is an instance of `object[key]`', () => { + function Foo(value) { + return value && object; + } + + var object = { Foo: Foo }, + bound = bindKey(object, 'Foo'); + + assert.ok(new bound() instanceof Foo); + assert.strictEqual(new bound(true), object); + }); +}); diff --git a/test/camelCase.spec.ts b/test/camelCase.spec.ts new file mode 100644 index 000000000..832c44f49 --- /dev/null +++ b/test/camelCase.spec.ts @@ -0,0 +1,28 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import camelCase from '../src/camelCase'; + +describe('camelCase', () => { + it('should work with numbers', () => { + assert.strictEqual(camelCase('12 feet'), '12Feet'); + assert.strictEqual(camelCase('enable 6h format'), 'enable6HFormat'); + assert.strictEqual(camelCase('enable 24H format'), 'enable24HFormat'); + assert.strictEqual(camelCase('too legit 2 quit'), 'tooLegit2Quit'); + assert.strictEqual(camelCase('walk 500 miles'), 'walk500Miles'); + assert.strictEqual(camelCase('xhr2 request'), 'xhr2Request'); + }); + + it('should handle acronyms', () => { + lodashStable.each(['safe HTML', 'safeHTML'], (string) => { + assert.strictEqual(camelCase(string), 'safeHtml'); + }); + + lodashStable.each(['escape HTML entities', 'escapeHTMLEntities'], (string) => { + assert.strictEqual(camelCase(string), 'escapeHtmlEntities'); + }); + + lodashStable.each(['XMLHttpRequest', 'XmlHTTPRequest'], (string) => { + assert.strictEqual(camelCase(string), 'xmlHttpRequest'); + }); + }); +}); diff --git a/test/camelCase.test.js b/test/camelCase.test.js deleted file mode 100644 index 89a36b02c..000000000 --- a/test/camelCase.test.js +++ /dev/null @@ -1,28 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import camelCase from '../camelCase.js'; - -describe('camelCase', function() { - it('should work with numbers', function() { - assert.strictEqual(camelCase('12 feet'), '12Feet'); - assert.strictEqual(camelCase('enable 6h format'), 'enable6HFormat'); - assert.strictEqual(camelCase('enable 24H format'), 'enable24HFormat'); - assert.strictEqual(camelCase('too legit 2 quit'), 'tooLegit2Quit'); - assert.strictEqual(camelCase('walk 500 miles'), 'walk500Miles'); - assert.strictEqual(camelCase('xhr2 request'), 'xhr2Request'); - }); - - it('should handle acronyms', function() { - lodashStable.each(['safe HTML', 'safeHTML'], function(string) { - assert.strictEqual(camelCase(string), 'safeHtml'); - }); - - lodashStable.each(['escape HTML entities', 'escapeHTMLEntities'], function(string) { - assert.strictEqual(camelCase(string), 'escapeHtmlEntities'); - }); - - lodashStable.each(['XMLHttpRequest', 'XmlHTTPRequest'], function(string) { - assert.strictEqual(camelCase(string), 'xmlHttpRequest'); - }); - }); -}); diff --git a/test/capitalize.spec.ts b/test/capitalize.spec.ts new file mode 100644 index 000000000..51abb8182 --- /dev/null +++ b/test/capitalize.spec.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert'; +import capitalize from '../src/capitalize'; + +describe('capitalize', () => { + it('should capitalize the first character of a string', () => { + assert.strictEqual(capitalize('fred'), 'Fred'); + assert.strictEqual(capitalize('Fred'), 'Fred'); + assert.strictEqual(capitalize(' fred'), ' fred'); + }); +}); diff --git a/test/capitalize.test.js b/test/capitalize.test.js deleted file mode 100644 index 0aeb2be92..000000000 --- a/test/capitalize.test.js +++ /dev/null @@ -1,10 +0,0 @@ -import assert from 'assert'; -import capitalize from '../capitalize.js'; - -describe('capitalize', function() { - it('should capitalize the first character of a string', function() { - assert.strictEqual(capitalize('fred'), 'Fred'); - assert.strictEqual(capitalize('Fred'), 'Fred'); - assert.strictEqual(capitalize(' fred'), ' fred'); - }); -}); diff --git a/test/case-methods.spec.ts b/test/case-methods.spec.ts new file mode 100644 index 000000000..e10313def --- /dev/null +++ b/test/case-methods.spec.ts @@ -0,0 +1,133 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubTrue, burredLetters, deburredLetters } from './utils'; +import camelCase from '../src/camelCase'; +import kebabCase from '../src/kebabCase'; +import lowerCase from '../src/lowerCase'; +import snakeCase from '../src/snakeCase'; +import startCase from '../src/startCase'; +import upperCase from '../src/upperCase'; + +const caseMethods = { + camelCase, + kebabCase, + lowerCase, + snakeCase, + startCase, + upperCase, +}; + +describe('case methods', () => { + lodashStable.each(['camel', 'kebab', 'lower', 'snake', 'start', 'upper'], (caseName) => { + const methodName = `${caseName}Case`, + func = caseMethods[methodName]; + + const strings = [ + 'foo bar', + 'Foo bar', + 'foo Bar', + 'Foo Bar', + 'FOO BAR', + 'fooBar', + '--foo-bar--', + '__foo_bar__', + ]; + + const converted = (function () { + switch (caseName) { + case 'camel': + return 'fooBar'; + case 'kebab': + return 'foo-bar'; + case 'lower': + return 'foo bar'; + case 'snake': + return 'foo_bar'; + case 'start': + return 'Foo Bar'; + case 'upper': + return 'FOO BAR'; + } + })(); + + it(`\`_.${methodName}\` should convert \`string\` to ${caseName} case`, () => { + const actual = lodashStable.map(strings, (string) => { + const expected = caseName == 'start' && string == 'FOO BAR' ? string : converted; + return func(string) === expected; + }); + + assert.deepStrictEqual(actual, lodashStable.map(strings, stubTrue)); + }); + + it(`\`_.${methodName}\` should handle double-converting strings`, () => { + const actual = lodashStable.map(strings, (string) => { + const expected = caseName == 'start' && string == 'FOO BAR' ? string : converted; + return func(func(string)) === expected; + }); + + assert.deepStrictEqual(actual, lodashStable.map(strings, stubTrue)); + }); + + it(`\`_.${methodName}\` should remove contraction apostrophes`, () => { + const postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; + + lodashStable.each(["'", '\u2019'], (apos) => { + const actual = lodashStable.map(postfixes, (postfix) => + func(`a b${apos}${postfix} c`), + ); + + const expected = lodashStable.map(postfixes, (postfix) => { + switch (caseName) { + case 'camel': + return `aB${postfix}C`; + case 'kebab': + return `a-b${postfix}-c`; + case 'lower': + return `a b${postfix} c`; + case 'snake': + return `a_b${postfix}_c`; + case 'start': + return `A B${postfix} C`; + case 'upper': + return `A B${postfix.toUpperCase()} C`; + } + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it(`\`_.${methodName}\` should remove Latin mathematical operators`, () => { + const actual = lodashStable.map(['\xd7', '\xf7'], func); + assert.deepStrictEqual(actual, ['', '']); + }); + + it(`\`_.${methodName}\` should coerce \`string\` to a string`, () => { + const string = 'foo bar'; + assert.strictEqual(func(Object(string)), converted); + assert.strictEqual(func({ toString: lodashStable.constant(string) }), converted); + }); + }); + + (function () { + it('should get the original value after cycling through all case methods', () => { + const funcs = [ + camelCase, + kebabCase, + lowerCase, + snakeCase, + startCase, + lowerCase, + camelCase, + ]; + + const actual = lodashStable.reduce( + funcs, + (result, func) => func(result), + 'enable 6h format', + ); + + assert.strictEqual(actual, 'enable6HFormat'); + }); + })(); +}); diff --git a/test/case-methods.test.js b/test/case-methods.test.js deleted file mode 100644 index 0fb6a5d87..000000000 --- a/test/case-methods.test.js +++ /dev/null @@ -1,105 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubTrue, burredLetters, deburredLetters } from './utils.js'; -import camelCase from '../camelCase.js'; -import kebabCase from '../kebabCase.js'; -import lowerCase from '../lowerCase.js'; -import snakeCase from '../snakeCase.js'; -import startCase from '../startCase.js'; -import upperCase from '../upperCase.js'; - -const caseMethods = { - camelCase, - kebabCase, - lowerCase, - snakeCase, - startCase, - upperCase -}; - -describe('case methods', function() { - lodashStable.each(['camel', 'kebab', 'lower', 'snake', 'start', 'upper'], function(caseName) { - var methodName = caseName + 'Case', - func = caseMethods[methodName]; - - var strings = [ - 'foo bar', 'Foo bar', 'foo Bar', 'Foo Bar', - 'FOO BAR', 'fooBar', '--foo-bar--', '__foo_bar__' - ]; - - var converted = (function() { - switch (caseName) { - case 'camel': return 'fooBar'; - case 'kebab': return 'foo-bar'; - case 'lower': return 'foo bar'; - case 'snake': return 'foo_bar'; - case 'start': return 'Foo Bar'; - case 'upper': return 'FOO BAR'; - } - }()); - - it('`_.' + methodName + '` should convert `string` to ' + caseName + ' case', function() { - var actual = lodashStable.map(strings, function(string) { - var expected = (caseName == 'start' && string == 'FOO BAR') ? string : converted; - return func(string) === expected; - }); - - assert.deepStrictEqual(actual, lodashStable.map(strings, stubTrue)); - }); - - it('`_.' + methodName + '` should handle double-converting strings', function() { - var actual = lodashStable.map(strings, function(string) { - var expected = (caseName == 'start' && string == 'FOO BAR') ? string : converted; - return func(func(string)) === expected; - }); - - assert.deepStrictEqual(actual, lodashStable.map(strings, stubTrue)); - }); - - it('`_.' + methodName + '` should remove contraction apostrophes', function() { - var postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; - - lodashStable.each(["'", '\u2019'], function(apos) { - var actual = lodashStable.map(postfixes, function(postfix) { - return func('a b' + apos + postfix + ' c'); - }); - - var expected = lodashStable.map(postfixes, function(postfix) { - switch (caseName) { - case 'camel': return 'aB' + postfix + 'C'; - case 'kebab': return 'a-b' + postfix + '-c'; - case 'lower': return 'a b' + postfix + ' c'; - case 'snake': return 'a_b' + postfix + '_c'; - case 'start': return 'A B' + postfix + ' C'; - case 'upper': return 'A B' + postfix.toUpperCase() + ' C'; - } - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('`_.' + methodName + '` should remove Latin mathematical operators', function() { - var actual = lodashStable.map(['\xd7', '\xf7'], func); - assert.deepStrictEqual(actual, ['', '']); - }); - - it('`_.' + methodName + '` should coerce `string` to a string', function() { - var string = 'foo bar'; - assert.strictEqual(func(Object(string)), converted); - assert.strictEqual(func({ 'toString': lodashStable.constant(string) }), converted); - }); - }); - - (function() { - it('should get the original value after cycling through all case methods', function() { - var funcs = [camelCase, kebabCase, lowerCase, snakeCase, startCase, lowerCase, camelCase]; - - var actual = lodashStable.reduce(funcs, function(result, func) { - return func(result); - }, 'enable 6h format'); - - assert.strictEqual(actual, 'enable6HFormat'); - }); - })(); -}); diff --git a/test/castArray.spec.ts b/test/castArray.spec.ts new file mode 100644 index 000000000..266d34871 --- /dev/null +++ b/test/castArray.spec.ts @@ -0,0 +1,23 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey } from './utils'; +import castArray from '../src/castArray'; + +describe('castArray', () => { + it('should wrap non-array items in an array', () => { + const values = falsey.concat(true, 1, 'a', { a: 1 }), + expected = lodashStable.map(values, (value) => [value]), + actual = lodashStable.map(values, castArray); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return array values by reference', () => { + const array = [1]; + assert.strictEqual(castArray(array), array); + }); + + it('should return an empty array when no arguments are given', () => { + assert.deepStrictEqual(castArray(), []); + }); +}); diff --git a/test/castArray.test.js b/test/castArray.test.js deleted file mode 100644 index be874b5e0..000000000 --- a/test/castArray.test.js +++ /dev/null @@ -1,23 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey } from './utils.js'; -import castArray from '../castArray.js'; - -describe('castArray', function() { - it('should wrap non-array items in an array', function() { - var values = falsey.concat(true, 1, 'a', { 'a': 1 }), - expected = lodashStable.map(values, function(value) { return [value]; }), - actual = lodashStable.map(values, castArray); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return array values by reference', function() { - var array = [1]; - assert.strictEqual(castArray(array), array); - }); - - it('should return an empty array when no arguments are given', function() { - assert.deepStrictEqual(castArray(), []); - }); -}); diff --git a/test/chain.js b/test/chain.js deleted file mode 100644 index d02142071..000000000 --- a/test/chain.js +++ /dev/null @@ -1,74 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { square } from './utils.js'; -import chain from '../chain.js'; - -describe('chain', function() { - it('should return a wrapped value', function() { - var actual = chain({ 'a': 0 }); - assert.ok(actual instanceof _); - }); - - it('should return existing wrapped values', function() { - var wrapped = _({ 'a': 0 }); - assert.strictEqual(chain(wrapped), wrapped); - assert.strictEqual(wrapped.chain(), wrapped); - }); - - it('should enable chaining for methods that return unwrapped values', function() { - var array = ['c', 'b', 'a']; - - assert.ok(chain(array).head() instanceof _); - assert.ok(_(array).chain().head() instanceof _); - - assert.ok(chain(array).isArray() instanceof _); - assert.ok(_(array).chain().isArray() instanceof _); - - assert.ok(chain(array).sortBy().head() instanceof _); - assert.ok(_(array).chain().sortBy().head() instanceof _); - }); - - it('should chain multiple methods', function() { - lodashStable.times(2, function(index) { - var array = ['one two three four', 'five six seven eight', 'nine ten eleven twelve'], - expected = { ' ': 9, 'e': 14, 'f': 2, 'g': 1, 'h': 2, 'i': 4, 'l': 2, 'n': 6, 'o': 3, 'r': 2, 's': 2, 't': 5, 'u': 1, 'v': 4, 'w': 2, 'x': 1 }, - wrapped = index ? _(array).chain() : chain(array); - - var actual = wrapped - .chain() - .map(function(value) { return value.split(''); }) - .flatten() - .reduce(function(object, chr) { - object[chr] || (object[chr] = 0); - object[chr]++; - return object; - }, {}) - .value(); - - assert.deepStrictEqual(actual, expected); - - array = [1, 2, 3, 4, 5, 6]; - wrapped = index ? _(array).chain() : chain(array); - actual = wrapped - .chain() - .filter(function(n) { return n % 2 != 0; }) - .reject(function(n) { return n % 3 == 0; }) - .sortBy(function(n) { return -n; }) - .value(); - - assert.deepStrictEqual(actual, [5, 1]); - - array = [3, 4]; - wrapped = index ? _(array).chain() : chain(array); - actual = wrapped - .reverse() - .concat([2, 1]) - .unshift(5) - .tap(function(value) { value.pop(); }) - .map(square) - .value(); - - assert.deepStrictEqual(actual, [25, 16, 9, 4]); - }); - }); -}); diff --git a/test/chain.spec.ts b/test/chain.spec.ts new file mode 100644 index 000000000..b9a6a35f6 --- /dev/null +++ b/test/chain.spec.ts @@ -0,0 +1,93 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { square } from './utils'; +import chain from '../src/chain'; + +describe('chain', () => { + it('should return a wrapped value', () => { + const actual = chain({ a: 0 }); + assert.ok(actual instanceof _); + }); + + it('should return existing wrapped values', () => { + const wrapped = _({ a: 0 }); + assert.strictEqual(chain(wrapped), wrapped); + assert.strictEqual(wrapped.chain(), wrapped); + }); + + it('should enable chaining for methods that return unwrapped values', () => { + const array = ['c', 'b', 'a']; + + assert.ok(chain(array).head() instanceof _); + assert.ok(_(array).chain().head() instanceof _); + + assert.ok(chain(array).isArray() instanceof _); + assert.ok(_(array).chain().isArray() instanceof _); + + assert.ok(chain(array).sortBy().head() instanceof _); + assert.ok(_(array).chain().sortBy().head() instanceof _); + }); + + it('should chain multiple methods', () => { + lodashStable.times(2, (index) => { + let array = ['one two three four', 'five six seven eight', 'nine ten eleven twelve'], + expected = { + ' ': 9, + e: 14, + f: 2, + g: 1, + h: 2, + i: 4, + l: 2, + n: 6, + o: 3, + r: 2, + s: 2, + t: 5, + u: 1, + v: 4, + w: 2, + x: 1, + }, + wrapped = index ? _(array).chain() : chain(array); + + let actual = wrapped + .chain() + .map((value) => value.split('')) + .flatten() + .reduce((object, chr) => { + object[chr] || (object[chr] = 0); + object[chr]++; + return object; + }, {}) + .value(); + + assert.deepStrictEqual(actual, expected); + + array = [1, 2, 3, 4, 5, 6]; + wrapped = index ? _(array).chain() : chain(array); + actual = wrapped + .chain() + .filter((n) => n % 2 != 0) + .reject((n) => n % 3 == 0) + .sortBy((n) => -n) + .value(); + + assert.deepStrictEqual(actual, [5, 1]); + + array = [3, 4]; + wrapped = index ? _(array).chain() : chain(array); + actual = wrapped + .reverse() + .concat([2, 1]) + .unshift(5) + .tap((value) => { + value.pop(); + }) + .map(square) + .value(); + + assert.deepStrictEqual(actual, [25, 16, 9, 4]); + }); + }); +}); diff --git a/test/chunk.spec.ts b/test/chunk.spec.ts new file mode 100644 index 000000000..640b217f7 --- /dev/null +++ b/test/chunk.spec.ts @@ -0,0 +1,49 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubArray } from './utils'; +import chunk from '../src/chunk'; + +describe('chunk', () => { + const array = [0, 1, 2, 3, 4, 5]; + + it('should return chunked arrays', () => { + const actual = chunk(array, 3); + assert.deepStrictEqual(actual, [ + [0, 1, 2], + [3, 4, 5], + ]); + }); + + it('should return the last chunk as remaining elements', () => { + const actual = chunk(array, 4); + assert.deepStrictEqual(actual, [ + [0, 1, 2, 3], + [4, 5], + ]); + }); + + it('should treat falsey `size` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, (value) => + value === undefined ? [[0], [1], [2], [3], [4], [5]] : [], + ); + + const actual = lodashStable.map(falsey, (size, index) => + index ? chunk(array, size) : chunk(array), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should ensure the minimum `size` is `0`', () => { + const values = lodashStable.reject(falsey, lodashStable.isUndefined).concat(-1, -Infinity), + expected = lodashStable.map(values, stubArray); + + const actual = lodashStable.map(values, (n) => chunk(array, n)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should coerce `size` to an integer', () => { + assert.deepStrictEqual(chunk(array, array.length / 4), [[0], [1], [2], [3], [4], [5]]); + }); +}); diff --git a/test/chunk.test.js b/test/chunk.test.js deleted file mode 100644 index f8bdc69d2..000000000 --- a/test/chunk.test.js +++ /dev/null @@ -1,45 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubArray } from './utils.js'; -import chunk from '../chunk.js'; - -describe('chunk', function() { - var array = [0, 1, 2, 3, 4, 5]; - - it('should return chunked arrays', function() { - var actual = chunk(array, 3); - assert.deepStrictEqual(actual, [[0, 1, 2], [3, 4, 5]]); - }); - - it('should return the last chunk as remaining elements', function() { - var actual = chunk(array, 4); - assert.deepStrictEqual(actual, [[0, 1, 2, 3], [4, 5]]); - }); - - it('should treat falsey `size` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? [[0], [1], [2], [3], [4], [5]] : []; - }); - - var actual = lodashStable.map(falsey, function(size, index) { - return index ? chunk(array, size) : chunk(array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should ensure the minimum `size` is `0`', function() { - var values = lodashStable.reject(falsey, lodashStable.isUndefined).concat(-1, -Infinity), - expected = lodashStable.map(values, stubArray); - - var actual = lodashStable.map(values, function(n) { - return chunk(array, n); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should coerce `size` to an integer', function() { - assert.deepStrictEqual(chunk(array, array.length / 4), [[0], [1], [2], [3], [4], [5]]); - }); -}); diff --git a/test/clamp.js b/test/clamp.js deleted file mode 100644 index 911f57e9d..000000000 --- a/test/clamp.js +++ /dev/null @@ -1,58 +0,0 @@ -import assert from 'assert'; -import clamp from '../clamp.js'; - -describe('clamp', function() { - it('should work with a `max`', function() { - assert.strictEqual(clamp(5, 3), 3); - assert.strictEqual(clamp(1, 3), 1); - }); - - it('should clamp negative numbers', function() { - assert.strictEqual(clamp(-10, -5, 5), -5); - assert.strictEqual(clamp(-10.2, -5.5, 5.5), -5.5); - assert.strictEqual(clamp(-Infinity, -5, 5), -5); - }); - - it('should clamp positive numbers', function() { - assert.strictEqual(clamp(10, -5, 5), 5); - assert.strictEqual(clamp(10.6, -5.6, 5.4), 5.4); - assert.strictEqual(clamp(Infinity, -5, 5), 5); - }); - - it('should not alter negative numbers in range', function() { - assert.strictEqual(clamp(-4, -5, 5), -4); - assert.strictEqual(clamp(-5, -5, 5), -5); - assert.strictEqual(clamp(-5.5, -5.6, 5.6), -5.5); - }); - - it('should not alter positive numbers in range', function() { - assert.strictEqual(clamp(4, -5, 5), 4); - assert.strictEqual(clamp(5, -5, 5), 5); - assert.strictEqual(clamp(4.5, -5.1, 5.2), 4.5); - }); - - it('should not alter `0` in range', function() { - assert.strictEqual(1 / clamp(0, -5, 5), Infinity); - }); - - it('should clamp to `0`', function() { - assert.strictEqual(1 / clamp(-10, 0, 5), Infinity); - }); - - it('should not alter `-0` in range', function() { - assert.strictEqual(1 / clamp(-0, -5, 5), -Infinity); - }); - - it('should clamp to `-0`', function() { - assert.strictEqual(1 / clamp(-10, -0, 5), -Infinity); - }); - - it('should return `NaN` when `number` is `NaN`', function() { - assert.deepStrictEqual(clamp(NaN, -5, 5), NaN); - }); - - it('should coerce `min` and `max` of `NaN` to `0`', function() { - assert.deepStrictEqual(clamp(1, -5, NaN), 0); - assert.deepStrictEqual(clamp(-1, NaN, 5), 0); - }); -}); diff --git a/test/clamp.spec.ts b/test/clamp.spec.ts new file mode 100644 index 000000000..ba2ed1ba1 --- /dev/null +++ b/test/clamp.spec.ts @@ -0,0 +1,58 @@ +import assert from 'node:assert'; +import clamp from '../src/clamp'; + +describe('clamp', () => { + it('should work with a `max`', () => { + assert.strictEqual(clamp(5, 3), 3); + assert.strictEqual(clamp(1, 3), 1); + }); + + it('should clamp negative numbers', () => { + assert.strictEqual(clamp(-10, -5, 5), -5); + assert.strictEqual(clamp(-10.2, -5.5, 5.5), -5.5); + assert.strictEqual(clamp(-Infinity, -5, 5), -5); + }); + + it('should clamp positive numbers', () => { + assert.strictEqual(clamp(10, -5, 5), 5); + assert.strictEqual(clamp(10.6, -5.6, 5.4), 5.4); + assert.strictEqual(clamp(Infinity, -5, 5), 5); + }); + + it('should not alter negative numbers in range', () => { + assert.strictEqual(clamp(-4, -5, 5), -4); + assert.strictEqual(clamp(-5, -5, 5), -5); + assert.strictEqual(clamp(-5.5, -5.6, 5.6), -5.5); + }); + + it('should not alter positive numbers in range', () => { + assert.strictEqual(clamp(4, -5, 5), 4); + assert.strictEqual(clamp(5, -5, 5), 5); + assert.strictEqual(clamp(4.5, -5.1, 5.2), 4.5); + }); + + it('should not alter `0` in range', () => { + assert.strictEqual(1 / clamp(0, -5, 5), Infinity); + }); + + it('should clamp to `0`', () => { + assert.strictEqual(1 / clamp(-10, 0, 5), Infinity); + }); + + it('should not alter `-0` in range', () => { + assert.strictEqual(1 / clamp(-0, -5, 5), -Infinity); + }); + + it('should clamp to `-0`', () => { + assert.strictEqual(1 / clamp(-10, -0, 5), -Infinity); + }); + + it('should return `NaN` when `number` is `NaN`', () => { + assert.deepStrictEqual(clamp(NaN, -5, 5), NaN); + }); + + it('should coerce `min` and `max` of `NaN` to `0`', () => { + assert.deepStrictEqual(clamp(1, -5, NaN), 0); + assert.deepStrictEqual(clamp(-1, NaN, 5), 0); + }); +}); diff --git a/test/clone-methods.js b/test/clone-methods.js deleted file mode 100644 index b3f086d4d..000000000 --- a/test/clone-methods.js +++ /dev/null @@ -1,429 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - map, - set, - realm, - body, - asyncFunc, - genFunc, - errors, - _, - LARGE_ARRAY_SIZE, - isNpm, - mapCaches, - arrayBuffer, - stubTrue, - objectProto, - symbol, - defineProperty, - getSymbols, - document, - arrayViews, - slice, - noop, -} from './utils.js'; - -import cloneDeep from '../cloneDeep.js'; -import cloneDeepWith from '../cloneDeepWith.js'; -import last from '../last.js'; - -describe('clone methods', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 1; - Foo.c = function() {}; - - if (Map) { - var map = new Map; - map.set('a', 1); - map.set('b', 2); - } - if (Set) { - var set = new Set; - set.add(1); - set.add(2); - } - var objects = { - '`arguments` objects': arguments, - 'arrays': ['a', ''], - 'array-like objects': { '0': 'a', 'length': 1 }, - 'booleans': false, - 'boolean objects': Object(false), - 'date objects': new Date, - 'Foo instances': new Foo, - 'objects': { 'a': 0, 'b': 1, 'c': 2 }, - 'objects with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } }, - 'objects from another document': realm.object || {}, - 'maps': map, - 'null values': null, - 'numbers': 0, - 'number objects': Object(0), - 'regexes': /a/gim, - 'sets': set, - 'strings': 'a', - 'string objects': Object('a'), - 'undefined values': undefined - }; - - objects.arrays.length = 3; - - var uncloneable = { - 'DOM elements': body, - 'functions': Foo, - 'async functions': asyncFunc, - 'generator functions': genFunc, - 'the `Proxy` constructor': Proxy - }; - - lodashStable.each(errors, function(error) { - uncloneable[error.name + 's'] = error; - }); - - it('`_.clone` should perform a shallow clone', function() { - var array = [{ 'a': 0 }, { 'b': 1 }], - actual = _.clone(array); - - assert.deepStrictEqual(actual, array); - assert.ok(actual !== array && actual[0] === array[0]); - }); - - it('`_.cloneDeep` should deep clone objects with circular references', function() { - var object = { - 'foo': { 'b': { 'c': { 'd': {} } } }, - 'bar': {} - }; - - object.foo.b.c.d = object; - object.bar.b = object.foo.b; - - var actual = cloneDeep(object); - assert.ok(actual.bar.b === actual.foo.b && actual === actual.foo.b.c.d && actual !== object); - }); - - it('`_.cloneDeep` should deep clone objects with lots of circular references', function() { - var cyclical = {}; - lodashStable.times(LARGE_ARRAY_SIZE + 1, function(index) { - cyclical['v' + index] = [index ? cyclical['v' + (index - 1)] : cyclical]; - }); - - var clone = cloneDeep(cyclical), - actual = clone['v' + LARGE_ARRAY_SIZE][0]; - - assert.strictEqual(actual, clone['v' + (LARGE_ARRAY_SIZE - 1)]); - assert.notStrictEqual(actual, cyclical['v' + (LARGE_ARRAY_SIZE - 1)]); - }); - - it('`_.cloneDeepWith` should provide `stack` to `customizer`', function() { - var actual; - - cloneDeepWith({ 'a': 1 }, function() { - actual = last(arguments); - }); - - assert.ok(isNpm - ? actual.constructor.name == 'Stack' - : actual instanceof mapCaches.Stack - ); - }); - - lodashStable.each(['clone', 'cloneDeep'], function(methodName) { - var func = _[methodName], - isDeep = methodName == 'cloneDeep'; - - lodashStable.forOwn(objects, function(object, kind) { - it('`_.' + methodName + '` should clone ' + kind, function() { - var actual = func(object); - assert.ok(lodashStable.isEqual(actual, object)); - - if (lodashStable.isObject(object)) { - assert.notStrictEqual(actual, object); - } else { - assert.strictEqual(actual, object); - } - }); - }); - - it('`_.' + methodName + '` should clone array buffers', function() { - if (ArrayBuffer) { - var actual = func(arrayBuffer); - assert.strictEqual(actual.byteLength, arrayBuffer.byteLength); - assert.notStrictEqual(actual, arrayBuffer); - } - }); - - it('`_.' + methodName + '` should clone buffers', function() { - if (Buffer) { - var buffer = new Buffer([1, 2]), - actual = func(buffer); - - assert.strictEqual(actual.byteLength, buffer.byteLength); - assert.strictEqual(actual.inspect(), buffer.inspect()); - assert.notStrictEqual(actual, buffer); - - buffer[0] = 2; - assert.strictEqual(actual[0], isDeep ? 2 : 1); - } - }); - - it('`_.' + methodName + '` should clone `index` and `input` array properties', function() { - var array = /c/.exec('abcde'), - actual = func(array); - - assert.strictEqual(actual.index, 2); - assert.strictEqual(actual.input, 'abcde'); - }); - - it('`_.' + methodName + '` should clone `lastIndex` regexp property', function() { - var regexp = /c/g; - regexp.exec('abcde'); - - assert.strictEqual(func(regexp).lastIndex, 3); - }); - - it('`_.' + methodName + '` should clone expando properties', function() { - var values = lodashStable.map([false, true, 1, 'a'], function(value) { - var object = Object(value); - object.a = 1; - return object; - }); - - var expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value) { - return func(value).a === 1; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should clone prototype objects', function() { - var actual = func(Foo.prototype); - - assert.ok(!(actual instanceof Foo)); - assert.deepStrictEqual(actual, { 'b': 1 }); - }); - - it('`_.' + methodName + '` should set the `[[Prototype]]` of a clone', function() { - assert.ok(func(new Foo) instanceof Foo); - }); - - it('`_.' + methodName + '` should set the `[[Prototype]]` of a clone even when the `constructor` is incorrect', function() { - Foo.prototype.constructor = Object; - assert.ok(func(new Foo) instanceof Foo); - Foo.prototype.constructor = Foo; - }); - - it('`_.' + methodName + '` should ensure `value` constructor is a function before using its `[[Prototype]]`', function() { - Foo.prototype.constructor = null; - assert.ok(!(func(new Foo) instanceof Foo)); - Foo.prototype.constructor = Foo; - }); - - it('`_.' + methodName + '` should clone properties that shadow those on `Object.prototype`', function() { - var object = { - 'constructor': objectProto.constructor, - 'hasOwnProperty': objectProto.hasOwnProperty, - 'isPrototypeOf': objectProto.isPrototypeOf, - 'propertyIsEnumerable': objectProto.propertyIsEnumerable, - 'toLocaleString': objectProto.toLocaleString, - 'toString': objectProto.toString, - 'valueOf': objectProto.valueOf - }; - - var actual = func(object); - - assert.deepStrictEqual(actual, object); - assert.notStrictEqual(actual, object); - }); - - it('`_.' + methodName + '` should clone symbol properties', function() { - function Foo() { - this[symbol] = { 'c': 1 }; - } - - if (Symbol) { - var symbol2 = Symbol('b'); - Foo.prototype[symbol2] = 2; - - var symbol3 = Symbol('c'); - defineProperty(Foo.prototype, symbol3, { - 'configurable': true, - 'enumerable': false, - 'writable': true, - 'value': 3 - }); - - var object = { 'a': { 'b': new Foo } }; - object[symbol] = { 'b': 1 }; - - var actual = func(object); - if (isDeep) { - assert.notStrictEqual(actual[symbol], object[symbol]); - assert.notStrictEqual(actual.a, object.a); - } else { - assert.strictEqual(actual[symbol], object[symbol]); - assert.strictEqual(actual.a, object.a); - } - assert.deepStrictEqual(actual[symbol], object[symbol]); - assert.deepStrictEqual(getSymbols(actual.a.b), [symbol]); - assert.deepStrictEqual(actual.a.b[symbol], object.a.b[symbol]); - assert.deepStrictEqual(actual.a.b[symbol2], object.a.b[symbol2]); - assert.deepStrictEqual(actual.a.b[symbol3], object.a.b[symbol3]); - } - }); - - it('`_.' + methodName + '` should clone symbol objects', function() { - if (Symbol) { - assert.strictEqual(func(symbol), symbol); - - var object = Object(symbol), - actual = func(object); - - assert.strictEqual(typeof actual, 'object'); - assert.strictEqual(typeof actual.valueOf(), 'symbol'); - assert.notStrictEqual(actual, object); - } - }); - - it('`_.' + methodName + '` should not clone symbol primitives', function() { - if (Symbol) { - assert.strictEqual(func(symbol), symbol); - } - }); - - it('`_.' + methodName + '` should not error on DOM elements', function() { - if (document) { - var element = document.createElement('div'); - - try { - assert.deepStrictEqual(func(element), {}); - } catch (e) { - assert.ok(false, e.message); - } - } - }); - - it('`_.' + methodName + '` should create an object from the same realm as `value`', function() { - var props = []; - - var objects = lodashStable.transform(_, function(result, value, key) { - if (lodashStable.startsWith(key, '_') && lodashStable.isObject(value) && - !lodashStable.isArguments(value) && !lodashStable.isElement(value) && - !lodashStable.isFunction(value)) { - props.push(lodashStable.capitalize(lodashStable.camelCase(key))); - result.push(value); - } - }, []); - - var expected = lodashStable.map(objects, stubTrue); - - var actual = lodashStable.map(objects, function(object) { - var Ctor = object.constructor, - result = func(object); - - return result !== object && ((result instanceof Ctor) || !(new Ctor instanceof Ctor)); - }); - - assert.deepStrictEqual(actual, expected, props.join(', ')); - }); - - it('`_.' + methodName + '` should perform a ' + (isDeep ? 'deep' : 'shallow') + ' clone when used as an iteratee for methods like `_.map`', function() { - var expected = [{ 'a': [0] }, { 'b': [1] }], - actual = lodashStable.map(expected, func); - - assert.deepStrictEqual(actual, expected); - - if (isDeep) { - assert.ok(actual[0] !== expected[0] && actual[0].a !== expected[0].a && actual[1].b !== expected[1].b); - } else { - assert.ok(actual[0] !== expected[0] && actual[0].a === expected[0].a && actual[1].b === expected[1].b); - } - }); - - it('`_.' + methodName + '` should return a unwrapped value when chaining', function() { - var object = objects.objects, - actual = _(object)[methodName](); - - assert.deepEqual(actual, object); - assert.notStrictEqual(actual, object); - }); - - lodashStable.each(arrayViews, function(type) { - it('`_.' + methodName + '` should clone ' + type + ' values', function() { - var Ctor = root[type]; - - lodashStable.times(2, function(index) { - if (Ctor) { - var buffer = new ArrayBuffer(24), - view = index ? new Ctor(buffer, 8, 1) : new Ctor(buffer), - actual = func(view); - - assert.deepStrictEqual(actual, view); - assert.notStrictEqual(actual, view); - assert.strictEqual(actual.buffer === view.buffer, !isDeep); - assert.strictEqual(actual.byteOffset, view.byteOffset); - assert.strictEqual(actual.length, view.length); - } - }); - }); - }); - - lodashStable.forOwn(uncloneable, function(value, key) { - it('`_.' + methodName + '` should not clone ' + key, function() { - if (value) { - var object = { 'a': value, 'b': { 'c': value } }, - actual = func(object), - expected = value === Foo ? { 'c': Foo.c } : {}; - - assert.deepStrictEqual(actual, object); - assert.notStrictEqual(actual, object); - assert.deepStrictEqual(func(value), expected); - } - }); - }); - }); - - lodashStable.each(['cloneWith', 'cloneDeepWith'], function(methodName) { - var func = _[methodName], - isDeep = methodName == 'cloneDeepWith'; - - it('`_.' + methodName + '` should provide correct `customizer` arguments', function() { - var argsList = [], - object = new Foo; - - func(object, function() { - var length = arguments.length, - args = slice.call(arguments, 0, length - (length > 1 ? 1 : 0)); - - argsList.push(args); - }); - - assert.deepStrictEqual(argsList, isDeep ? [[object], [1, 'a', object]] : [[object]]); - }); - - it('`_.' + methodName + '` should handle cloning when `customizer` returns `undefined`', function() { - var actual = func({ 'a': { 'b': 'c' } }, noop); - assert.deepStrictEqual(actual, { 'a': { 'b': 'c' } }); - }); - - lodashStable.forOwn(uncloneable, function(value, key) { - it('`_.' + methodName + '` should work with a `customizer` callback and ' + key, function() { - var customizer = function(value) { - return lodashStable.isPlainObject(value) ? undefined : value; - }; - - var actual = func(value, customizer); - assert.strictEqual(actual, value); - - var object = { 'a': value, 'b': { 'c': value } }; - actual = func(object, customizer); - - assert.deepStrictEqual(actual, object); - assert.notStrictEqual(actual, object); - }); - }); - }); -}); diff --git a/test/clone-methods.spec.ts b/test/clone-methods.spec.ts new file mode 100644 index 000000000..719c78de7 --- /dev/null +++ b/test/clone-methods.spec.ts @@ -0,0 +1,446 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + map, + set, + realm, + body, + asyncFunc, + genFunc, + errors, + _, + LARGE_ARRAY_SIZE, + isNpm, + mapCaches, + arrayBuffer, + stubTrue, + objectProto, + symbol, + defineProperty, + getSymbols, + document, + arrayViews, + slice, + noop, +} from './utils'; + +import cloneDeep from '../src/cloneDeep'; +import cloneDeepWith from '../src/cloneDeepWith'; +import last from '../src/last'; + +xdescribe('clone methods', function () { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 1; + Foo.c = function () {}; + + if (Map) { + var map = new Map(); + map.set('a', 1); + map.set('b', 2); + } + if (Set) { + var set = new Set(); + set.add(1); + set.add(2); + } + const objects = { + '`arguments` objects': arguments, + arrays: ['a', ''], + 'array-like objects': { '0': 'a', length: 1 }, + booleans: false, + 'boolean objects': Object(false), + 'date objects': new Date(), + 'Foo instances': new Foo(), + objects: { a: 0, b: 1, c: 2 }, + 'objects with object values': { a: /a/, b: ['B'], c: { C: 1 } }, + 'objects from another document': realm.object || {}, + maps: map, + 'null values': null, + numbers: 0, + 'number objects': Object(0), + regexes: /a/gim, + sets: set, + strings: 'a', + 'string objects': Object('a'), + 'undefined values': undefined, + }; + + objects.arrays.length = 3; + + const uncloneable = { + 'DOM elements': body, + functions: Foo, + 'async functions': asyncFunc, + 'generator functions': genFunc, + 'the `Proxy` constructor': Proxy, + }; + + lodashStable.each(errors, (error) => { + uncloneable[`${error.name}s`] = error; + }); + + it('`_.clone` should perform a shallow clone', () => { + const array = [{ a: 0 }, { b: 1 }], + actual = _.clone(array); + + assert.deepStrictEqual(actual, array); + assert.ok(actual !== array && actual[0] === array[0]); + }); + + it('`_.cloneDeep` should deep clone objects with circular references', () => { + const object = { + foo: { b: { c: { d: {} } } }, + bar: {}, + }; + + object.foo.b.c.d = object; + object.bar.b = object.foo.b; + + const actual = cloneDeep(object); + assert.ok( + actual.bar.b === actual.foo.b && actual === actual.foo.b.c.d && actual !== object, + ); + }); + + it('`_.cloneDeep` should deep clone objects with lots of circular references', () => { + const cyclical = {}; + lodashStable.times(LARGE_ARRAY_SIZE + 1, (index) => { + cyclical[`v${index}`] = [index ? cyclical[`v${index - 1}`] : cyclical]; + }); + + const clone = cloneDeep(cyclical), + actual = clone[`v${LARGE_ARRAY_SIZE}`][0]; + + assert.strictEqual(actual, clone[`v${LARGE_ARRAY_SIZE - 1}`]); + assert.notStrictEqual(actual, cyclical[`v${LARGE_ARRAY_SIZE - 1}`]); + }); + + it('`_.cloneDeepWith` should provide `stack` to `customizer`', () => { + let actual; + + cloneDeepWith({ a: 1 }, function () { + actual = last(arguments); + }); + + assert.ok(isNpm ? actual.constructor.name == 'Stack' : actual instanceof mapCaches.Stack); + }); + + lodashStable.each(['clone', 'cloneDeep'], (methodName) => { + const func = _[methodName], + isDeep = methodName == 'cloneDeep'; + + lodashStable.forOwn(objects, (object, kind) => { + it(`\`_.${methodName}\` should clone ${kind}`, () => { + const actual = func(object); + assert.ok(lodashStable.isEqual(actual, object)); + + if (lodashStable.isObject(object)) { + assert.notStrictEqual(actual, object); + } else { + assert.strictEqual(actual, object); + } + }); + }); + + it(`\`_.${methodName}\` should clone array buffers`, () => { + if (ArrayBuffer) { + const actual = func(arrayBuffer); + assert.strictEqual(actual.byteLength, arrayBuffer.byteLength); + assert.notStrictEqual(actual, arrayBuffer); + } + }); + + it(`\`_.${methodName}\` should clone buffers`, () => { + if (Buffer) { + const buffer = new Buffer([1, 2]), + actual = func(buffer); + + assert.strictEqual(actual.byteLength, buffer.byteLength); + assert.strictEqual(actual.inspect(), buffer.inspect()); + assert.notStrictEqual(actual, buffer); + + buffer[0] = 2; + assert.strictEqual(actual[0], isDeep ? 2 : 1); + } + }); + + it(`\`_.${methodName}\` should clone \`index\` and \`input\` array properties`, () => { + const array = /c/.exec('abcde'), + actual = func(array); + + assert.strictEqual(actual.index, 2); + assert.strictEqual(actual.input, 'abcde'); + }); + + it(`\`_.${methodName}\` should clone \`lastIndex\` regexp property`, () => { + const regexp = /c/g; + regexp.exec('abcde'); + + assert.strictEqual(func(regexp).lastIndex, 3); + }); + + it(`\`_.${methodName}\` should clone expando properties`, () => { + const values = lodashStable.map([false, true, 1, 'a'], (value) => { + const object = Object(value); + object.a = 1; + return object; + }); + + const expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (value) => func(value).a === 1); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should clone prototype objects`, () => { + const actual = func(Foo.prototype); + + assert.ok(!(actual instanceof Foo)); + assert.deepStrictEqual(actual, { b: 1 }); + }); + + it(`\`_.${methodName}\` should set the \`[[Prototype]]\` of a clone`, () => { + assert.ok(func(new Foo()) instanceof Foo); + }); + + it(`\`_.${methodName}\` should set the \`[[Prototype]]\` of a clone even when the \`constructor\` is incorrect`, () => { + Foo.prototype.constructor = Object; + assert.ok(func(new Foo()) instanceof Foo); + Foo.prototype.constructor = Foo; + }); + + it(`\`_.${methodName}\` should ensure \`value\` constructor is a function before using its \`[[Prototype]]\``, () => { + Foo.prototype.constructor = null; + assert.ok(!(func(new Foo()) instanceof Foo)); + Foo.prototype.constructor = Foo; + }); + + it(`\`_.${methodName}\` should clone properties that shadow those on \`Object.prototype\``, () => { + const object = { + constructor: objectProto.constructor, + hasOwnProperty: objectProto.hasOwnProperty, + isPrototypeOf: objectProto.isPrototypeOf, + propertyIsEnumerable: objectProto.propertyIsEnumerable, + toLocaleString: objectProto.toLocaleString, + toString: objectProto.toString, + valueOf: objectProto.valueOf, + }; + + const actual = func(object); + + assert.deepStrictEqual(actual, object); + assert.notStrictEqual(actual, object); + }); + + it(`\`_.${methodName}\` should clone symbol properties`, () => { + function Foo() { + this[symbol] = { c: 1 }; + } + + if (Symbol) { + const symbol2 = Symbol('b'); + Foo.prototype[symbol2] = 2; + + const symbol3 = Symbol('c'); + defineProperty(Foo.prototype, symbol3, { + configurable: true, + enumerable: false, + writable: true, + value: 3, + }); + + const object = { a: { b: new Foo() } }; + object[symbol] = { b: 1 }; + + const actual = func(object); + if (isDeep) { + assert.notStrictEqual(actual[symbol], object[symbol]); + assert.notStrictEqual(actual.a, object.a); + } else { + assert.strictEqual(actual[symbol], object[symbol]); + assert.strictEqual(actual.a, object.a); + } + assert.deepStrictEqual(actual[symbol], object[symbol]); + assert.deepStrictEqual(getSymbols(actual.a.b), [symbol]); + assert.deepStrictEqual(actual.a.b[symbol], object.a.b[symbol]); + assert.deepStrictEqual(actual.a.b[symbol2], object.a.b[symbol2]); + assert.deepStrictEqual(actual.a.b[symbol3], object.a.b[symbol3]); + } + }); + + it(`\`_.${methodName}\` should clone symbol objects`, () => { + if (Symbol) { + assert.strictEqual(func(symbol), symbol); + + const object = Object(symbol), + actual = func(object); + + assert.strictEqual(typeof actual, 'object'); + assert.strictEqual(typeof actual.valueOf(), 'symbol'); + assert.notStrictEqual(actual, object); + } + }); + + it(`\`_.${methodName}\` should not clone symbol primitives`, () => { + if (Symbol) { + assert.strictEqual(func(symbol), symbol); + } + }); + + it(`\`_.${methodName}\` should not error on DOM elements`, () => { + if (document) { + const element = document.createElement('div'); + + try { + assert.deepStrictEqual(func(element), {}); + } catch (e) { + assert.ok(false, e.message); + } + } + }); + + it(`\`_.${methodName}\` should create an object from the same realm as \`value\``, () => { + const props = []; + + const objects = lodashStable.transform( + _, + (result, value, key) => { + if ( + lodashStable.startsWith(key, '_') && + lodashStable.isObject(value) && + !lodashStable.isArguments(value) && + !lodashStable.isElement(value) && + !lodashStable.isFunction(value) + ) { + props.push(lodashStable.capitalize(lodashStable.camelCase(key))); + result.push(value); + } + }, + [], + ); + + const expected = lodashStable.map(objects, stubTrue); + + const actual = lodashStable.map(objects, (object) => { + const Ctor = object.constructor, + result = func(object); + + return ( + result !== object && (result instanceof Ctor || !(new Ctor() instanceof Ctor)) + ); + }); + + assert.deepStrictEqual(actual, expected, props.join(', ')); + }); + + it(`\`_.${methodName}\` should perform a ${ + isDeep ? 'deep' : 'shallow' + } clone when used as an iteratee for methods like \`_.map\``, () => { + const expected = [{ a: [0] }, { b: [1] }], + actual = lodashStable.map(expected, func); + + assert.deepStrictEqual(actual, expected); + + if (isDeep) { + assert.ok( + actual[0] !== expected[0] && + actual[0].a !== expected[0].a && + actual[1].b !== expected[1].b, + ); + } else { + assert.ok( + actual[0] !== expected[0] && + actual[0].a === expected[0].a && + actual[1].b === expected[1].b, + ); + } + }); + + it(`\`_.${methodName}\` should return a unwrapped value when chaining`, () => { + const object = objects.objects, + actual = _(object)[methodName](); + + assert.deepEqual(actual, object); + assert.notStrictEqual(actual, object); + }); + + lodashStable.each(arrayViews, (type) => { + it(`\`_.${methodName}\` should clone ${type} values`, () => { + const Ctor = root[type]; + + lodashStable.times(2, (index) => { + if (Ctor) { + const buffer = new ArrayBuffer(24), + view = index ? new Ctor(buffer, 8, 1) : new Ctor(buffer), + actual = func(view); + + assert.deepStrictEqual(actual, view); + assert.notStrictEqual(actual, view); + assert.strictEqual(actual.buffer === view.buffer, !isDeep); + assert.strictEqual(actual.byteOffset, view.byteOffset); + assert.strictEqual(actual.length, view.length); + } + }); + }); + }); + + lodashStable.forOwn(uncloneable, (value, key) => { + it(`\`_.${methodName}\` should not clone ${key}`, () => { + if (value) { + const object = { a: value, b: { c: value } }, + actual = func(object), + expected = value === Foo ? { c: Foo.c } : {}; + + assert.deepStrictEqual(actual, object); + assert.notStrictEqual(actual, object); + assert.deepStrictEqual(func(value), expected); + } + }); + }); + }); + + lodashStable.each(['cloneWith', 'cloneDeepWith'], (methodName) => { + const func = _[methodName], + isDeep = methodName == 'cloneDeepWith'; + + it(`\`_.${methodName}\` should provide correct \`customizer\` arguments`, () => { + const argsList = [], + object = new Foo(); + + func(object, function () { + const length = arguments.length, + args = slice.call(arguments, 0, length - (length > 1 ? 1 : 0)); + + argsList.push(args); + }); + + assert.deepStrictEqual(argsList, isDeep ? [[object], [1, 'a', object]] : [[object]]); + }); + + it(`\`_.${methodName}\` should handle cloning when \`customizer\` returns \`undefined\``, () => { + const actual = func({ a: { b: 'c' } }, noop); + assert.deepStrictEqual(actual, { a: { b: 'c' } }); + }); + + lodashStable.forOwn(uncloneable, (value, key) => { + it(`\`_.${methodName}\` should work with a \`customizer\` callback and ${key}`, () => { + const customizer = function (value) { + return lodashStable.isPlainObject(value) ? undefined : value; + }; + + let actual = func(value, customizer); + assert.strictEqual(actual, value); + + const object = { a: value, b: { c: value } }; + actual = func(object, customizer); + + assert.deepStrictEqual(actual, object); + assert.notStrictEqual(actual, object); + }); + }); + }); +}); diff --git a/test/compact.js b/test/compact.js deleted file mode 100644 index 2c3935863..000000000 --- a/test/compact.js +++ /dev/null @@ -1,42 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE, _, falsey } from './utils.js'; -import compact from '../compact.js'; -import slice from '../slice.js'; - -describe('compact', function() { - var largeArray = lodashStable.range(LARGE_ARRAY_SIZE).concat(null); - - it('should filter falsey values', function() { - var array = ['0', '1', '2']; - assert.deepStrictEqual(compact(falsey.concat(array)), array); - }); - - it('should work when in-between lazy operators', function() { - var actual = _(falsey).thru(slice).compact().thru(slice).value(); - assert.deepEqual(actual, []); - - actual = _(falsey).thru(slice).push(true, 1).compact().push('a').value(); - assert.deepEqual(actual, [true, 1, 'a']); - }); - - it('should work in a lazy sequence', function() { - var actual = _(largeArray).slice(1).compact().reverse().take().value(); - assert.deepEqual(actual, _.take(compact(slice(largeArray, 1)).reverse())); - }); - - it('should work in a lazy sequence with a custom `_.iteratee`', function() { - var iteratee = _.iteratee, - pass = false; - - _.iteratee = identity; - - try { - var actual = _(largeArray).slice(1).compact().value(); - pass = lodashStable.isEqual(actual, compact(slice(largeArray, 1))); - } catch (e) {console.log(e);} - - assert.ok(pass); - _.iteratee = iteratee; - }); -}); diff --git a/test/compact.spec.ts b/test/compact.spec.ts new file mode 100644 index 000000000..8fc99b269 --- /dev/null +++ b/test/compact.spec.ts @@ -0,0 +1,44 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE, _, falsey } from './utils'; +import compact from '../src/compact'; +import slice from '../src/slice'; + +describe('compact', () => { + const largeArray = lodashStable.range(LARGE_ARRAY_SIZE).concat(null); + + it('should filter falsey values', () => { + const array = ['0', '1', '2']; + assert.deepStrictEqual(compact(falsey.concat(array)), array); + }); + + it('should work when in-between lazy operators', () => { + let actual = _(falsey).thru(slice).compact().thru(slice).value(); + assert.deepEqual(actual, []); + + actual = _(falsey).thru(slice).push(true, 1).compact().push('a').value(); + assert.deepEqual(actual, [true, 1, 'a']); + }); + + it('should work in a lazy sequence', () => { + const actual = _(largeArray).slice(1).compact().reverse().take().value(); + assert.deepEqual(actual, _.take(compact(slice(largeArray, 1)).reverse())); + }); + + it('should work in a lazy sequence with a custom `_.iteratee`', () => { + let iteratee = _.iteratee, + pass = false; + + _.iteratee = identity; + + try { + const actual = _(largeArray).slice(1).compact().value(); + pass = lodashStable.isEqual(actual, compact(slice(largeArray, 1))); + } catch (e) { + console.log(e); + } + + assert.ok(pass); + _.iteratee = iteratee; + }); +}); diff --git a/test/concat.js b/test/concat.js deleted file mode 100644 index d66561982..000000000 --- a/test/concat.js +++ /dev/null @@ -1,65 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import concat from '../concat.js'; - -describe('concat', function() { - it('should shallow clone `array`', function() { - var array = [1, 2, 3], - actual = concat(array); - - assert.deepStrictEqual(actual, array); - assert.notStrictEqual(actual, array); - }); - - it('should concat arrays and values', function() { - var array = [1], - actual = concat(array, 2, [3], [[4]]); - - assert.deepStrictEqual(actual, [1, 2, 3, [4]]); - assert.deepStrictEqual(array, [1]); - }); - - it('should cast non-array `array` values to arrays', function() { - var values = [, null, undefined, false, true, 1, NaN, 'a']; - - var expected = lodashStable.map(values, function(value, index) { - return index ? [value] : []; - }); - - var actual = lodashStable.map(values, function(value, index) { - return index ? concat(value) : concat(); - }); - - assert.deepStrictEqual(actual, expected); - - expected = lodashStable.map(values, function(value) { - return [value, 2, [3]]; - }); - - actual = lodashStable.map(values, function(value) { - return concat(value, [2], [[3]]); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should treat sparse arrays as dense', function() { - var expected = [], - actual = concat(Array(1), Array(1)); - - expected.push(undefined, undefined); - - assert.ok('0'in actual); - assert.ok('1' in actual); - assert.deepStrictEqual(actual, expected); - }); - - it('should return a new wrapped array', function() { - var array = [1], - wrapped = _(array).concat([2, 3]), - actual = wrapped.value(); - - assert.deepEqual(array, [1]); - assert.deepEqual(actual, [1, 2, 3]); - }); -}); diff --git a/test/concat.spec.ts b/test/concat.spec.ts new file mode 100644 index 000000000..89cdb127f --- /dev/null +++ b/test/concat.spec.ts @@ -0,0 +1,57 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import concat from '../src/concat'; + +describe('concat', () => { + it('should shallow clone `array`', () => { + const array = [1, 2, 3], + actual = concat(array); + + assert.deepStrictEqual(actual, array); + assert.notStrictEqual(actual, array); + }); + + it('should concat arrays and values', () => { + const array = [1], + actual = concat(array, 2, [3], [[4]]); + + assert.deepStrictEqual(actual, [1, 2, 3, [4]]); + assert.deepStrictEqual(array, [1]); + }); + + it('should cast non-array `array` values to arrays', () => { + const values = [, null, undefined, false, true, 1, NaN, 'a']; + + let expected = lodashStable.map(values, (value, index) => (index ? [value] : [])); + + let actual = lodashStable.map(values, (value, index) => (index ? concat(value) : concat())); + + assert.deepStrictEqual(actual, expected); + + expected = lodashStable.map(values, (value) => [value, 2, [3]]); + + actual = lodashStable.map(values, (value) => concat(value, [2], [[3]])); + + assert.deepStrictEqual(actual, expected); + }); + + it('should treat sparse arrays as dense', () => { + const expected = [], + actual = concat(Array(1), Array(1)); + + expected.push(undefined, undefined); + + assert.ok('0' in actual); + assert.ok('1' in actual); + assert.deepStrictEqual(actual, expected); + }); + + it('should return a new wrapped array', () => { + const array = [1], + wrapped = _(array).concat([2, 3]), + actual = wrapped.value(); + + assert.deepEqual(array, [1]); + assert.deepEqual(actual, [1, 2, 3]); + }); +}); diff --git a/test/cond.js b/test/cond.js deleted file mode 100644 index e3594ab46..000000000 --- a/test/cond.js +++ /dev/null @@ -1,65 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, stubA, stubB, stubC, slice, stubFalse, stubTrue } from './utils.js'; - -describe('cond', function() { - it('should create a conditional function', function() { - var cond = _.cond([ - [lodashStable.matches({ 'a': 1 }), stubA], - [lodashStable.matchesProperty('b', 1), stubB], - [lodashStable.property('c'), stubC] - ]); - - assert.strictEqual(cond({ 'a': 1, 'b': 2, 'c': 3 }), 'a'); - assert.strictEqual(cond({ 'a': 0, 'b': 1, 'c': 2 }), 'b'); - assert.strictEqual(cond({ 'a': -1, 'b': 0, 'c': 1 }), 'c'); - }); - - it('should provide arguments to functions', function() { - var args1, - args2, - expected = ['a', 'b', 'c']; - - var cond = _.cond([[ - function() { args1 || (args1 = slice.call(arguments)); return true; }, - function() { args2 || (args2 = slice.call(arguments)); } - ]]); - - cond('a', 'b', 'c'); - - assert.deepStrictEqual(args1, expected); - assert.deepStrictEqual(args2, expected); - }); - - it('should work with predicate shorthands', function() { - var cond = _.cond([ - [{ 'a': 1 }, stubA], - [['b', 1], stubB], - ['c', stubC] - ]); - - assert.strictEqual(cond({ 'a': 1, 'b': 2, 'c': 3 }), 'a'); - assert.strictEqual(cond({ 'a': 0, 'b': 1, 'c': 2 }), 'b'); - assert.strictEqual(cond({ 'a': -1, 'b': 0, 'c': 1 }), 'c'); - }); - - it('should return `undefined` when no condition is met', function() { - var cond = _.cond([[stubFalse, stubA]]); - assert.strictEqual(cond({ 'a': 1 }), undefined); - }); - - it('should throw a TypeError if `pairs` is not composed of functions', function() { - lodashStable.each([false, true], function(value) { - assert.throws(function() { _.cond([[stubTrue, value]])(); }, TypeError); - }); - }); - - it('should use `this` binding of function for `pairs`', function() { - var cond = _.cond([ - [function(a) { return this[a]; }, function(a, b) { return this[b]; }] - ]); - - var object = { 'cond': cond, 'a': 1, 'b': 2 }; - assert.strictEqual(object.cond('a', 'b'), 2); - }); -}); diff --git a/test/cond.spec.ts b/test/cond.spec.ts new file mode 100644 index 000000000..e100811ea --- /dev/null +++ b/test/cond.spec.ts @@ -0,0 +1,81 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, stubA, stubB, stubC, slice, stubFalse, stubTrue } from './utils'; + +describe('cond', () => { + it('should create a conditional function', () => { + const cond = _.cond([ + [lodashStable.matches({ a: 1 }), stubA], + [lodashStable.matchesProperty('b', 1), stubB], + [lodashStable.property('c'), stubC], + ]); + + assert.strictEqual(cond({ a: 1, b: 2, c: 3 }), 'a'); + assert.strictEqual(cond({ a: 0, b: 1, c: 2 }), 'b'); + assert.strictEqual(cond({ a: -1, b: 0, c: 1 }), 'c'); + }); + + it('should provide arguments to functions', () => { + let args1, + args2, + expected = ['a', 'b', 'c']; + + const cond = _.cond([ + [ + function () { + args1 || (args1 = slice.call(arguments)); + return true; + }, + function () { + args2 || (args2 = slice.call(arguments)); + }, + ], + ]); + + cond('a', 'b', 'c'); + + assert.deepStrictEqual(args1, expected); + assert.deepStrictEqual(args2, expected); + }); + + it('should work with predicate shorthands', () => { + const cond = _.cond([ + [{ a: 1 }, stubA], + [['b', 1], stubB], + ['c', stubC], + ]); + + assert.strictEqual(cond({ a: 1, b: 2, c: 3 }), 'a'); + assert.strictEqual(cond({ a: 0, b: 1, c: 2 }), 'b'); + assert.strictEqual(cond({ a: -1, b: 0, c: 1 }), 'c'); + }); + + it('should return `undefined` when no condition is met', () => { + const cond = _.cond([[stubFalse, stubA]]); + assert.strictEqual(cond({ a: 1 }), undefined); + }); + + it('should throw a TypeError if `pairs` is not composed of functions', () => { + lodashStable.each([false, true], (value) => { + assert.throws(() => { + _.cond([[stubTrue, value]])(); + }, TypeError); + }); + }); + + it('should use `this` binding of function for `pairs`', () => { + const cond = _.cond([ + [ + function (a) { + return this[a]; + }, + function (a, b) { + return this[b]; + }, + ], + ]); + + const object = { cond: cond, a: 1, b: 2 }; + assert.strictEqual(object.cond('a', 'b'), 2); + }); +}); diff --git a/test/conforms-methods.js b/test/conforms-methods.js deleted file mode 100644 index c28e8f8b5..000000000 --- a/test/conforms-methods.js +++ /dev/null @@ -1,153 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, stubFalse, stubTrue, empties } from './utils.js'; -import conformsTo from '../conformsTo.js'; - -describe('conforms methods', function() { - lodashStable.each(['conforms', 'conformsTo'], function(methodName) { - var isConforms = methodName == 'conforms'; - - function conforms(source) { - return isConforms ? _.conforms(source) : function(object) { - return conformsTo(object, source); - }; - } - - it('`_.' + methodName + '` should check if `object` conforms to `source`', function() { - var objects = [ - { 'a': 1, 'b': 8 }, - { 'a': 2, 'b': 4 }, - { 'a': 3, 'b': 16 } - ]; - - var par = conforms({ - 'b': function(value) { return value > 4; } - }); - - var actual = lodashStable.filter(objects, par); - assert.deepStrictEqual(actual, [objects[0], objects[2]]); - - par = conforms({ - 'b': function(value) { return value > 8; }, - 'a': function(value) { return value > 1; } - }); - - actual = lodashStable.filter(objects, par); - assert.deepStrictEqual(actual, [objects[2]]); - }); - - it('`_.' + methodName + '` should not match by inherited `source` properties', function() { - function Foo() { - this.a = function(value) { - return value > 1; - }; - } - Foo.prototype.b = function(value) { - return value > 8; - }; - - var objects = [ - { 'a': 1, 'b': 8 }, - { 'a': 2, 'b': 4 }, - { 'a': 3, 'b': 16 } - ]; - - var par = conforms(new Foo), - actual = lodashStable.filter(objects, par); - - assert.deepStrictEqual(actual, [objects[1], objects[2]]); - }); - - it('`_.' + methodName + '` should not invoke `source` predicates for missing `object` properties', function() { - var count = 0; - - var par = conforms({ - 'a': function() { count++; return true; } - }); - - assert.strictEqual(par({}), false); - assert.strictEqual(count, 0); - }); - - it('`_.' + methodName + '` should work with a function for `object`', function() { - function Foo() {} - Foo.a = 1; - - function Bar() {} - Bar.a = 2; - - var par = conforms({ - 'a': function(value) { return value > 1; } - }); - - assert.strictEqual(par(Foo), false); - assert.strictEqual(par(Bar), true); - }); - - it('`_.' + methodName + '` should work with a function for `source`', function() { - function Foo() {} - Foo.a = function(value) { return value > 1; }; - - var objects = [{ 'a': 1 }, { 'a': 2 }], - actual = lodashStable.filter(objects, conforms(Foo)); - - assert.deepStrictEqual(actual, [objects[1]]); - }); - - it('`_.' + methodName + '` should work with a non-plain `object`', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var par = conforms({ - 'b': function(value) { return value > 1; } - }); - - assert.strictEqual(par(new Foo), true); - }); - - it('`_.' + methodName + '` should return `false` when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubFalse); - - var par = conforms({ - 'a': function(value) { return value > 1; } - }); - - var actual = lodashStable.map(values, function(value, index) { - try { - return index ? par(value) : par(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return `true` when comparing an empty `source` to a nullish `object`', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubTrue), - par = conforms({}); - - var actual = lodashStable.map(values, function(value, index) { - try { - return index ? par(value) : par(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return `true` when comparing an empty `source`', function() { - var object = { 'a': 1 }, - expected = lodashStable.map(empties, stubTrue); - - var actual = lodashStable.map(empties, function(value) { - var par = conforms(value); - return par(object); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/conforms-methods.spec.ts b/test/conforms-methods.spec.ts new file mode 100644 index 000000000..e6af51890 --- /dev/null +++ b/test/conforms-methods.spec.ts @@ -0,0 +1,172 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, stubFalse, stubTrue, empties } from './utils'; +import conformsTo from '../src/conformsTo'; + +describe('conforms methods', () => { + lodashStable.each(['conforms', 'conformsTo'], (methodName) => { + const isConforms = methodName == 'conforms'; + + function conforms(source) { + return isConforms + ? _.conforms(source) + : function (object) { + return conformsTo(object, source); + }; + } + + it(`\`_.${methodName}\` should check if \`object\` conforms to \`source\``, () => { + const objects = [ + { a: 1, b: 8 }, + { a: 2, b: 4 }, + { a: 3, b: 16 }, + ]; + + let par = conforms({ + b: function (value) { + return value > 4; + }, + }); + + let actual = lodashStable.filter(objects, par); + assert.deepStrictEqual(actual, [objects[0], objects[2]]); + + par = conforms({ + b: function (value) { + return value > 8; + }, + a: function (value) { + return value > 1; + }, + }); + + actual = lodashStable.filter(objects, par); + assert.deepStrictEqual(actual, [objects[2]]); + }); + + it(`\`_.${methodName}\` should not match by inherited \`source\` properties`, () => { + function Foo() { + this.a = function (value) { + return value > 1; + }; + } + Foo.prototype.b = function (value) { + return value > 8; + }; + + const objects = [ + { a: 1, b: 8 }, + { a: 2, b: 4 }, + { a: 3, b: 16 }, + ]; + + const par = conforms(new Foo()), + actual = lodashStable.filter(objects, par); + + assert.deepStrictEqual(actual, [objects[1], objects[2]]); + }); + + it(`\`_.${methodName}\` should not invoke \`source\` predicates for missing \`object\` properties`, () => { + let count = 0; + + const par = conforms({ + a: function () { + count++; + return true; + }, + }); + + assert.strictEqual(par({}), false); + assert.strictEqual(count, 0); + }); + + it(`\`_.${methodName}\` should work with a function for \`object\``, () => { + function Foo() {} + Foo.a = 1; + + function Bar() {} + Bar.a = 2; + + const par = conforms({ + a: function (value) { + return value > 1; + }, + }); + + assert.strictEqual(par(Foo), false); + assert.strictEqual(par(Bar), true); + }); + + it(`\`_.${methodName}\` should work with a function for \`source\``, () => { + function Foo() {} + Foo.a = function (value) { + return value > 1; + }; + + const objects = [{ a: 1 }, { a: 2 }], + actual = lodashStable.filter(objects, conforms(Foo)); + + assert.deepStrictEqual(actual, [objects[1]]); + }); + + it(`\`_.${methodName}\` should work with a non-plain \`object\``, () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const par = conforms({ + b: function (value) { + return value > 1; + }, + }); + + assert.strictEqual(par(new Foo()), true); + }); + + it(`\`_.${methodName}\` should return \`false\` when \`object\` is nullish`, () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubFalse); + + const par = conforms({ + a: function (value) { + return value > 1; + }, + }); + + const actual = lodashStable.map(values, (value, index) => { + try { + return index ? par(value) : par(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return \`true\` when comparing an empty \`source\` to a nullish \`object\``, () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubTrue), + par = conforms({}); + + const actual = lodashStable.map(values, (value, index) => { + try { + return index ? par(value) : par(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return \`true\` when comparing an empty \`source\``, () => { + const object = { a: 1 }, + expected = lodashStable.map(empties, stubTrue); + + const actual = lodashStable.map(empties, (value) => { + const par = conforms(value); + return par(object); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); +}); diff --git a/test/conforms.js b/test/conforms.js deleted file mode 100644 index 204694a37..000000000 --- a/test/conforms.js +++ /dev/null @@ -1,15 +0,0 @@ -import assert from 'assert'; -import conforms from '../conforms.js'; - -describe('conforms', function() { - it('should not change behavior if `source` is modified', function() { - var object = { 'a': 2 }, - source = { 'a': function(value) { return value > 1; } }, - par = conforms(source); - - assert.strictEqual(par(object), true); - - source.a = function(value) { return value < 2; }; - assert.strictEqual(par(object), true); - }); -}); diff --git a/test/conforms.spec.ts b/test/conforms.spec.ts new file mode 100644 index 000000000..a89d04d1e --- /dev/null +++ b/test/conforms.spec.ts @@ -0,0 +1,21 @@ +import assert from 'node:assert'; +import conforms from '../src/conforms'; + +describe('conforms', () => { + it('should not change behavior if `source` is modified', () => { + const object = { a: 2 }, + source = { + a: function (value) { + return value > 1; + }, + }, + par = conforms(source); + + assert.strictEqual(par(object), true); + + source.a = function (value) { + return value < 2; + }; + assert.strictEqual(par(object), true); + }); +}); diff --git a/test/constant.js b/test/constant.js deleted file mode 100644 index 00151ad67..000000000 --- a/test/constant.js +++ /dev/null @@ -1,40 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { empties, _, falsey, stubTrue } from './utils.js'; - -describe('constant', function() { - it('should create a function that returns `value`', function() { - var object = { 'a': 1 }, - values = Array(2).concat(empties, true, 1, 'a'), - constant = _.constant(object); - - var results = lodashStable.map(values, function(value, index) { - if (index < 2) { - return index ? constant.call({}) : constant(); - } - return constant(value); - }); - - assert.ok(lodashStable.every(results, function(result) { - return result === object; - })); - }); - - it('should work with falsey values', function() { - var expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(value, index) { - var constant = index ? _.constant(value) : _.constant(), - result = constant(); - - return (result === value) || (result !== result && value !== value); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return a wrapped value when chaining', function() { - var wrapped = _(true).constant(); - assert.ok(wrapped instanceof _); - }); -}); diff --git a/test/constant.spec.ts b/test/constant.spec.ts new file mode 100644 index 000000000..eb15a7023 --- /dev/null +++ b/test/constant.spec.ts @@ -0,0 +1,38 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { empties, _, falsey, stubTrue } from './utils'; + +describe('constant', () => { + it('should create a function that returns `value`', () => { + const object = { a: 1 }, + values = Array(2).concat(empties, true, 1, 'a'), + constant = _.constant(object); + + const results = lodashStable.map(values, (value, index) => { + if (index < 2) { + return index ? constant.call({}) : constant(); + } + return constant(value); + }); + + assert.ok(lodashStable.every(results, (result) => result === object)); + }); + + it('should work with falsey values', () => { + const expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (value, index) => { + const constant = index ? _.constant(value) : _.constant(), + result = constant(); + + return result === value || (result !== result && value !== value); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return a wrapped value when chaining', () => { + const wrapped = _(true).constant(); + assert.ok(wrapped instanceof _); + }); +}); diff --git a/test/countBy.js b/test/countBy.js deleted file mode 100644 index b3e7a2779..000000000 --- a/test/countBy.js +++ /dev/null @@ -1,66 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE } from './utils.js'; -import countBy from '../countBy.js'; - -describe('countBy', function() { - var array = [6.1, 4.2, 6.3]; - - it('should transform keys by `iteratee`', function() { - var actual = countBy(array, Math.floor); - assert.deepStrictEqual(actual, { '4': 1, '6': 2 }); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var array = [4, 6, 6], - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant({ '4': 1, '6': 2 })); - - var actual = lodashStable.map(values, function(value, index) { - return index ? countBy(array, value) : countBy(array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `_.property` shorthands', function() { - var actual = countBy(['one', 'two', 'three'], 'length'); - assert.deepStrictEqual(actual, { '3': 2, '5': 1 }); - }); - - it('should only add values to own, not inherited, properties', function() { - var actual = countBy(array, function(n) { - return Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor'; - }); - - assert.deepStrictEqual(actual.constructor, 1); - assert.deepStrictEqual(actual.hasOwnProperty, 2); - }); - - it('should work with a number for `iteratee`', function() { - var array = [ - [1, 'a'], - [2, 'a'], - [2, 'b'] - ]; - - assert.deepStrictEqual(countBy(array, 0), { '1': 1, '2': 2 }); - assert.deepStrictEqual(countBy(array, 1), { 'a': 2, 'b': 1 }); - }); - - it('should work with an object for `collection`', function() { - var actual = countBy({ 'a': 6.1, 'b': 4.2, 'c': 6.3 }, Math.floor); - assert.deepStrictEqual(actual, { '4': 1, '6': 2 }); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE).concat( - lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), - lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE) - ); - - var actual = _(array).countBy().map(square).filter(isEven).take().value(); - - assert.deepEqual(actual, _.take(_.filter(_.map(countBy(array), square), isEven))); - }); -}); diff --git a/test/countBy.spec.ts b/test/countBy.spec.ts new file mode 100644 index 000000000..47bc28577 --- /dev/null +++ b/test/countBy.spec.ts @@ -0,0 +1,68 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE } from './utils'; +import countBy from '../src/countBy'; + +describe('countBy', () => { + const array = [6.1, 4.2, 6.3]; + + it('should transform keys by `iteratee`', () => { + const actual = countBy(array, Math.floor); + assert.deepStrictEqual(actual, { '4': 1, '6': 2 }); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const array = [4, 6, 6], + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant({ '4': 1, '6': 2 })); + + const actual = lodashStable.map(values, (value, index) => + index ? countBy(array, value) : countBy(array), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `_.property` shorthands', () => { + const actual = countBy(['one', 'two', 'three'], 'length'); + assert.deepStrictEqual(actual, { '3': 2, '5': 1 }); + }); + + it('should only add values to own, not inherited, properties', () => { + const actual = countBy(array, (n) => + Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor', + ); + + assert.deepStrictEqual(actual.constructor, 1); + assert.deepStrictEqual(actual.hasOwnProperty, 2); + }); + + it('should work with a number for `iteratee`', () => { + const array = [ + [1, 'a'], + [2, 'a'], + [2, 'b'], + ]; + + assert.deepStrictEqual(countBy(array, 0), { '1': 1, '2': 2 }); + assert.deepStrictEqual(countBy(array, 1), { a: 2, b: 1 }); + }); + + it('should work with an object for `collection`', () => { + const actual = countBy({ a: 6.1, b: 4.2, c: 6.3 }, Math.floor); + assert.deepStrictEqual(actual, { '4': 1, '6': 2 }); + }); + + it('should work in a lazy sequence', () => { + const array = lodashStable + .range(LARGE_ARRAY_SIZE) + .concat( + lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), + lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE), + ); + + const actual = _(array).countBy().map(square).filter(isEven).take().value(); + + assert.deepEqual(actual, _.take(_.filter(_.map(countBy(array), square), isEven))); + }); +}); diff --git a/test/create.spec.ts b/test/create.spec.ts new file mode 100644 index 000000000..023d840e6 --- /dev/null +++ b/test/create.spec.ts @@ -0,0 +1,100 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, primitives, stubTrue } from './utils'; +import create from '../src/create'; +import keys from '../src/keys'; + +describe('create', () => { + function Shape() { + this.x = 0; + this.y = 0; + } + + function Circle() { + Shape.call(this); + } + + it('should create an object that inherits from the given `prototype` object', () => { + Circle.prototype = create(Shape.prototype); + Circle.prototype.constructor = Circle; + + const actual = new Circle(); + + assert.ok(actual instanceof Circle); + assert.ok(actual instanceof Shape); + assert.notStrictEqual(Circle.prototype, Shape.prototype); + }); + + it('should assign `properties` to the created object', () => { + const expected = { constructor: Circle, radius: 0 }; + const properties = Object.keys(expected); + Circle.prototype = create(Shape.prototype, expected); + + const actual = new Circle(); + + assert.ok(actual instanceof Circle); + assert.ok(actual instanceof Shape); + assert.deepStrictEqual(Object.keys(Circle.prototype), properties); + properties.forEach((property) => { + assert.strictEqual(Circle.prototype[property], expected[property]); + }); + }); + + it('should assign own properties', () => { + function Foo() { + this.a = 1; + this.c = 3; + } + Foo.prototype.b = 2; + + const actual = create({}, new Foo()); + const expected = { a: 1, c: 3 }; + const properties = Object.keys(expected); + + assert.deepStrictEqual(Object.keys(actual), properties); + properties.forEach((property) => { + assert.strictEqual(actual[property], expected[property]); + }); + }); + + it('should assign properties that shadow those of `prototype`', () => { + function Foo() { + this.a = 1; + } + const object = create(new Foo(), { a: 1 }); + assert.deepStrictEqual(lodashStable.keys(object), ['a']); + }); + + it('should accept a falsey `prototype`', () => { + const actual = lodashStable.map(falsey, (prototype, index) => + index ? create(prototype) : create(), + ); + + actual.forEach((value) => { + assert.ok(lodashStable.isObject(value)); + }); + }); + + it('should accept a primitive `prototype`', () => { + const actual = lodashStable.map(primitives, (value, index) => + index ? create(value) : create(), + ); + + actual.forEach((value) => { + assert.ok(lodashStable.isObject(value)); + }); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [{ a: 1 }, { a: 1 }, { a: 1 }], + expected = lodashStable.map(array, stubTrue), + objects = lodashStable.map(array, create); + + const actual = lodashStable.map( + objects, + (object) => object.a === 1 && !keys(object).length, + ); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/create.test.js b/test/create.test.js deleted file mode 100644 index fef0be6de..000000000 --- a/test/create.test.js +++ /dev/null @@ -1,99 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, primitives, stubTrue } from './utils.js'; -import create from '../create.js'; -import keys from '../keys.js'; - -describe('create', function() { - function Shape() { - this.x = 0; - this.y = 0; - } - - function Circle() { - Shape.call(this); - } - - it('should create an object that inherits from the given `prototype` object', function() { - Circle.prototype = create(Shape.prototype); - Circle.prototype.constructor = Circle; - - var actual = new Circle; - - assert.ok(actual instanceof Circle); - assert.ok(actual instanceof Shape); - assert.notStrictEqual(Circle.prototype, Shape.prototype); - }); - - it('should assign `properties` to the created object', function() { - var expected = { 'constructor': Circle, 'radius': 0 }; - var properties = Object.keys(expected); - Circle.prototype = create(Shape.prototype, expected); - - var actual = new Circle; - - assert.ok(actual instanceof Circle); - assert.ok(actual instanceof Shape); - assert.deepStrictEqual(Object.keys(Circle.prototype), properties); - properties.forEach((property) => { - assert.strictEqual(Circle.prototype[property], expected[property]); - }); - }); - - it('should assign own properties', function() { - function Foo() { - this.a = 1; - this.c = 3; - } - Foo.prototype.b = 2; - - var actual = create({}, new Foo); - var expected = { 'a': 1, 'c': 3 }; - var properties = Object.keys(expected); - - assert.deepStrictEqual(Object.keys(actual), properties); - properties.forEach((property) => { - assert.strictEqual(actual[property], expected[property]); - }); - }); - - it('should assign properties that shadow those of `prototype`', function() { - function Foo() { - this.a = 1; - } - var object = create(new Foo, { 'a': 1 }); - assert.deepStrictEqual(lodashStable.keys(object), ['a']); - }); - - it('should accept a falsey `prototype`', function() { - var actual = lodashStable.map(falsey, function(prototype, index) { - return index ? create(prototype) : create(); - }); - - actual.forEach((value) => { - assert.ok(lodashStable.isObject(value)); - }); - }); - - it('should accept a primitive `prototype`', function() { - var actual = lodashStable.map(primitives, function(value, index) { - return index ? create(value) : create(); - }); - - actual.forEach((value) => { - assert.ok(lodashStable.isObject(value)); - }); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [{ 'a': 1 }, { 'a': 1 }, { 'a': 1 }], - expected = lodashStable.map(array, stubTrue), - objects = lodashStable.map(array, create); - - var actual = lodashStable.map(objects, function(object) { - return object.a === 1 && !keys(object).length; - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/curry-methods.js b/test/curry-methods.js deleted file mode 100644 index e742e0315..000000000 --- a/test/curry-methods.js +++ /dev/null @@ -1,52 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, slice } from './utils.js'; -import curry from '../curry.js'; - -describe('curry methods', function() { - lodashStable.each(['curry', 'curryRight'], function(methodName) { - var func = _[methodName], - fn = function(a, b) { return slice.call(arguments); }, - isCurry = methodName == 'curry'; - - it('`_.' + methodName + '` should not error on functions with the same name as lodash methods', function() { - function run(a, b) { - return a + b; - } - - var curried = func(run); - - try { - var actual = curried(1)(2); - } catch (e) {} - - assert.strictEqual(actual, 3); - }); - - it('`_.' + methodName + '` should work for function names that shadow those on `Object.prototype`', function() { - var curried = curry(function hasOwnProperty(a, b, c) { - return [a, b, c]; - }); - - var expected = [1, 2, 3]; - - assert.deepStrictEqual(curried(1)(2)(3), expected); - }); - - it('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function() { - var array = [fn, fn, fn], - object = { 'a': fn, 'b': fn, 'c': fn }; - - lodashStable.each([array, object], function(collection) { - var curries = lodashStable.map(collection, func), - expected = lodashStable.map(collection, lodashStable.constant(isCurry ? ['a', 'b'] : ['b', 'a'])); - - var actual = lodashStable.map(curries, function(curried) { - return curried('a')('b'); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - }); -}); diff --git a/test/curry-methods.spec.ts b/test/curry-methods.spec.ts new file mode 100644 index 000000000..255f07b61 --- /dev/null +++ b/test/curry-methods.spec.ts @@ -0,0 +1,53 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, slice } from './utils'; +import curry from '../src/curry'; + +describe('curry methods', () => { + lodashStable.each(['curry', 'curryRight'], (methodName) => { + const func = _[methodName], + fn = function (a, b) { + return slice.call(arguments); + }, + isCurry = methodName == 'curry'; + + it(`\`_.${methodName}\` should not error on functions with the same name as lodash methods`, () => { + function run(a, b) { + return a + b; + } + + const curried = func(run); + + try { + var actual = curried(1)(2); + } catch (e) {} + + assert.strictEqual(actual, 3); + }); + + it(`\`_.${methodName}\` should work for function names that shadow those on \`Object.prototype\``, () => { + const curried = curry((a, b, c) => [a, b, c]); + + const expected = [1, 2, 3]; + + assert.deepStrictEqual(curried(1)(2)(3), expected); + }); + + it(`\`_.${methodName}\` should work as an iteratee for methods like \`_.map\``, () => { + const array = [fn, fn, fn], + object = { a: fn, b: fn, c: fn }; + + lodashStable.each([array, object], (collection) => { + const curries = lodashStable.map(collection, func), + expected = lodashStable.map( + collection, + lodashStable.constant(isCurry ? ['a', 'b'] : ['b', 'a']), + ); + + const actual = lodashStable.map(curries, (curried) => curried('a')('b')); + + assert.deepStrictEqual(actual, expected); + }); + }); + }); +}); diff --git a/test/curry.js b/test/curry.js deleted file mode 100644 index 5b8ab7364..000000000 --- a/test/curry.js +++ /dev/null @@ -1,135 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, stubArray } from './utils.js'; -import curry from '../curry.js'; -import placeholder from '../placeholder.js'; -import bind from '../bind.js'; -import partial from '../partial.js'; -import partialRight from '../partialRight.js'; - -describe('curry', function() { - function fn(a, b, c, d) { - return slice.call(arguments); - } - - it('should curry based on the number of arguments given', function() { - var curried = curry(fn), - expected = [1, 2, 3, 4]; - - assert.deepStrictEqual(curried(1)(2)(3)(4), expected); - assert.deepStrictEqual(curried(1, 2)(3, 4), expected); - assert.deepStrictEqual(curried(1, 2, 3, 4), expected); - }); - - it('should allow specifying `arity`', function() { - var curried = curry(fn, 3), - expected = [1, 2, 3]; - - assert.deepStrictEqual(curried(1)(2, 3), expected); - assert.deepStrictEqual(curried(1, 2)(3), expected); - assert.deepStrictEqual(curried(1, 2, 3), expected); - }); - - it('should coerce `arity` to an integer', function() { - var values = ['0', 0.6, 'xyz'], - expected = lodashStable.map(values, stubArray); - - var actual = lodashStable.map(values, function(arity) { - return curry(fn, arity)(); - }); - - assert.deepStrictEqual(actual, expected); - assert.deepStrictEqual(curry(fn, '2')(1)(2), [1, 2]); - }); - - it('should support placeholders', function() { - var curried = curry(fn), - ph = curried.placeholder; - - assert.deepStrictEqual(curried(1)(ph, 3)(ph, 4)(2), [1, 2, 3, 4]); - assert.deepStrictEqual(curried(ph, 2)(1)(ph, 4)(3), [1, 2, 3, 4]); - assert.deepStrictEqual(curried(ph, ph, 3)(ph, 2)(ph, 4)(1), [1, 2, 3, 4]); - assert.deepStrictEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), [1, 2, 3, 4]); - }); - - it('should persist placeholders', function() { - var curried = curry(fn), - ph = curried.placeholder, - actual = curried(ph, ph, ph, 'd')('a')(ph)('b')('c'); - - assert.deepStrictEqual(actual, ['a', 'b', 'c', 'd']); - }); - - it('should use `_.placeholder` when set', function() { - var curried = curry(fn), - _ph = placeholder = {}, - ph = curried.placeholder; - - assert.deepEqual(curried(1)(_ph, 3)(ph, 4), [1, ph, 3, 4]); - delete placeholder; - }); - - it('should provide additional arguments after reaching the target arity', function() { - var curried = curry(fn, 3); - assert.deepStrictEqual(curried(1)(2, 3, 4), [1, 2, 3, 4]); - assert.deepStrictEqual(curried(1, 2)(3, 4, 5), [1, 2, 3, 4, 5]); - assert.deepStrictEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); - }); - - it('should create a function with a `length` of `0`', function() { - lodashStable.times(2, function(index) { - var curried = index ? curry(fn, 4) : curry(fn); - assert.strictEqual(curried.length, 0); - assert.strictEqual(curried(1).length, 0); - assert.strictEqual(curried(1, 2).length, 0); - }); - }); - - it('should ensure `new curried` is an instance of `func`', function() { - function Foo(value) { - return value && object; - } - - var curried = curry(Foo), - object = {}; - - assert.ok(new curried(false) instanceof Foo); - assert.strictEqual(new curried(true), object); - }); - - it('should use `this` binding of function', function() { - var fn = function(a, b, c) { - var value = this || {}; - return [value[a], value[b], value[c]]; - }; - - var object = { 'a': 1, 'b': 2, 'c': 3 }, - expected = [1, 2, 3]; - - assert.deepStrictEqual(curry(bind(fn, object), 3)('a')('b')('c'), expected); - assert.deepStrictEqual(curry(bind(fn, object), 3)('a', 'b')('c'), expected); - assert.deepStrictEqual(curry(bind(fn, object), 3)('a', 'b', 'c'), expected); - - assert.deepStrictEqual(bind(curry(fn), object)('a')('b')('c'), Array(3)); - assert.deepStrictEqual(bind(curry(fn), object)('a', 'b')('c'), Array(3)); - assert.deepStrictEqual(bind(curry(fn), object)('a', 'b', 'c'), expected); - - object.curried = curry(fn); - assert.deepStrictEqual(object.curried('a')('b')('c'), Array(3)); - assert.deepStrictEqual(object.curried('a', 'b')('c'), Array(3)); - assert.deepStrictEqual(object.curried('a', 'b', 'c'), expected); - }); - - it('should work with partialed methods', function() { - var curried = curry(fn), - expected = [1, 2, 3, 4]; - - var a = partial(curried, 1), - b = bind(a, null, 2), - c = partialRight(b, 4), - d = partialRight(b(3), 4); - - assert.deepStrictEqual(c(3), expected); - assert.deepStrictEqual(d(), expected); - }); -}); diff --git a/test/curry.spec.ts b/test/curry.spec.ts new file mode 100644 index 000000000..e75139247 --- /dev/null +++ b/test/curry.spec.ts @@ -0,0 +1,133 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, stubArray } from './utils'; +import curry from '../src/curry'; +import placeholder from '../src/placeholder'; +import bind from '../src/bind'; +import partial from '../src/partial'; +import partialRight from '../src/partialRight'; + +describe('curry', () => { + function fn(a, b, c, d) { + return slice.call(arguments); + } + + it('should curry based on the number of arguments given', () => { + const curried = curry(fn), + expected = [1, 2, 3, 4]; + + assert.deepStrictEqual(curried(1)(2)(3)(4), expected); + assert.deepStrictEqual(curried(1, 2)(3, 4), expected); + assert.deepStrictEqual(curried(1, 2, 3, 4), expected); + }); + + it('should allow specifying `arity`', () => { + const curried = curry(fn, 3), + expected = [1, 2, 3]; + + assert.deepStrictEqual(curried(1)(2, 3), expected); + assert.deepStrictEqual(curried(1, 2)(3), expected); + assert.deepStrictEqual(curried(1, 2, 3), expected); + }); + + it('should coerce `arity` to an integer', () => { + const values = ['0', 0.6, 'xyz'], + expected = lodashStable.map(values, stubArray); + + const actual = lodashStable.map(values, (arity) => curry(fn, arity)()); + + assert.deepStrictEqual(actual, expected); + assert.deepStrictEqual(curry(fn, '2')(1)(2), [1, 2]); + }); + + it('should support placeholders', () => { + const curried = curry(fn), + ph = curried.placeholder; + + assert.deepStrictEqual(curried(1)(ph, 3)(ph, 4)(2), [1, 2, 3, 4]); + assert.deepStrictEqual(curried(ph, 2)(1)(ph, 4)(3), [1, 2, 3, 4]); + assert.deepStrictEqual(curried(ph, ph, 3)(ph, 2)(ph, 4)(1), [1, 2, 3, 4]); + assert.deepStrictEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), [1, 2, 3, 4]); + }); + + it('should persist placeholders', () => { + const curried = curry(fn), + ph = curried.placeholder, + actual = curried(ph, ph, ph, 'd')('a')(ph)('b')('c'); + + assert.deepStrictEqual(actual, ['a', 'b', 'c', 'd']); + }); + + it('should use `_.placeholder` when set', () => { + const curried = curry(fn), + _ph = (placeholder = {}), + ph = curried.placeholder; + + assert.deepEqual(curried(1)(_ph, 3)(ph, 4), [1, ph, 3, 4]); + delete placeholder; + }); + + it('should provide additional arguments after reaching the target arity', () => { + const curried = curry(fn, 3); + assert.deepStrictEqual(curried(1)(2, 3, 4), [1, 2, 3, 4]); + assert.deepStrictEqual(curried(1, 2)(3, 4, 5), [1, 2, 3, 4, 5]); + assert.deepStrictEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); + }); + + it('should create a function with a `length` of `0`', () => { + lodashStable.times(2, (index) => { + const curried = index ? curry(fn, 4) : curry(fn); + assert.strictEqual(curried.length, 0); + assert.strictEqual(curried(1).length, 0); + assert.strictEqual(curried(1, 2).length, 0); + }); + }); + + it('should ensure `new curried` is an instance of `func`', () => { + function Foo(value) { + return value && object; + } + + var curried = curry(Foo), + object = {}; + + assert.ok(new curried(false) instanceof Foo); + assert.strictEqual(new curried(true), object); + }); + + it('should use `this` binding of function', () => { + const fn = function (a, b, c) { + const value = this || {}; + return [value[a], value[b], value[c]]; + }; + + const object = { a: 1, b: 2, c: 3 }, + expected = [1, 2, 3]; + + assert.deepStrictEqual(curry(bind(fn, object), 3)('a')('b')('c'), expected); + assert.deepStrictEqual(curry(bind(fn, object), 3)('a', 'b')('c'), expected); + assert.deepStrictEqual(curry(bind(fn, object), 3)('a', 'b', 'c'), expected); + + assert.deepStrictEqual(bind(curry(fn), object)('a')('b')('c'), Array(3)); + assert.deepStrictEqual(bind(curry(fn), object)('a', 'b')('c'), Array(3)); + assert.deepStrictEqual(bind(curry(fn), object)('a', 'b', 'c'), expected); + + object.curried = curry(fn); + assert.deepStrictEqual(object.curried('a')('b')('c'), Array(3)); + assert.deepStrictEqual(object.curried('a', 'b')('c'), Array(3)); + assert.deepStrictEqual(object.curried('a', 'b', 'c'), expected); + }); + + it('should work with partialed methods', () => { + const curried = curry(fn), + expected = [1, 2, 3, 4]; + + const a = partial(curried, 1), + b = bind(a, null, 2), + c = partialRight(b, 4), + d = partialRight(b(3), 4); + + assert.deepStrictEqual(c(3), expected); + assert.deepStrictEqual(d(), expected); + }); +}); diff --git a/test/curryRight.js b/test/curryRight.js deleted file mode 100644 index 21f6acdb7..000000000 --- a/test/curryRight.js +++ /dev/null @@ -1,136 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, stubArray } from './utils.js'; -import curryRight from '../curryRight.js'; -import placeholder from '../placeholder.js'; -import bind from '../bind.js'; -import partialRight from '../partialRight.js'; -import partial from '../partial.js'; - -describe('curryRight', function() { - function fn(a, b, c, d) { - return slice.call(arguments); - } - - it('should curry based on the number of arguments given', function() { - var curried = curryRight(fn), - expected = [1, 2, 3, 4]; - - assert.deepStrictEqual(curried(4)(3)(2)(1), expected); - assert.deepStrictEqual(curried(3, 4)(1, 2), expected); - assert.deepStrictEqual(curried(1, 2, 3, 4), expected); - }); - - it('should allow specifying `arity`', function() { - var curried = curryRight(fn, 3), - expected = [1, 2, 3]; - - assert.deepStrictEqual(curried(3)(1, 2), expected); - assert.deepStrictEqual(curried(2, 3)(1), expected); - assert.deepStrictEqual(curried(1, 2, 3), expected); - }); - - it('should coerce `arity` to an integer', function() { - var values = ['0', 0.6, 'xyz'], - expected = lodashStable.map(values, stubArray); - - var actual = lodashStable.map(values, function(arity) { - return curryRight(fn, arity)(); - }); - - assert.deepStrictEqual(actual, expected); - assert.deepStrictEqual(curryRight(fn, '2')(1)(2), [2, 1]); - }); - - it('should support placeholders', function() { - var curried = curryRight(fn), - expected = [1, 2, 3, 4], - ph = curried.placeholder; - - assert.deepStrictEqual(curried(4)(2, ph)(1, ph)(3), expected); - assert.deepStrictEqual(curried(3, ph)(4)(1, ph)(2), expected); - assert.deepStrictEqual(curried(ph, ph, 4)(ph, 3)(ph, 2)(1), expected); - assert.deepStrictEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), expected); - }); - - it('should persist placeholders', function() { - var curried = curryRight(fn), - ph = curried.placeholder, - actual = curried('a', ph, ph, ph)('b')(ph)('c')('d'); - - assert.deepStrictEqual(actual, ['a', 'b', 'c', 'd']); - }); - - it('should use `_.placeholder` when set', function() { - var curried = curryRight(fn), - _ph = placeholder = {}, - ph = curried.placeholder; - - assert.deepEqual(curried(4)(2, _ph)(1, ph), [1, 2, ph, 4]); - delete placeholder; - }); - - it('should provide additional arguments after reaching the target arity', function() { - var curried = curryRight(fn, 3); - assert.deepStrictEqual(curried(4)(1, 2, 3), [1, 2, 3, 4]); - assert.deepStrictEqual(curried(4, 5)(1, 2, 3), [1, 2, 3, 4, 5]); - assert.deepStrictEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); - }); - - it('should create a function with a `length` of `0`', function() { - lodashStable.times(2, function(index) { - var curried = index ? curryRight(fn, 4) : curryRight(fn); - assert.strictEqual(curried.length, 0); - assert.strictEqual(curried(4).length, 0); - assert.strictEqual(curried(3, 4).length, 0); - }); - }); - - it('should ensure `new curried` is an instance of `func`', function() { - function Foo(value) { - return value && object; - } - - var curried = curryRight(Foo), - object = {}; - - assert.ok(new curried(false) instanceof Foo); - assert.strictEqual(new curried(true), object); - }); - - it('should use `this` binding of function', function() { - var fn = function(a, b, c) { - var value = this || {}; - return [value[a], value[b], value[c]]; - }; - - var object = { 'a': 1, 'b': 2, 'c': 3 }, - expected = [1, 2, 3]; - - assert.deepStrictEqual(curryRight(bind(fn, object), 3)('c')('b')('a'), expected); - assert.deepStrictEqual(curryRight(bind(fn, object), 3)('b', 'c')('a'), expected); - assert.deepStrictEqual(curryRight(bind(fn, object), 3)('a', 'b', 'c'), expected); - - assert.deepStrictEqual(bind(curryRight(fn), object)('c')('b')('a'), Array(3)); - assert.deepStrictEqual(bind(curryRight(fn), object)('b', 'c')('a'), Array(3)); - assert.deepStrictEqual(bind(curryRight(fn), object)('a', 'b', 'c'), expected); - - object.curried = curryRight(fn); - assert.deepStrictEqual(object.curried('c')('b')('a'), Array(3)); - assert.deepStrictEqual(object.curried('b', 'c')('a'), Array(3)); - assert.deepStrictEqual(object.curried('a', 'b', 'c'), expected); - }); - - it('should work with partialed methods', function() { - var curried = curryRight(fn), - expected = [1, 2, 3, 4]; - - var a = partialRight(curried, 4), - b = partialRight(a, 3), - c = bind(b, null, 1), - d = partial(b(2), 1); - - assert.deepStrictEqual(c(2), expected); - assert.deepStrictEqual(d(), expected); - }); -}); diff --git a/test/curryRight.spec.ts b/test/curryRight.spec.ts new file mode 100644 index 000000000..94735f064 --- /dev/null +++ b/test/curryRight.spec.ts @@ -0,0 +1,134 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, stubArray } from './utils'; +import curryRight from '../src/curryRight'; +import placeholder from '../src/placeholder'; +import bind from '../src/bind'; +import partialRight from '../src/partialRight'; +import partial from '../src/partial'; + +describe('curryRight', () => { + function fn(a, b, c, d) { + return slice.call(arguments); + } + + it('should curry based on the number of arguments given', () => { + const curried = curryRight(fn), + expected = [1, 2, 3, 4]; + + assert.deepStrictEqual(curried(4)(3)(2)(1), expected); + assert.deepStrictEqual(curried(3, 4)(1, 2), expected); + assert.deepStrictEqual(curried(1, 2, 3, 4), expected); + }); + + it('should allow specifying `arity`', () => { + const curried = curryRight(fn, 3), + expected = [1, 2, 3]; + + assert.deepStrictEqual(curried(3)(1, 2), expected); + assert.deepStrictEqual(curried(2, 3)(1), expected); + assert.deepStrictEqual(curried(1, 2, 3), expected); + }); + + it('should coerce `arity` to an integer', () => { + const values = ['0', 0.6, 'xyz'], + expected = lodashStable.map(values, stubArray); + + const actual = lodashStable.map(values, (arity) => curryRight(fn, arity)()); + + assert.deepStrictEqual(actual, expected); + assert.deepStrictEqual(curryRight(fn, '2')(1)(2), [2, 1]); + }); + + it('should support placeholders', () => { + const curried = curryRight(fn), + expected = [1, 2, 3, 4], + ph = curried.placeholder; + + assert.deepStrictEqual(curried(4)(2, ph)(1, ph)(3), expected); + assert.deepStrictEqual(curried(3, ph)(4)(1, ph)(2), expected); + assert.deepStrictEqual(curried(ph, ph, 4)(ph, 3)(ph, 2)(1), expected); + assert.deepStrictEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), expected); + }); + + it('should persist placeholders', () => { + const curried = curryRight(fn), + ph = curried.placeholder, + actual = curried('a', ph, ph, ph)('b')(ph)('c')('d'); + + assert.deepStrictEqual(actual, ['a', 'b', 'c', 'd']); + }); + + it('should use `_.placeholder` when set', () => { + const curried = curryRight(fn), + _ph = (placeholder = {}), + ph = curried.placeholder; + + assert.deepEqual(curried(4)(2, _ph)(1, ph), [1, 2, ph, 4]); + delete placeholder; + }); + + it('should provide additional arguments after reaching the target arity', () => { + const curried = curryRight(fn, 3); + assert.deepStrictEqual(curried(4)(1, 2, 3), [1, 2, 3, 4]); + assert.deepStrictEqual(curried(4, 5)(1, 2, 3), [1, 2, 3, 4, 5]); + assert.deepStrictEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); + }); + + it('should create a function with a `length` of `0`', () => { + lodashStable.times(2, (index) => { + const curried = index ? curryRight(fn, 4) : curryRight(fn); + assert.strictEqual(curried.length, 0); + assert.strictEqual(curried(4).length, 0); + assert.strictEqual(curried(3, 4).length, 0); + }); + }); + + it('should ensure `new curried` is an instance of `func`', () => { + function Foo(value) { + return value && object; + } + + var curried = curryRight(Foo), + object = {}; + + assert.ok(new curried(false) instanceof Foo); + assert.strictEqual(new curried(true), object); + }); + + it('should use `this` binding of function', () => { + const fn = function (a, b, c) { + const value = this || {}; + return [value[a], value[b], value[c]]; + }; + + const object = { a: 1, b: 2, c: 3 }, + expected = [1, 2, 3]; + + assert.deepStrictEqual(curryRight(bind(fn, object), 3)('c')('b')('a'), expected); + assert.deepStrictEqual(curryRight(bind(fn, object), 3)('b', 'c')('a'), expected); + assert.deepStrictEqual(curryRight(bind(fn, object), 3)('a', 'b', 'c'), expected); + + assert.deepStrictEqual(bind(curryRight(fn), object)('c')('b')('a'), Array(3)); + assert.deepStrictEqual(bind(curryRight(fn), object)('b', 'c')('a'), Array(3)); + assert.deepStrictEqual(bind(curryRight(fn), object)('a', 'b', 'c'), expected); + + object.curried = curryRight(fn); + assert.deepStrictEqual(object.curried('c')('b')('a'), Array(3)); + assert.deepStrictEqual(object.curried('b', 'c')('a'), Array(3)); + assert.deepStrictEqual(object.curried('a', 'b', 'c'), expected); + }); + + it('should work with partialed methods', () => { + const curried = curryRight(fn), + expected = [1, 2, 3, 4]; + + const a = partialRight(curried, 4), + b = partialRight(a, 3), + c = bind(b, null, 1), + d = partial(b(2), 1); + + assert.deepStrictEqual(c(2), expected); + assert.deepStrictEqual(d(), expected); + }); +}); diff --git a/test/custom-_.iteratee-methods.js b/test/custom-_.iteratee-methods.js deleted file mode 100644 index 0571d77ab..000000000 --- a/test/custom-_.iteratee-methods.js +++ /dev/null @@ -1,270 +0,0 @@ -import assert from 'assert'; -import partial from '../partial.js'; -import property from '../property.js'; -import iteratee from '../iteratee.js'; - -describe('custom `_.iteratee` methods', function() { - var array = ['one', 'two', 'three'], - getPropA = partial(property, 'a'), - getPropB = partial(property, 'b'), - getLength = partial(property, 'length'), - iteratee = iteratee; - - var getSum = function() { - return function(result, object) { - return result + object.a; - }; - }; - - var objects = [ - { 'a': 0, 'b': 0 }, - { 'a': 1, 'b': 0 }, - { 'a': 1, 'b': 1 } - ]; - - it('`_.countBy` should use `_.iteratee` internally', function() { - iteratee = getLength; - assert.deepEqual(_.countBy(array), { '3': 2, '5': 1 }); - iteratee = iteratee; - }); - - it('`_.differenceBy` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.deepEqual(_.differenceBy(objects, [objects[1]]), [objects[0]]); - iteratee = iteratee; - }); - - it('`_.dropRightWhile` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.dropRightWhile(objects), objects.slice(0, 2)); - iteratee = iteratee; - }); - - it('`_.dropWhile` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2)); - iteratee = iteratee; - }); - - it('`_.every` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.strictEqual(_.every(objects.slice(1)), true); - iteratee = iteratee; - }); - - it('`_.filter` should use `_.iteratee` internally', function() { - var objects = [{ 'a': 0 }, { 'a': 1 }]; - - iteratee = getPropA; - assert.deepEqual(_.filter(objects), [objects[1]]); - iteratee = iteratee; - }); - - it('`_.find` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.strictEqual(_.find(objects), objects[1]); - iteratee = iteratee; - }); - - it('`_.findIndex` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.strictEqual(_.findIndex(objects), 1); - iteratee = iteratee; - }); - - it('`_.findLast` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.strictEqual(_.findLast(objects), objects[2]); - iteratee = iteratee; - }); - - it('`_.findLastIndex` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.strictEqual(_.findLastIndex(objects), 2); - iteratee = iteratee; - }); - - it('`_.findKey` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.strictEqual(_.findKey(objects), '2'); - iteratee = iteratee; - }); - - it('`_.findLastKey` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.strictEqual(_.findLastKey(objects), '2'); - iteratee = iteratee; - }); - - it('`_.groupBy` should use `_.iteratee` internally', function() { - iteratee = getLength; - assert.deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] }); - iteratee = iteratee; - }); - - it('`_.intersectionBy` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.deepEqual(_.intersectionBy(objects, [objects[2]]), [objects[1]]); - iteratee = iteratee; - }); - - it('`_.keyBy` should use `_.iteratee` internally', function() { - iteratee = getLength; - assert.deepEqual(_.keyBy(array), { '3': 'two', '5': 'three' }); - iteratee = iteratee; - }); - - it('`_.map` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.deepEqual(_.map(objects), [0, 1, 1]); - iteratee = iteratee; - }); - - it('`_.mapKeys` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.mapKeys({ 'a': { 'b': 2 } }), { '2': { 'b': 2 } }); - iteratee = iteratee; - }); - - it('`_.mapValues` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.mapValues({ 'a': { 'b': 2 } }), { 'a': 2 }); - iteratee = iteratee; - }); - - it('`_.maxBy` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.maxBy(objects), objects[2]); - iteratee = iteratee; - }); - - it('`_.meanBy` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.strictEqual(_.meanBy(objects), 2 / 3); - iteratee = iteratee; - }); - - it('`_.minBy` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.minBy(objects), objects[0]); - iteratee = iteratee; - }); - - it('`_.partition` should use `_.iteratee` internally', function() { - var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }]; - - iteratee = getPropA; - assert.deepEqual(_.partition(objects), [objects.slice(0, 2), objects.slice(2)]); - iteratee = iteratee; - }); - - it('`_.pullAllBy` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.deepEqual(_.pullAllBy(objects.slice(), [{ 'a': 1, 'b': 0 }]), [objects[0]]); - iteratee = iteratee; - }); - - it('`_.reduce` should use `_.iteratee` internally', function() { - iteratee = getSum; - assert.strictEqual(_.reduce(objects, undefined, 0), 2); - iteratee = iteratee; - }); - - it('`_.reduceRight` should use `_.iteratee` internally', function() { - iteratee = getSum; - assert.strictEqual(_.reduceRight(objects, undefined, 0), 2); - iteratee = iteratee; - }); - - it('`_.reject` should use `_.iteratee` internally', function() { - var objects = [{ 'a': 0 }, { 'a': 1 }]; - - iteratee = getPropA; - assert.deepEqual(_.reject(objects), [objects[0]]); - iteratee = iteratee; - }); - - it('`_.remove` should use `_.iteratee` internally', function() { - var objects = [{ 'a': 0 }, { 'a': 1 }]; - - iteratee = getPropA; - _.remove(objects); - assert.deepEqual(objects, [{ 'a': 0 }]); - iteratee = iteratee; - }); - - it('`_.some` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.strictEqual(_.some(objects), true); - iteratee = iteratee; - }); - - it('`_.sortBy` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]); - iteratee = iteratee; - }); - - it('`_.sortedIndexBy` should use `_.iteratee` internally', function() { - var objects = [{ 'a': 30 }, { 'a': 50 }]; - - iteratee = getPropA; - assert.strictEqual(_.sortedIndexBy(objects, { 'a': 40 }), 1); - iteratee = iteratee; - }); - - it('`_.sortedLastIndexBy` should use `_.iteratee` internally', function() { - var objects = [{ 'a': 30 }, { 'a': 50 }]; - - iteratee = getPropA; - assert.strictEqual(_.sortedLastIndexBy(objects, { 'a': 40 }), 1); - iteratee = iteratee; - }); - - it('`_.sumBy` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.strictEqual(_.sumBy(objects), 1); - iteratee = iteratee; - }); - - it('`_.takeRightWhile` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.takeRightWhile(objects), objects.slice(2)); - iteratee = iteratee; - }); - - it('`_.takeWhile` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2)); - iteratee = iteratee; - }); - - it('`_.transform` should use `_.iteratee` internally', function() { - iteratee = function() { - return function(result, object) { - result.sum += object.a; - }; - }; - - assert.deepEqual(_.transform(objects, undefined, { 'sum': 0 }), { 'sum': 2 }); - iteratee = iteratee; - }); - - it('`_.uniqBy` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.uniqBy(objects), [objects[0], objects[2]]); - iteratee = iteratee; - }); - - it('`_.unionBy` should use `_.iteratee` internally', function() { - iteratee = getPropB; - assert.deepEqual(_.unionBy(objects.slice(0, 1), [objects[2]]), [objects[0], objects[2]]); - iteratee = iteratee; - }); - - it('`_.xorBy` should use `_.iteratee` internally', function() { - iteratee = getPropA; - assert.deepEqual(_.xorBy(objects, objects.slice(1)), [objects[0]]); - iteratee = iteratee; - }); -}); diff --git a/test/custom-_.iteratee-methods.spec.ts b/test/custom-_.iteratee-methods.spec.ts new file mode 100644 index 000000000..4c3773a74 --- /dev/null +++ b/test/custom-_.iteratee-methods.spec.ts @@ -0,0 +1,270 @@ +import assert from 'node:assert'; +import partial from '../src/partial'; +import property from '../src/property'; +import iteratee from '../src/iteratee'; + +describe('custom `_.iteratee` methods', () => { + var array = ['one', 'two', 'three'], + getPropA = partial(property, 'a'), + getPropB = partial(property, 'b'), + getLength = partial(property, 'length'), + iteratee = iteratee; + + const getSum = function () { + return function (result, object) { + return result + object.a; + }; + }; + + const objects = [ + { a: 0, b: 0 }, + { a: 1, b: 0 }, + { a: 1, b: 1 }, + ]; + + it('`_.countBy` should use `_.iteratee` internally', () => { + iteratee = getLength; + assert.deepEqual(_.countBy(array), { '3': 2, '5': 1 }); + iteratee = iteratee; + }); + + it('`_.differenceBy` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.deepEqual(_.differenceBy(objects, [objects[1]]), [objects[0]]); + iteratee = iteratee; + }); + + it('`_.dropRightWhile` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.dropRightWhile(objects), objects.slice(0, 2)); + iteratee = iteratee; + }); + + it('`_.dropWhile` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2)); + iteratee = iteratee; + }); + + it('`_.every` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.strictEqual(_.every(objects.slice(1)), true); + iteratee = iteratee; + }); + + it('`_.filter` should use `_.iteratee` internally', () => { + const objects = [{ a: 0 }, { a: 1 }]; + + iteratee = getPropA; + assert.deepEqual(_.filter(objects), [objects[1]]); + iteratee = iteratee; + }); + + it('`_.find` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.strictEqual(_.find(objects), objects[1]); + iteratee = iteratee; + }); + + it('`_.findIndex` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.strictEqual(_.findIndex(objects), 1); + iteratee = iteratee; + }); + + it('`_.findLast` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.strictEqual(_.findLast(objects), objects[2]); + iteratee = iteratee; + }); + + it('`_.findLastIndex` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.strictEqual(_.findLastIndex(objects), 2); + iteratee = iteratee; + }); + + it('`_.findKey` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.strictEqual(_.findKey(objects), '2'); + iteratee = iteratee; + }); + + it('`_.findLastKey` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.strictEqual(_.findLastKey(objects), '2'); + iteratee = iteratee; + }); + + it('`_.groupBy` should use `_.iteratee` internally', () => { + iteratee = getLength; + assert.deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] }); + iteratee = iteratee; + }); + + it('`_.intersectionBy` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.deepEqual(_.intersectionBy(objects, [objects[2]]), [objects[1]]); + iteratee = iteratee; + }); + + it('`_.keyBy` should use `_.iteratee` internally', () => { + iteratee = getLength; + assert.deepEqual(_.keyBy(array), { '3': 'two', '5': 'three' }); + iteratee = iteratee; + }); + + it('`_.map` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.deepEqual(_.map(objects), [0, 1, 1]); + iteratee = iteratee; + }); + + it('`_.mapKeys` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.mapKeys({ a: { b: 2 } }), { '2': { b: 2 } }); + iteratee = iteratee; + }); + + it('`_.mapValues` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.mapValues({ a: { b: 2 } }), { a: 2 }); + iteratee = iteratee; + }); + + it('`_.maxBy` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.maxBy(objects), objects[2]); + iteratee = iteratee; + }); + + it('`_.meanBy` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.strictEqual(_.meanBy(objects), 2 / 3); + iteratee = iteratee; + }); + + it('`_.minBy` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.minBy(objects), objects[0]); + iteratee = iteratee; + }); + + it('`_.partition` should use `_.iteratee` internally', () => { + const objects = [{ a: 1 }, { a: 1 }, { b: 2 }]; + + iteratee = getPropA; + assert.deepEqual(_.partition(objects), [objects.slice(0, 2), objects.slice(2)]); + iteratee = iteratee; + }); + + it('`_.pullAllBy` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.deepEqual(_.pullAllBy(objects.slice(), [{ a: 1, b: 0 }]), [objects[0]]); + iteratee = iteratee; + }); + + it('`_.reduce` should use `_.iteratee` internally', () => { + iteratee = getSum; + assert.strictEqual(_.reduce(objects, undefined, 0), 2); + iteratee = iteratee; + }); + + it('`_.reduceRight` should use `_.iteratee` internally', () => { + iteratee = getSum; + assert.strictEqual(_.reduceRight(objects, undefined, 0), 2); + iteratee = iteratee; + }); + + it('`_.reject` should use `_.iteratee` internally', () => { + const objects = [{ a: 0 }, { a: 1 }]; + + iteratee = getPropA; + assert.deepEqual(_.reject(objects), [objects[0]]); + iteratee = iteratee; + }); + + it('`_.remove` should use `_.iteratee` internally', () => { + const objects = [{ a: 0 }, { a: 1 }]; + + iteratee = getPropA; + _.remove(objects); + assert.deepEqual(objects, [{ a: 0 }]); + iteratee = iteratee; + }); + + it('`_.some` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.strictEqual(_.some(objects), true); + iteratee = iteratee; + }); + + it('`_.sortBy` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]); + iteratee = iteratee; + }); + + it('`_.sortedIndexBy` should use `_.iteratee` internally', () => { + const objects = [{ a: 30 }, { a: 50 }]; + + iteratee = getPropA; + assert.strictEqual(_.sortedIndexBy(objects, { a: 40 }), 1); + iteratee = iteratee; + }); + + it('`_.sortedLastIndexBy` should use `_.iteratee` internally', () => { + const objects = [{ a: 30 }, { a: 50 }]; + + iteratee = getPropA; + assert.strictEqual(_.sortedLastIndexBy(objects, { a: 40 }), 1); + iteratee = iteratee; + }); + + it('`_.sumBy` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.strictEqual(_.sumBy(objects), 1); + iteratee = iteratee; + }); + + it('`_.takeRightWhile` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.takeRightWhile(objects), objects.slice(2)); + iteratee = iteratee; + }); + + it('`_.takeWhile` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2)); + iteratee = iteratee; + }); + + it('`_.transform` should use `_.iteratee` internally', () => { + iteratee = function () { + return function (result, object) { + result.sum += object.a; + }; + }; + + assert.deepEqual(_.transform(objects, undefined, { sum: 0 }), { sum: 2 }); + iteratee = iteratee; + }); + + it('`_.uniqBy` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.uniqBy(objects), [objects[0], objects[2]]); + iteratee = iteratee; + }); + + it('`_.unionBy` should use `_.iteratee` internally', () => { + iteratee = getPropB; + assert.deepEqual(_.unionBy(objects.slice(0, 1), [objects[2]]), [objects[0], objects[2]]); + iteratee = iteratee; + }); + + it('`_.xorBy` should use `_.iteratee` internally', () => { + iteratee = getPropA; + assert.deepEqual(_.xorBy(objects, objects.slice(1)), [objects[0]]); + iteratee = iteratee; + }); +}); diff --git a/test/debounce-and-throttle.js b/test/debounce-and-throttle.js deleted file mode 100644 index ece01eaa6..000000000 --- a/test/debounce-and-throttle.js +++ /dev/null @@ -1,167 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, noop, push, isModularize } from './utils.js'; -import runInContext from '../runInContext.js'; - -describe('debounce and throttle', function() { - lodashStable.each(['debounce', 'throttle'], function(methodName) { - var func = _[methodName], - isDebounce = methodName == 'debounce'; - - it('`_.' + methodName + '` should not error for non-object `options` values', function() { - func(noop, 32, 1); - assert.ok(true); - }); - - it('`_.' + methodName + '` should use a default `wait` of `0`', function(done) { - var callCount = 0, - funced = func(function() { callCount++; }); - - funced(); - - setTimeout(function() { - funced(); - assert.strictEqual(callCount, isDebounce ? 1 : 2); - done(); - }, 32); - }); - - it('`_.' + methodName + '` should invoke `func` with the correct `this` binding', function(done) { - var actual = [], - object = { 'funced': func(function() { actual.push(this); }, 32) }, - expected = lodashStable.times(isDebounce ? 1 : 2, lodashStable.constant(object)); - - object.funced(); - if (!isDebounce) { - object.funced(); - } - setTimeout(function() { - assert.deepStrictEqual(actual, expected); - done(); - }, 64); - }); - - it('`_.' + methodName + '` supports recursive calls', function(done) { - var actual = [], - args = lodashStable.map(['a', 'b', 'c'], function(chr) { return [{}, chr]; }), - expected = args.slice(), - queue = args.slice(); - - var funced = func(function() { - var current = [this]; - push.apply(current, arguments); - actual.push(current); - - var next = queue.shift(); - if (next) { - funced.call(next[0], next[1]); - } - }, 32); - - var next = queue.shift(); - funced.call(next[0], next[1]); - assert.deepStrictEqual(actual, expected.slice(0, isDebounce ? 0 : 1)); - - setTimeout(function() { - assert.deepStrictEqual(actual, expected.slice(0, actual.length)); - done(); - }, 256); - }); - - it('`_.' + methodName + '` should work if the system time is set backwards', function(done) { - if (!isModularize) { - var callCount = 0, - dateCount = 0; - - var lodash = runInContext({ - 'Date': { - 'now': function() { - return ++dateCount == 4 - ? +new Date(2012, 3, 23, 23, 27, 18) - : +new Date; - } - } - }); - - var funced = lodash[methodName](function() { - callCount++; - }, 32); - - funced(); - - setTimeout(function() { - funced(); - assert.strictEqual(callCount, isDebounce ? 1 : 2); - done(); - }, 64); - } - else { - done(); - } - }); - - it('`_.' + methodName + '` should support cancelling delayed calls', function(done) { - var callCount = 0; - - var funced = func(function() { - callCount++; - }, 32, { 'leading': false }); - - funced(); - funced.cancel(); - - setTimeout(function() { - assert.strictEqual(callCount, 0); - done(); - }, 64); - }); - - it('`_.' + methodName + '` should reset `lastCalled` after cancelling', function(done) { - var callCount = 0; - - var funced = func(function() { - return ++callCount; - }, 32, { 'leading': true }); - - assert.strictEqual(funced(), 1); - funced.cancel(); - - assert.strictEqual(funced(), 2); - funced(); - - setTimeout(function() { - assert.strictEqual(callCount, 3); - done(); - }, 64); - }); - - it('`_.' + methodName + '` should support flushing delayed calls', function(done) { - var callCount = 0; - - var funced = func(function() { - return ++callCount; - }, 32, { 'leading': false }); - - funced(); - assert.strictEqual(funced.flush(), 1); - - setTimeout(function() { - assert.strictEqual(callCount, 1); - done(); - }, 64); - }); - - it('`_.' + methodName + '` should noop `cancel` and `flush` when nothing is queued', function(done) { - var callCount = 0, - funced = func(function() { callCount++; }, 32); - - funced.cancel(); - assert.strictEqual(funced.flush(), undefined); - - setTimeout(function() { - assert.strictEqual(callCount, 0); - done(); - }, 64); - }); - }); -}); diff --git a/test/debounce-and-throttle.spec.ts b/test/debounce-and-throttle.spec.ts new file mode 100644 index 000000000..8b8a90221 --- /dev/null +++ b/test/debounce-and-throttle.spec.ts @@ -0,0 +1,174 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, noop, push, isModularize } from './utils'; +import runInContext from '../src/runInContext'; + +describe('debounce and throttle', () => { + lodashStable.each(['debounce', 'throttle'], (methodName) => { + const func = _[methodName], + isDebounce = methodName == 'debounce'; + + it(`\`_.${methodName}\` should not error for non-object \`options\` values`, () => { + func(noop, 32, 1); + assert.ok(true); + }); + + it(`\`_.${methodName}\` should use a default \`wait\` of \`0\``, (done) => { + let callCount = 0, + funced = func(() => { + callCount++; + }); + + funced(); + + setTimeout(() => { + funced(); + assert.strictEqual(callCount, isDebounce ? 1 : 2); + done(); + }, 32); + }); + + it(`\`_.${methodName}\` should invoke \`func\` with the correct \`this\` binding`, (done) => { + const actual = [], + object = { + funced: func(function () { + actual.push(this); + }, 32), + }, + expected = lodashStable.times(isDebounce ? 1 : 2, lodashStable.constant(object)); + + object.funced(); + if (!isDebounce) { + object.funced(); + } + setTimeout(() => { + assert.deepStrictEqual(actual, expected); + done(); + }, 64); + }); + + it(`\`_.${methodName}\` supports recursive calls`, (done) => { + const actual = [], + args = lodashStable.map(['a', 'b', 'c'], (chr) => [{}, chr]), + expected = args.slice(), + queue = args.slice(); + + var funced = func(function () { + const current = [this]; + push.apply(current, arguments); + actual.push(current); + + const next = queue.shift(); + if (next) { + funced.call(next[0], next[1]); + } + }, 32); + + const next = queue.shift(); + funced.call(next[0], next[1]); + assert.deepStrictEqual(actual, expected.slice(0, isDebounce ? 0 : 1)); + + setTimeout(() => { + assert.deepStrictEqual(actual, expected.slice(0, actual.length)); + done(); + }, 256); + }); + + it(`\`_.${methodName}\` should work if the system time is set backwards`, (done) => { + if (!isModularize) { + let callCount = 0, + dateCount = 0; + + const lodash = runInContext({ + Date: { + now: function () { + return ++dateCount == 4 + ? +new Date(2012, 3, 23, 23, 27, 18) + : +new Date(); + }, + }, + }); + + const funced = lodash[methodName](() => { + callCount++; + }, 32); + + funced(); + + setTimeout(() => { + funced(); + assert.strictEqual(callCount, isDebounce ? 1 : 2); + done(); + }, 64); + } else { + done(); + } + }); + + it(`\`_.${methodName}\` should support cancelling delayed calls`, (done) => { + let callCount = 0; + + const funced = func( + () => { + callCount++; + }, + 32, + { leading: false }, + ); + + funced(); + funced.cancel(); + + setTimeout(() => { + assert.strictEqual(callCount, 0); + done(); + }, 64); + }); + + it(`\`_.${methodName}\` should reset \`lastCalled\` after cancelling`, (done) => { + let callCount = 0; + + const funced = func(() => ++callCount, 32, { leading: true }); + + assert.strictEqual(funced(), 1); + funced.cancel(); + + assert.strictEqual(funced(), 2); + funced(); + + setTimeout(() => { + assert.strictEqual(callCount, 3); + done(); + }, 64); + }); + + it(`\`_.${methodName}\` should support flushing delayed calls`, (done) => { + let callCount = 0; + + const funced = func(() => ++callCount, 32, { leading: false }); + + funced(); + assert.strictEqual(funced.flush(), 1); + + setTimeout(() => { + assert.strictEqual(callCount, 1); + done(); + }, 64); + }); + + it(`\`_.${methodName}\` should noop \`cancel\` and \`flush\` when nothing is queued`, (done) => { + let callCount = 0, + funced = func(() => { + callCount++; + }, 32); + + funced.cancel(); + assert.strictEqual(funced.flush(), undefined); + + setTimeout(() => { + assert.strictEqual(callCount, 0); + done(); + }, 64); + }); + }); +}); diff --git a/test/debounce.spec.ts b/test/debounce.spec.ts new file mode 100644 index 000000000..8692e2226 --- /dev/null +++ b/test/debounce.spec.ts @@ -0,0 +1,294 @@ +import assert from 'node:assert'; +import { identity, argv, isPhantom, push } from './utils'; +import debounce from '../src/debounce'; + +describe('debounce', () => { + it('should debounce a function', (done) => { + let callCount = 0; + + const debounced = debounce((value) => { + ++callCount; + return value; + }, 32); + + const results = [debounced('a'), debounced('b'), debounced('c')]; + assert.deepStrictEqual(results, [undefined, undefined, undefined]); + assert.strictEqual(callCount, 0); + + setTimeout(() => { + assert.strictEqual(callCount, 1); + + const results = [debounced('d'), debounced('e'), debounced('f')]; + assert.deepStrictEqual(results, ['c', 'c', 'c']); + assert.strictEqual(callCount, 1); + }, 128); + + setTimeout(() => { + assert.strictEqual(callCount, 2); + done(); + }, 256); + }); + + it('subsequent debounced calls return the last `func` result', (done) => { + const debounced = debounce(identity, 32); + debounced('a'); + + setTimeout(() => { + assert.notStrictEqual(debounced('b'), 'b'); + }, 64); + + setTimeout(() => { + assert.notStrictEqual(debounced('c'), 'c'); + done(); + }, 128); + }); + + it('should not immediately call `func` when `wait` is `0`', (done) => { + let callCount = 0, + debounced = debounce(() => { + ++callCount; + }, 0); + + debounced(); + debounced(); + assert.strictEqual(callCount, 0); + + setTimeout(() => { + assert.strictEqual(callCount, 1); + done(); + }, 5); + }); + + it('should apply default options', (done) => { + let callCount = 0, + debounced = debounce( + () => { + callCount++; + }, + 32, + {}, + ); + + debounced(); + assert.strictEqual(callCount, 0); + + setTimeout(() => { + assert.strictEqual(callCount, 1); + done(); + }, 64); + }); + + it('should support a `leading` option', (done) => { + const callCounts = [0, 0]; + + const withLeading = debounce( + () => { + callCounts[0]++; + }, + 32, + { leading: true }, + ); + + const withLeadingAndTrailing = debounce( + () => { + callCounts[1]++; + }, + 32, + { leading: true }, + ); + + withLeading(); + assert.strictEqual(callCounts[0], 1); + + withLeadingAndTrailing(); + withLeadingAndTrailing(); + assert.strictEqual(callCounts[1], 1); + + setTimeout(() => { + assert.deepStrictEqual(callCounts, [1, 2]); + + withLeading(); + assert.strictEqual(callCounts[0], 2); + + done(); + }, 64); + }); + + it('subsequent leading debounced calls return the last `func` result', (done) => { + const debounced = debounce(identity, 32, { leading: true, trailing: false }), + results = [debounced('a'), debounced('b')]; + + assert.deepStrictEqual(results, ['a', 'a']); + + setTimeout(() => { + const results = [debounced('c'), debounced('d')]; + assert.deepStrictEqual(results, ['c', 'c']); + done(); + }, 64); + }); + + it('should support a `trailing` option', (done) => { + let withCount = 0, + withoutCount = 0; + + const withTrailing = debounce( + () => { + withCount++; + }, + 32, + { trailing: true }, + ); + + const withoutTrailing = debounce( + () => { + withoutCount++; + }, + 32, + { trailing: false }, + ); + + withTrailing(); + assert.strictEqual(withCount, 0); + + withoutTrailing(); + assert.strictEqual(withoutCount, 0); + + setTimeout(() => { + assert.strictEqual(withCount, 1); + assert.strictEqual(withoutCount, 0); + done(); + }, 64); + }); + + it('should support a `maxWait` option', (done) => { + let callCount = 0; + + const debounced = debounce( + (value) => { + ++callCount; + return value; + }, + 32, + { maxWait: 64 }, + ); + + debounced(); + debounced(); + assert.strictEqual(callCount, 0); + + setTimeout(() => { + assert.strictEqual(callCount, 1); + debounced(); + debounced(); + assert.strictEqual(callCount, 1); + }, 128); + + setTimeout(() => { + assert.strictEqual(callCount, 2); + done(); + }, 256); + }); + + it('should support `maxWait` in a tight loop', (done) => { + let limit = argv || isPhantom ? 1000 : 320, + withCount = 0, + withoutCount = 0; + + const withMaxWait = debounce( + () => { + withCount++; + }, + 64, + { maxWait: 128 }, + ); + + const withoutMaxWait = debounce(() => { + withoutCount++; + }, 96); + + const start = +new Date(); + while (new Date() - start < limit) { + withMaxWait(); + withoutMaxWait(); + } + const actual = [Boolean(withoutCount), Boolean(withCount)]; + setTimeout(() => { + assert.deepStrictEqual(actual, [false, true]); + done(); + }, 1); + }); + + it('should queue a trailing call for subsequent debounced calls after `maxWait`', (done) => { + let callCount = 0; + + const debounced = debounce( + () => { + ++callCount; + }, + 200, + { maxWait: 200 }, + ); + + debounced(); + + setTimeout(debounced, 190); + setTimeout(debounced, 200); + setTimeout(debounced, 210); + + setTimeout(() => { + assert.strictEqual(callCount, 2); + done(); + }, 500); + }); + + it('should cancel `maxDelayed` when `delayed` is invoked', (done) => { + let callCount = 0; + + const debounced = debounce( + () => { + callCount++; + }, + 32, + { maxWait: 64 }, + ); + + debounced(); + + setTimeout(() => { + debounced(); + assert.strictEqual(callCount, 1); + }, 128); + + setTimeout(() => { + assert.strictEqual(callCount, 2); + done(); + }, 192); + }); + + it('should invoke the trailing call with the correct arguments and `this` binding', (done) => { + let actual, + callCount = 0, + object = {}; + + const debounced = debounce( + function (value) { + actual = [this]; + push.apply(actual, arguments); + return ++callCount != 2; + }, + 32, + { leading: true, maxWait: 64 }, + ); + + while (true) { + if (!debounced.call(object, 'a')) { + break; + } + } + setTimeout(() => { + assert.strictEqual(callCount, 2); + assert.deepStrictEqual(actual, [object, 'a']); + done(); + }, 64); + }); +}); diff --git a/test/debounce.test.js b/test/debounce.test.js deleted file mode 100644 index 184d9b91d..000000000 --- a/test/debounce.test.js +++ /dev/null @@ -1,250 +0,0 @@ -import assert from 'assert'; -import { identity, argv, isPhantom, push } from './utils.js'; -import debounce from '../debounce.js'; - -describe('debounce', function() { - it('should debounce a function', function(done) { - var callCount = 0; - - var debounced = debounce(function(value) { - ++callCount; - return value; - }, 32); - - var results = [debounced('a'), debounced('b'), debounced('c')]; - assert.deepStrictEqual(results, [undefined, undefined, undefined]); - assert.strictEqual(callCount, 0); - - setTimeout(function() { - assert.strictEqual(callCount, 1); - - var results = [debounced('d'), debounced('e'), debounced('f')]; - assert.deepStrictEqual(results, ['c', 'c', 'c']); - assert.strictEqual(callCount, 1); - }, 128); - - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 256); - }); - - it('subsequent debounced calls return the last `func` result', function(done) { - var debounced = debounce(identity, 32); - debounced('a'); - - setTimeout(function() { - assert.notStrictEqual(debounced('b'), 'b'); - }, 64); - - setTimeout(function() { - assert.notStrictEqual(debounced('c'), 'c'); - done(); - }, 128); - }); - - it('should not immediately call `func` when `wait` is `0`', function(done) { - var callCount = 0, - debounced = debounce(function() { ++callCount; }, 0); - - debounced(); - debounced(); - assert.strictEqual(callCount, 0); - - setTimeout(function() { - assert.strictEqual(callCount, 1); - done(); - }, 5); - }); - - it('should apply default options', function(done) { - var callCount = 0, - debounced = debounce(function() { callCount++; }, 32, {}); - - debounced(); - assert.strictEqual(callCount, 0); - - setTimeout(function() { - assert.strictEqual(callCount, 1); - done(); - }, 64); - }); - - it('should support a `leading` option', function(done) { - var callCounts = [0, 0]; - - var withLeading = debounce(function() { - callCounts[0]++; - }, 32, { 'leading': true }); - - var withLeadingAndTrailing = debounce(function() { - callCounts[1]++; - }, 32, { 'leading': true }); - - withLeading(); - assert.strictEqual(callCounts[0], 1); - - withLeadingAndTrailing(); - withLeadingAndTrailing(); - assert.strictEqual(callCounts[1], 1); - - setTimeout(function() { - assert.deepStrictEqual(callCounts, [1, 2]); - - withLeading(); - assert.strictEqual(callCounts[0], 2); - - done(); - }, 64); - }); - - it('subsequent leading debounced calls return the last `func` result', function(done) { - var debounced = debounce(identity, 32, { 'leading': true, 'trailing': false }), - results = [debounced('a'), debounced('b')]; - - assert.deepStrictEqual(results, ['a', 'a']); - - setTimeout(function() { - var results = [debounced('c'), debounced('d')]; - assert.deepStrictEqual(results, ['c', 'c']); - done(); - }, 64); - }); - - it('should support a `trailing` option', function(done) { - var withCount = 0, - withoutCount = 0; - - var withTrailing = debounce(function() { - withCount++; - }, 32, { 'trailing': true }); - - var withoutTrailing = debounce(function() { - withoutCount++; - }, 32, { 'trailing': false }); - - withTrailing(); - assert.strictEqual(withCount, 0); - - withoutTrailing(); - assert.strictEqual(withoutCount, 0); - - setTimeout(function() { - assert.strictEqual(withCount, 1); - assert.strictEqual(withoutCount, 0); - done(); - }, 64); - }); - - it('should support a `maxWait` option', function(done) { - var callCount = 0; - - var debounced = debounce(function(value) { - ++callCount; - return value; - }, 32, { 'maxWait': 64 }); - - debounced(); - debounced(); - assert.strictEqual(callCount, 0); - - setTimeout(function() { - assert.strictEqual(callCount, 1); - debounced(); - debounced(); - assert.strictEqual(callCount, 1); - }, 128); - - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 256); - }); - - it('should support `maxWait` in a tight loop', function(done) { - var limit = (argv || isPhantom) ? 1000 : 320, - withCount = 0, - withoutCount = 0; - - var withMaxWait = debounce(function() { - withCount++; - }, 64, { 'maxWait': 128 }); - - var withoutMaxWait = debounce(function() { - withoutCount++; - }, 96); - - var start = +new Date; - while ((new Date - start) < limit) { - withMaxWait(); - withoutMaxWait(); - } - var actual = [Boolean(withoutCount), Boolean(withCount)]; - setTimeout(function() { - assert.deepStrictEqual(actual, [false, true]); - done(); - }, 1); - }); - - it('should queue a trailing call for subsequent debounced calls after `maxWait`', function(done) { - var callCount = 0; - - var debounced = debounce(function() { - ++callCount; - }, 200, { 'maxWait': 200 }); - - debounced(); - - setTimeout(debounced, 190); - setTimeout(debounced, 200); - setTimeout(debounced, 210); - - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 500); - }); - - it('should cancel `maxDelayed` when `delayed` is invoked', function(done) { - var callCount = 0; - - var debounced = debounce(function() { - callCount++; - }, 32, { 'maxWait': 64 }); - - debounced(); - - setTimeout(function() { - debounced(); - assert.strictEqual(callCount, 1); - }, 128); - - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 192); - }); - - it('should invoke the trailing call with the correct arguments and `this` binding', function(done) { - var actual, - callCount = 0, - object = {}; - - var debounced = debounce(function(value) { - actual = [this]; - push.apply(actual, arguments); - return ++callCount != 2; - }, 32, { 'leading': true, 'maxWait': 64 }); - - while (true) { - if (!debounced.call(object, 'a')) { - break; - } - } - setTimeout(function() { - assert.strictEqual(callCount, 2); - assert.deepStrictEqual(actual, [object, 'a']); - done(); - }, 64); - }); -}); diff --git a/test/deburr.spec.ts b/test/deburr.spec.ts new file mode 100644 index 000000000..09265a29c --- /dev/null +++ b/test/deburr.spec.ts @@ -0,0 +1,26 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { burredLetters, deburredLetters, comboMarks } from './utils'; +import deburr from '../src/deburr'; + +describe('deburr', () => { + it('should convert Latin Unicode letters to basic Latin', () => { + const actual = lodashStable.map(burredLetters, deburr); + assert.deepStrictEqual(actual, deburredLetters); + }); + + it('should not deburr Latin mathematical operators', () => { + const operators = ['\xd7', '\xf7'], + actual = lodashStable.map(operators, deburr); + + assert.deepStrictEqual(actual, operators); + }); + + it('should deburr combining diacritical marks', () => { + const expected = lodashStable.map(comboMarks, lodashStable.constant('ei')); + + const actual = lodashStable.map(comboMarks, (chr) => deburr(`e${chr}i`)); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/deburr.test.js b/test/deburr.test.js deleted file mode 100644 index 5ab176f4a..000000000 --- a/test/deburr.test.js +++ /dev/null @@ -1,28 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { burredLetters, deburredLetters, comboMarks } from './utils.js'; -import deburr from '../deburr.js'; - -describe('deburr', function() { - it('should convert Latin Unicode letters to basic Latin', function() { - var actual = lodashStable.map(burredLetters, deburr); - assert.deepStrictEqual(actual, deburredLetters); - }); - - it('should not deburr Latin mathematical operators', function() { - var operators = ['\xd7', '\xf7'], - actual = lodashStable.map(operators, deburr); - - assert.deepStrictEqual(actual, operators); - }); - - it('should deburr combining diacritical marks', function() { - var expected = lodashStable.map(comboMarks, lodashStable.constant('ei')); - - var actual = lodashStable.map(comboMarks, function(chr) { - return deburr('e' + chr + 'i'); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/defaultTo.spec.ts b/test/defaultTo.spec.ts new file mode 100644 index 000000000..c615f643b --- /dev/null +++ b/test/defaultTo.spec.ts @@ -0,0 +1,16 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey } from './utils'; +import defaultTo from '../src/defaultTo'; + +describe('defaultTo', () => { + it('should return a default value if `value` is `NaN` or nullish', () => { + const expected = lodashStable.map(falsey, (value) => + value == null || value !== value ? 1 : value, + ); + + const actual = lodashStable.map(falsey, (value) => defaultTo(value, 1)); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/defaultTo.test.js b/test/defaultTo.test.js deleted file mode 100644 index 5d6dc5f3a..000000000 --- a/test/defaultTo.test.js +++ /dev/null @@ -1,18 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey } from './utils.js'; -import defaultTo from '../defaultTo.js'; - -describe('defaultTo', function() { - it('should return a default value if `value` is `NaN` or nullish', function() { - var expected = lodashStable.map(falsey, function(value) { - return (value == null || value !== value) ? 1 : value; - }); - - var actual = lodashStable.map(falsey, function(value) { - return defaultTo(value, 1); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/defaults.spec.ts b/test/defaults.spec.ts new file mode 100644 index 000000000..1cf10cab9 --- /dev/null +++ b/test/defaults.spec.ts @@ -0,0 +1,66 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { objectProto } from './utils'; +import defaults from '../src/defaults'; + +describe('defaults', () => { + it('should assign source properties if missing on `object`', () => { + const actual = defaults({ a: 1 }, { a: 2, b: 2 }); + assert.deepStrictEqual(actual, { a: 1, b: 2 }); + }); + + it('should accept multiple sources', () => { + let expected = { a: 1, b: 2, c: 3 }, + actual = defaults({ a: 1, b: 2 }, { b: 3 }, { c: 3 }); + + assert.deepStrictEqual(actual, expected); + + actual = defaults({ a: 1, b: 2 }, { b: 3, c: 3 }, { c: 2 }); + assert.deepStrictEqual(actual, expected); + }); + + it('should not overwrite `null` values', () => { + const actual = defaults({ a: null }, { a: 1 }); + assert.strictEqual(actual.a, null); + }); + + it('should overwrite `undefined` values', () => { + const actual = defaults({ a: undefined }, { a: 1 }); + assert.strictEqual(actual.a, 1); + }); + + it('should assign `undefined` values', () => { + const source = { a: undefined, b: 1 }, + actual = defaults({}, source); + + assert.deepStrictEqual(actual, { a: undefined, b: 1 }); + }); + + it('should assign properties that shadow those on `Object.prototype`', () => { + const object = { + constructor: objectProto.constructor, + hasOwnProperty: objectProto.hasOwnProperty, + isPrototypeOf: objectProto.isPrototypeOf, + propertyIsEnumerable: objectProto.propertyIsEnumerable, + toLocaleString: objectProto.toLocaleString, + toString: objectProto.toString, + valueOf: objectProto.valueOf, + }; + + const source = { + constructor: 1, + hasOwnProperty: 2, + isPrototypeOf: 3, + propertyIsEnumerable: 4, + toLocaleString: 5, + toString: 6, + valueOf: 7, + }; + + let expected = lodashStable.clone(source); + assert.deepStrictEqual(defaults({}, source), expected); + + expected = lodashStable.clone(object); + assert.deepStrictEqual(defaults({}, object, source), expected); + }); +}); diff --git a/test/defaults.test.js b/test/defaults.test.js deleted file mode 100644 index 867f31d80..000000000 --- a/test/defaults.test.js +++ /dev/null @@ -1,66 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { objectProto } from './utils.js'; -import defaults from '../defaults.js'; - -describe('defaults', function() { - it('should assign source properties if missing on `object`', function() { - var actual = defaults({ 'a': 1 }, { 'a': 2, 'b': 2 }); - assert.deepStrictEqual(actual, { 'a': 1, 'b': 2 }); - }); - - it('should accept multiple sources', function() { - var expected = { 'a': 1, 'b': 2, 'c': 3 }, - actual = defaults({ 'a': 1, 'b': 2 }, { 'b': 3 }, { 'c': 3 }); - - assert.deepStrictEqual(actual, expected); - - actual = defaults({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 3 }, { 'c': 2 }); - assert.deepStrictEqual(actual, expected); - }); - - it('should not overwrite `null` values', function() { - var actual = defaults({ 'a': null }, { 'a': 1 }); - assert.strictEqual(actual.a, null); - }); - - it('should overwrite `undefined` values', function() { - var actual = defaults({ 'a': undefined }, { 'a': 1 }); - assert.strictEqual(actual.a, 1); - }); - - it('should assign `undefined` values', function() { - var source = { 'a': undefined, 'b': 1 }, - actual = defaults({}, source); - - assert.deepStrictEqual(actual, { 'a': undefined, 'b': 1 }); - }); - - it('should assign properties that shadow those on `Object.prototype`', function() { - var object = { - 'constructor': objectProto.constructor, - 'hasOwnProperty': objectProto.hasOwnProperty, - 'isPrototypeOf': objectProto.isPrototypeOf, - 'propertyIsEnumerable': objectProto.propertyIsEnumerable, - 'toLocaleString': objectProto.toLocaleString, - 'toString': objectProto.toString, - 'valueOf': objectProto.valueOf - }; - - var source = { - 'constructor': 1, - 'hasOwnProperty': 2, - 'isPrototypeOf': 3, - 'propertyIsEnumerable': 4, - 'toLocaleString': 5, - 'toString': 6, - 'valueOf': 7 - }; - - var expected = lodashStable.clone(source); - assert.deepStrictEqual(defaults({}, source), expected); - - expected = lodashStable.clone(object); - assert.deepStrictEqual(defaults({}, object, source), expected); - }); -}); diff --git a/test/defaultsDeep.js b/test/defaultsDeep.js deleted file mode 100644 index a4a9ff2fb..000000000 --- a/test/defaultsDeep.js +++ /dev/null @@ -1,101 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { noop } from './utils.js'; -import defaultsDeep from '../defaultsDeep.js'; - -describe('defaultsDeep', function() { - it('should deep assign source properties if missing on `object`', function() { - var object = { 'a': { 'b': 2 }, 'd': 4 }, - source = { 'a': { 'b': 3, 'c': 3 }, 'e': 5 }, - expected = { 'a': { 'b': 2, 'c': 3 }, 'd': 4, 'e': 5 }; - - assert.deepStrictEqual(defaultsDeep(object, source), expected); - }); - - it('should accept multiple sources', function() { - var source1 = { 'a': { 'b': 3 } }, - source2 = { 'a': { 'c': 3 } }, - source3 = { 'a': { 'b': 3, 'c': 3 } }, - source4 = { 'a': { 'c': 4 } }, - expected = { 'a': { 'b': 2, 'c': 3 } }; - - assert.deepStrictEqual(defaultsDeep({ 'a': { 'b': 2 } }, source1, source2), expected); - assert.deepStrictEqual(defaultsDeep({ 'a': { 'b': 2 } }, source3, source4), expected); - }); - - it('should not overwrite `null` values', function() { - var object = { 'a': { 'b': null } }, - source = { 'a': { 'b': 2 } }, - actual = defaultsDeep(object, source); - - assert.strictEqual(actual.a.b, null); - }); - - it('should not overwrite regexp values', function() { - var object = { 'a': { 'b': /x/ } }, - source = { 'a': { 'b': /y/ } }, - actual = defaultsDeep(object, source); - - assert.deepStrictEqual(actual.a.b, /x/); - }); - - it('should not convert function properties to objects', function() { - var actual = defaultsDeep({}, { 'a': noop }); - assert.strictEqual(actual.a, noop); - - actual = defaultsDeep({}, { 'a': { 'b': noop } }); - assert.strictEqual(actual.a.b, noop); - }); - - it('should overwrite `undefined` values', function() { - var object = { 'a': { 'b': undefined } }, - source = { 'a': { 'b': 2 } }, - actual = defaultsDeep(object, source); - - assert.strictEqual(actual.a.b, 2); - }); - - it('should assign `undefined` values', function() { - var source = { 'a': undefined, 'b': { 'c': undefined, 'd': 1 } }, - expected = lodashStable.cloneDeep(source), - actual = defaultsDeep({}, source); - - assert.deepStrictEqual(actual, expected); - }); - - it('should merge sources containing circular references', function() { - var object = { - 'foo': { 'b': { 'c': { 'd': {} } } }, - 'bar': { 'a': 2 } - }; - - var source = { - 'foo': { 'b': { 'c': { 'd': {} } } }, - 'bar': {} - }; - - object.foo.b.c.d = object; - source.foo.b.c.d = source; - source.bar.b = source.foo.b; - - var actual = defaultsDeep(object, source); - - assert.strictEqual(actual.bar.b, actual.foo.b); - assert.strictEqual(actual.foo.b.c.d, actual.foo.b.c.d.foo.b.c.d); - }); - - it('should not modify sources', function() { - var source1 = { 'a': 1, 'b': { 'c': 2 } }, - source2 = { 'b': { 'c': 3, 'd': 3 } }, - actual = defaultsDeep({}, source1, source2); - - assert.deepStrictEqual(actual, { 'a': 1, 'b': { 'c': 2, 'd': 3 } }); - assert.deepStrictEqual(source1, { 'a': 1, 'b': { 'c': 2 } }); - assert.deepStrictEqual(source2, { 'b': { 'c': 3, 'd': 3 } }); - }); - - it('should not attempt a merge of a string into an array', function() { - var actual = defaultsDeep({ 'a': ['abc'] }, { 'a': 'abc' }); - assert.deepStrictEqual(actual.a, ['abc']); - }); -}); diff --git a/test/defaultsDeep.spec.ts b/test/defaultsDeep.spec.ts new file mode 100644 index 000000000..9bfc57d2d --- /dev/null +++ b/test/defaultsDeep.spec.ts @@ -0,0 +1,101 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { noop } from './utils'; +import defaultsDeep from '../src/defaultsDeep'; + +describe('defaultsDeep', () => { + it('should deep assign source properties if missing on `object`', () => { + const object = { a: { b: 2 }, d: 4 }, + source = { a: { b: 3, c: 3 }, e: 5 }, + expected = { a: { b: 2, c: 3 }, d: 4, e: 5 }; + + assert.deepStrictEqual(defaultsDeep(object, source), expected); + }); + + it('should accept multiple sources', () => { + const source1 = { a: { b: 3 } }, + source2 = { a: { c: 3 } }, + source3 = { a: { b: 3, c: 3 } }, + source4 = { a: { c: 4 } }, + expected = { a: { b: 2, c: 3 } }; + + assert.deepStrictEqual(defaultsDeep({ a: { b: 2 } }, source1, source2), expected); + assert.deepStrictEqual(defaultsDeep({ a: { b: 2 } }, source3, source4), expected); + }); + + it('should not overwrite `null` values', () => { + const object = { a: { b: null } }, + source = { a: { b: 2 } }, + actual = defaultsDeep(object, source); + + assert.strictEqual(actual.a.b, null); + }); + + it('should not overwrite regexp values', () => { + const object = { a: { b: /x/ } }, + source = { a: { b: /y/ } }, + actual = defaultsDeep(object, source); + + assert.deepStrictEqual(actual.a.b, /x/); + }); + + it('should not convert function properties to objects', () => { + let actual = defaultsDeep({}, { a: noop }); + assert.strictEqual(actual.a, noop); + + actual = defaultsDeep({}, { a: { b: noop } }); + assert.strictEqual(actual.a.b, noop); + }); + + it('should overwrite `undefined` values', () => { + const object = { a: { b: undefined } }, + source = { a: { b: 2 } }, + actual = defaultsDeep(object, source); + + assert.strictEqual(actual.a.b, 2); + }); + + it('should assign `undefined` values', () => { + const source = { a: undefined, b: { c: undefined, d: 1 } }, + expected = lodashStable.cloneDeep(source), + actual = defaultsDeep({}, source); + + assert.deepStrictEqual(actual, expected); + }); + + it('should merge sources containing circular references', () => { + const object = { + foo: { b: { c: { d: {} } } }, + bar: { a: 2 }, + }; + + const source = { + foo: { b: { c: { d: {} } } }, + bar: {}, + }; + + object.foo.b.c.d = object; + source.foo.b.c.d = source; + source.bar.b = source.foo.b; + + const actual = defaultsDeep(object, source); + + assert.strictEqual(actual.bar.b, actual.foo.b); + assert.strictEqual(actual.foo.b.c.d, actual.foo.b.c.d.foo.b.c.d); + }); + + it('should not modify sources', () => { + const source1 = { a: 1, b: { c: 2 } }, + source2 = { b: { c: 3, d: 3 } }, + actual = defaultsDeep({}, source1, source2); + + assert.deepStrictEqual(actual, { a: 1, b: { c: 2, d: 3 } }); + assert.deepStrictEqual(source1, { a: 1, b: { c: 2 } }); + assert.deepStrictEqual(source2, { b: { c: 3, d: 3 } }); + }); + + it('should not attempt a merge of a string into an array', () => { + const actual = defaultsDeep({ a: ['abc'] }, { a: 'abc' }); + assert.deepStrictEqual(actual.a, ['abc']); + }); +}); diff --git a/test/defer.spec.ts b/test/defer.spec.ts new file mode 100644 index 000000000..04092ba6c --- /dev/null +++ b/test/defer.spec.ts @@ -0,0 +1,48 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import defer from '../src/defer'; + +describe('defer', () => { + it('should defer `func` execution', (done) => { + let pass = false; + defer(() => { + pass = true; + }); + + setTimeout(() => { + assert.ok(pass); + done(); + }, 32); + }); + + it('should provide additional arguments to `func`', (done) => { + let args; + + defer( + function () { + args = slice.call(arguments); + }, + 1, + 2, + ); + + setTimeout(() => { + assert.deepStrictEqual(args, [1, 2]); + done(); + }, 32); + }); + + it('should be cancelable', (done) => { + let pass = true, + timerId = defer(() => { + pass = false; + }); + + clearTimeout(timerId); + + setTimeout(() => { + assert.ok(pass); + done(); + }, 32); + }); +}); diff --git a/test/defer.test.js b/test/defer.test.js deleted file mode 100644 index 421fab372..000000000 --- a/test/defer.test.js +++ /dev/null @@ -1,40 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import defer from '../defer.js'; - -describe('defer', function() { - it('should defer `func` execution', function(done) { - var pass = false; - defer(function() { pass = true; }); - - setTimeout(function() { - assert.ok(pass); - done(); - }, 32); - }); - - it('should provide additional arguments to `func`', function(done) { - var args; - - defer(function() { - args = slice.call(arguments); - }, 1, 2); - - setTimeout(function() { - assert.deepStrictEqual(args, [1, 2]); - done(); - }, 32); - }); - - it('should be cancelable', function(done) { - var pass = true, - timerId = defer(function() { pass = false; }); - - clearTimeout(timerId); - - setTimeout(function() { - assert.ok(pass); - done(); - }, 32); - }); -}); diff --git a/test/delay.js b/test/delay.js deleted file mode 100644 index ef3ebcae4..000000000 --- a/test/delay.js +++ /dev/null @@ -1,67 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import delay from '../delay.js'; - -describe('delay', function() { - it('should delay `func` execution', function(done) { - var pass = false; - delay(function() { pass = true; }, 32); - - setTimeout(function() { - assert.ok(!pass); - }, 1); - - setTimeout(function() { - assert.ok(pass); - done(); - }, 64); - }); - - it('should provide additional arguments to `func`', function(done) { - var args; - - delay(function() { - args = slice.call(arguments); - }, 32, 1, 2); - - setTimeout(function() { - assert.deepStrictEqual(args, [1, 2]); - done(); - }, 64); - }); - - it('should use a default `wait` of `0`', function(done) { - var pass = false; - delay(function() { pass = true; }); - - assert.ok(!pass); - - setTimeout(function() { - assert.ok(pass); - done(); - }, 0); - }); - - it('should be cancelable', function(done) { - var pass = true, - timerId = delay(function() { pass = false; }, 32); - - clearTimeout(timerId); - - setTimeout(function() { - assert.ok(pass); - done(); - }, 64); - }); - - it('should work with mocked `setTimeout`', function() { - var pass = false, - setTimeout = root.setTimeout; - - setProperty(root, 'setTimeout', function(func) { func(); }); - delay(function() { pass = true; }, 32); - setProperty(root, 'setTimeout', setTimeout); - - assert.ok(pass); - }); -}); diff --git a/test/delay.spec.ts b/test/delay.spec.ts new file mode 100644 index 000000000..4715ff321 --- /dev/null +++ b/test/delay.spec.ts @@ -0,0 +1,82 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import delay from '../src/delay'; + +describe('delay', () => { + it('should delay `func` execution', (done) => { + let pass = false; + delay(() => { + pass = true; + }, 32); + + setTimeout(() => { + assert.ok(!pass); + }, 1); + + setTimeout(() => { + assert.ok(pass); + done(); + }, 64); + }); + + it('should provide additional arguments to `func`', (done) => { + let args; + + delay( + function () { + args = slice.call(arguments); + }, + 32, + 1, + 2, + ); + + setTimeout(() => { + assert.deepStrictEqual(args, [1, 2]); + done(); + }, 64); + }); + + it('should use a default `wait` of `0`', (done) => { + let pass = false; + delay(() => { + pass = true; + }); + + assert.ok(!pass); + + setTimeout(() => { + assert.ok(pass); + done(); + }, 0); + }); + + it('should be cancelable', (done) => { + let pass = true, + timerId = delay(() => { + pass = false; + }, 32); + + clearTimeout(timerId); + + setTimeout(() => { + assert.ok(pass); + done(); + }, 64); + }); + + it('should work with mocked `setTimeout`', () => { + let pass = false, + setTimeout = root.setTimeout; + + setProperty(root, 'setTimeout', (func) => { + func(); + }); + delay(() => { + pass = true; + }, 32); + setProperty(root, 'setTimeout', setTimeout); + + assert.ok(pass); + }); +}); diff --git a/test/difference-methods.js b/test/difference-methods.js deleted file mode 100644 index 6591193cf..000000000 --- a/test/difference-methods.js +++ /dev/null @@ -1,85 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, LARGE_ARRAY_SIZE, stubOne, stubNaN, args } from './utils.js'; - -describe('difference methods', function() { - lodashStable.each(['difference', 'differenceBy', 'differenceWith'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should return the difference of two arrays', function() { - var actual = func([2, 1], [2, 3]); - assert.deepStrictEqual(actual, [1]); - }); - - it('`_.' + methodName + '` should return the difference of multiple arrays', function() { - var actual = func([2, 1, 2, 3], [3, 4], [3, 2]); - assert.deepStrictEqual(actual, [1]); - }); - - it('`_.' + methodName + '` should treat `-0` as `0`', function() { - var array = [-0, 0]; - - var actual = lodashStable.map(array, function(value) { - return func(array, [value]); - }); - - assert.deepStrictEqual(actual, [[], []]); - - actual = lodashStable.map(func([-0, 1], [1]), lodashStable.toString); - assert.deepStrictEqual(actual, ['0']); - }); - - it('`_.' + methodName + '` should match `NaN`', function() { - assert.deepStrictEqual(func([1, NaN, 3], [NaN, 5, NaN]), [1, 3]); - }); - - it('`_.' + methodName + '` should work with large arrays', function() { - var array1 = lodashStable.range(LARGE_ARRAY_SIZE + 1), - array2 = lodashStable.range(LARGE_ARRAY_SIZE), - a = {}, - b = {}, - c = {}; - - array1.push(a, b, c); - array2.push(b, c, a); - - assert.deepStrictEqual(func(array1, array2), [LARGE_ARRAY_SIZE]); - }); - - it('`_.' + methodName + '` should work with large arrays of `-0` as `0`', function() { - var array = [-0, 0]; - - var actual = lodashStable.map(array, function(value) { - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(value)); - return func(array, largeArray); - }); - - assert.deepStrictEqual(actual, [[], []]); - - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubOne); - actual = lodashStable.map(func([-0, 1], largeArray), lodashStable.toString); - assert.deepStrictEqual(actual, ['0']); - }); - - it('`_.' + methodName + '` should work with large arrays of `NaN`', function() { - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubNaN); - assert.deepStrictEqual(func([1, NaN, 3], largeArray), [1, 3]); - }); - - it('`_.' + methodName + '` should work with large arrays of objects', function() { - var object1 = {}, - object2 = {}, - largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object1)); - - assert.deepStrictEqual(func([object1, object2], largeArray), [object2]); - }); - - it('`_.' + methodName + '` should ignore values that are not array-like', function() { - var array = [1, null, 3]; - - assert.deepStrictEqual(func(args, 3, { '0': 1 }), [1, 2, 3]); - assert.deepStrictEqual(func(null, array, 1), []); - assert.deepStrictEqual(func(array, args, null), [null]); - }); - }); -}); diff --git a/test/difference-methods.spec.ts b/test/difference-methods.spec.ts new file mode 100644 index 000000000..9c8e393ae --- /dev/null +++ b/test/difference-methods.spec.ts @@ -0,0 +1,86 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, LARGE_ARRAY_SIZE, stubOne, stubNaN, args } from './utils'; + +describe('difference methods', () => { + lodashStable.each(['difference', 'differenceBy', 'differenceWith'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should return the difference of two arrays`, () => { + const actual = func([2, 1], [2, 3]); + assert.deepStrictEqual(actual, [1]); + }); + + it(`\`_.${methodName}\` should return the difference of multiple arrays`, () => { + const actual = func([2, 1, 2, 3], [3, 4], [3, 2]); + assert.deepStrictEqual(actual, [1]); + }); + + it(`\`_.${methodName}\` should treat \`-0\` as \`0\``, () => { + const array = [-0, 0]; + + let actual = lodashStable.map(array, (value) => func(array, [value])); + + assert.deepStrictEqual(actual, [[], []]); + + actual = lodashStable.map(func([-0, 1], [1]), lodashStable.toString); + assert.deepStrictEqual(actual, ['0']); + }); + + it(`\`_.${methodName}\` should match \`NaN\``, () => { + assert.deepStrictEqual(func([1, NaN, 3], [NaN, 5, NaN]), [1, 3]); + }); + + it(`\`_.${methodName}\` should work with large arrays`, () => { + const array1 = lodashStable.range(LARGE_ARRAY_SIZE + 1), + array2 = lodashStable.range(LARGE_ARRAY_SIZE), + a = {}, + b = {}, + c = {}; + + array1.push(a, b, c); + array2.push(b, c, a); + + assert.deepStrictEqual(func(array1, array2), [LARGE_ARRAY_SIZE]); + }); + + it(`\`_.${methodName}\` should work with large arrays of \`-0\` as \`0\``, () => { + const array = [-0, 0]; + + let actual = lodashStable.map(array, (value) => { + const largeArray = lodashStable.times( + LARGE_ARRAY_SIZE, + lodashStable.constant(value), + ); + return func(array, largeArray); + }); + + assert.deepStrictEqual(actual, [[], []]); + + const largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubOne); + actual = lodashStable.map(func([-0, 1], largeArray), lodashStable.toString); + assert.deepStrictEqual(actual, ['0']); + }); + + it(`\`_.${methodName}\` should work with large arrays of \`NaN\``, () => { + const largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubNaN); + assert.deepStrictEqual(func([1, NaN, 3], largeArray), [1, 3]); + }); + + it(`\`_.${methodName}\` should work with large arrays of objects`, () => { + const object1 = {}, + object2 = {}, + largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object1)); + + assert.deepStrictEqual(func([object1, object2], largeArray), [object2]); + }); + + it(`\`_.${methodName}\` should ignore values that are not array-like`, () => { + const array = [1, null, 3]; + + assert.deepStrictEqual(func(args, 3, { '0': 1 }), [1, 2, 3]); + assert.deepStrictEqual(func(null, array, 1), []); + assert.deepStrictEqual(func(array, args, null), [null]); + }); + }); +}); diff --git a/test/differenceBy.js b/test/differenceBy.js deleted file mode 100644 index af5ca665b..000000000 --- a/test/differenceBy.js +++ /dev/null @@ -1,23 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import differenceBy from '../differenceBy.js'; - -describe('differenceBy', function() { - it('should accept an `iteratee`', function() { - var actual = differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); - assert.deepStrictEqual(actual, [1.2]); - - actual = differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); - assert.deepStrictEqual(actual, [{ 'x': 2 }]); - }); - - it('should provide correct `iteratee` arguments', function() { - var args; - - differenceBy([2.1, 1.2], [2.3, 3.4], function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [2.3]); - }); -}); diff --git a/test/differenceBy.spec.ts b/test/differenceBy.spec.ts new file mode 100644 index 000000000..3a120e4e3 --- /dev/null +++ b/test/differenceBy.spec.ts @@ -0,0 +1,23 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import differenceBy from '../src/differenceBy'; + +describe('differenceBy', () => { + it('should accept an `iteratee`', () => { + let actual = differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); + assert.deepStrictEqual(actual, [1.2]); + + actual = differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], 'x'); + assert.deepStrictEqual(actual, [{ x: 2 }]); + }); + + it('should provide correct `iteratee` arguments', () => { + let args; + + differenceBy([2.1, 1.2], [2.3, 3.4], function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [2.3]); + }); +}); diff --git a/test/differenceWith.spec.ts b/test/differenceWith.spec.ts new file mode 100644 index 000000000..984444bbc --- /dev/null +++ b/test/differenceWith.spec.ts @@ -0,0 +1,29 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE, stubOne } from './utils'; +import differenceWith from '../src/differenceWith'; + +describe('differenceWith', () => { + it('should work with a `comparator`', () => { + const objects = [ + { x: 1, y: 2 }, + { x: 2, y: 1 }, + ], + actual = differenceWith(objects, [{ x: 1, y: 2 }], lodashStable.isEqual); + + assert.deepStrictEqual(actual, [objects[1]]); + }); + + it('should preserve the sign of `0`', () => { + const array = [-0, 1], + largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubOne), + others = [[1], largeArray], + expected = lodashStable.map(others, lodashStable.constant(['-0'])); + + const actual = lodashStable.map(others, (other) => + lodashStable.map(differenceWith(array, other, lodashStable.eq), lodashStable.toString), + ); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/differenceWith.test.js b/test/differenceWith.test.js deleted file mode 100644 index 1c7c49d40..000000000 --- a/test/differenceWith.test.js +++ /dev/null @@ -1,26 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE, stubOne } from './utils.js'; -import differenceWith from '../differenceWith.js'; - -describe('differenceWith', function() { - it('should work with a `comparator`', function() { - var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }], - actual = differenceWith(objects, [{ 'x': 1, 'y': 2 }], lodashStable.isEqual); - - assert.deepStrictEqual(actual, [objects[1]]); - }); - - it('should preserve the sign of `0`', function() { - var array = [-0, 1], - largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubOne), - others = [[1], largeArray], - expected = lodashStable.map(others, lodashStable.constant(['-0'])); - - var actual = lodashStable.map(others, function(other) { - return lodashStable.map(differenceWith(array, other, lodashStable.eq), lodashStable.toString); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/divide.spec.ts b/test/divide.spec.ts new file mode 100644 index 000000000..45c32e56f --- /dev/null +++ b/test/divide.spec.ts @@ -0,0 +1,15 @@ +import assert from 'node:assert'; +import divide from '../src/divide'; + +describe('divide', () => { + it('should divide two numbers', () => { + assert.strictEqual(divide(6, 4), 1.5); + assert.strictEqual(divide(-6, 4), -1.5); + assert.strictEqual(divide(-6, -4), 1.5); + }); + + it('should coerce arguments to numbers', () => { + assert.strictEqual(divide('6', '4'), 1.5); + assert.deepStrictEqual(divide('x', 'y'), NaN); + }); +}); diff --git a/test/divide.test.js b/test/divide.test.js deleted file mode 100644 index 495a6bb70..000000000 --- a/test/divide.test.js +++ /dev/null @@ -1,15 +0,0 @@ -import assert from 'assert'; -import divide from '../divide.js'; - -describe('divide', function() { - it('should divide two numbers', function() { - assert.strictEqual(divide(6, 4), 1.5); - assert.strictEqual(divide(-6, 4), -1.5); - assert.strictEqual(divide(-6, -4), 1.5); - }); - - it('should coerce arguments to numbers', function() { - assert.strictEqual(divide('6', '4'), 1.5); - assert.deepStrictEqual(divide('x', 'y'), NaN); - }); -}); diff --git a/test/drop.spec.ts b/test/drop.spec.ts new file mode 100644 index 000000000..c2e4ccba5 --- /dev/null +++ b/test/drop.spec.ts @@ -0,0 +1,66 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils'; +import drop from '../src/drop'; + +describe('drop', () => { + const array = [1, 2, 3]; + + it('should drop the first two elements', () => { + assert.deepStrictEqual(drop(array, 2), [3]); + }); + + it('should treat falsey `n` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, (value) => + value === undefined ? [2, 3] : array, + ); + + const actual = lodashStable.map(falsey, (n) => drop(array, n)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return all elements when `n` < `1`', () => { + lodashStable.each([0, -1, -Infinity], (n) => { + assert.deepStrictEqual(drop(array, n), array); + }); + }); + + it('should return an empty array when `n` >= `length`', () => { + lodashStable.each([3, 4, 2 ** 32, Infinity], (n) => { + assert.deepStrictEqual(drop(array, n), []); + }); + }); + + it('should coerce `n` to an integer', () => { + assert.deepStrictEqual(drop(array, 1.6), [2, 3]); + }); + + it('should work in a lazy sequence', () => { + var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), + predicate = function (value) { + values.push(value); + return isEven(value); + }, + values = [], + actual = _(array).drop(2).drop().value(); + + assert.deepEqual(actual, array.slice(3)); + + actual = _(array).filter(predicate).drop(2).drop().value(); + assert.deepEqual(values, array); + assert.deepEqual(actual, drop(drop(_.filter(array, predicate), 2))); + + actual = _(array).drop(2).dropRight().drop().dropRight(2).value(); + assert.deepEqual(actual, _.dropRight(drop(_.dropRight(drop(array, 2))), 2)); + + values = []; + + actual = _(array).drop().filter(predicate).drop(2).dropRight().drop().dropRight(2).value(); + assert.deepEqual(values, array.slice(1)); + assert.deepEqual( + actual, + _.dropRight(drop(_.dropRight(drop(_.filter(drop(array), predicate), 2))), 2), + ); + }); +}); diff --git a/test/drop.test.js b/test/drop.test.js deleted file mode 100644 index 5011c70c0..000000000 --- a/test/drop.test.js +++ /dev/null @@ -1,62 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils.js'; -import drop from '../drop.js'; - -describe('drop', function() { - var array = [1, 2, 3]; - - it('should drop the first two elements', function() { - assert.deepStrictEqual(drop(array, 2), [3]); - }); - - it('should treat falsey `n` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? [2, 3] : array; - }); - - var actual = lodashStable.map(falsey, function(n) { - return drop(array, n); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return all elements when `n` < `1`', function() { - lodashStable.each([0, -1, -Infinity], function(n) { - assert.deepStrictEqual(drop(array, n), array); - }); - }); - - it('should return an empty array when `n` >= `length`', function() { - lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - assert.deepStrictEqual(drop(array, n), []); - }); - }); - - it('should coerce `n` to an integer', function() { - assert.deepStrictEqual(drop(array, 1.6), [2, 3]); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), - predicate = function(value) { values.push(value); return isEven(value); }, - values = [], - actual = _(array).drop(2).drop().value(); - - assert.deepEqual(actual, array.slice(3)); - - actual = _(array).filter(predicate).drop(2).drop().value(); - assert.deepEqual(values, array); - assert.deepEqual(actual, drop(drop(_.filter(array, predicate), 2))); - - actual = _(array).drop(2).dropRight().drop().dropRight(2).value(); - assert.deepEqual(actual, _.dropRight(drop(_.dropRight(drop(array, 2))), 2)); - - values = []; - - actual = _(array).drop().filter(predicate).drop(2).dropRight().drop().dropRight(2).value(); - assert.deepEqual(values, array.slice(1)); - assert.deepEqual(actual, _.dropRight(drop(_.dropRight(drop(_.filter(drop(array), predicate), 2))), 2)); - }); -}); diff --git a/test/dropRight.spec.ts b/test/dropRight.spec.ts new file mode 100644 index 000000000..6f27a323c --- /dev/null +++ b/test/dropRight.spec.ts @@ -0,0 +1,73 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils'; +import dropRight from '../src/dropRight'; + +describe('dropRight', () => { + const array = [1, 2, 3]; + + it('should drop the last two elements', () => { + assert.deepStrictEqual(dropRight(array, 2), [1]); + }); + + it('should treat falsey `n` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, (value) => + value === undefined ? [1, 2] : array, + ); + + const actual = lodashStable.map(falsey, (n) => dropRight(array, n)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return all elements when `n` < `1`', () => { + lodashStable.each([0, -1, -Infinity], (n) => { + assert.deepStrictEqual(dropRight(array, n), array); + }); + }); + + it('should return an empty array when `n` >= `length`', () => { + lodashStable.each([3, 4, 2 ** 32, Infinity], (n) => { + assert.deepStrictEqual(dropRight(array, n), []); + }); + }); + + it('should coerce `n` to an integer', () => { + assert.deepStrictEqual(dropRight(array, 1.6), [1, 2]); + }); + + it('should work in a lazy sequence', () => { + var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), + predicate = function (value) { + values.push(value); + return isEven(value); + }, + values = [], + actual = _(array).dropRight(2).dropRight().value(); + + assert.deepEqual(actual, array.slice(0, -3)); + + actual = _(array).filter(predicate).dropRight(2).dropRight().value(); + assert.deepEqual(values, array); + assert.deepEqual(actual, dropRight(dropRight(_.filter(array, predicate), 2))); + + actual = _(array).dropRight(2).drop().dropRight().drop(2).value(); + assert.deepEqual(actual, _.drop(dropRight(_.drop(dropRight(array, 2))), 2)); + + values = []; + + actual = _(array) + .dropRight() + .filter(predicate) + .dropRight(2) + .drop() + .dropRight() + .drop(2) + .value(); + assert.deepEqual(values, array.slice(0, -1)); + assert.deepEqual( + actual, + _.drop(dropRight(_.drop(dropRight(_.filter(dropRight(array), predicate), 2))), 2), + ); + }); +}); diff --git a/test/dropRight.test.js b/test/dropRight.test.js deleted file mode 100644 index 040ecc6cf..000000000 --- a/test/dropRight.test.js +++ /dev/null @@ -1,62 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils.js'; -import dropRight from '../dropRight.js'; - -describe('dropRight', function() { - var array = [1, 2, 3]; - - it('should drop the last two elements', function() { - assert.deepStrictEqual(dropRight(array, 2), [1]); - }); - - it('should treat falsey `n` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? [1, 2] : array; - }); - - var actual = lodashStable.map(falsey, function(n) { - return dropRight(array, n); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return all elements when `n` < `1`', function() { - lodashStable.each([0, -1, -Infinity], function(n) { - assert.deepStrictEqual(dropRight(array, n), array); - }); - }); - - it('should return an empty array when `n` >= `length`', function() { - lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - assert.deepStrictEqual(dropRight(array, n), []); - }); - }); - - it('should coerce `n` to an integer', function() { - assert.deepStrictEqual(dropRight(array, 1.6), [1, 2]); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), - predicate = function(value) { values.push(value); return isEven(value); }, - values = [], - actual = _(array).dropRight(2).dropRight().value(); - - assert.deepEqual(actual, array.slice(0, -3)); - - actual = _(array).filter(predicate).dropRight(2).dropRight().value(); - assert.deepEqual(values, array); - assert.deepEqual(actual, dropRight(dropRight(_.filter(array, predicate), 2))); - - actual = _(array).dropRight(2).drop().dropRight().drop(2).value(); - assert.deepEqual(actual, _.drop(dropRight(_.drop(dropRight(array, 2))), 2)); - - values = []; - - actual = _(array).dropRight().filter(predicate).dropRight(2).drop().dropRight().drop(2).value(); - assert.deepEqual(values, array.slice(0, -1)); - assert.deepEqual(actual, _.drop(dropRight(_.drop(dropRight(_.filter(dropRight(array), predicate), 2))), 2)); - }); -}); diff --git a/test/dropRightWhile.js b/test/dropRightWhile.js deleted file mode 100644 index 07dceadde..000000000 --- a/test/dropRightWhile.js +++ /dev/null @@ -1,52 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import dropRightWhile from '../dropRightWhile.js'; - -describe('dropRightWhile', function() { - var array = [1, 2, 3, 4]; - - var objects = [ - { 'a': 0, 'b': 0 }, - { 'a': 1, 'b': 1 }, - { 'a': 2, 'b': 2 } - ]; - - it('should drop elements while `predicate` returns truthy', function() { - var actual = dropRightWhile(array, function(n) { - return n > 2; - }); - - assert.deepStrictEqual(actual, [1, 2]); - }); - - it('should provide correct `predicate` arguments', function() { - var args; - - dropRightWhile(array, function() { - args = slice.call(arguments); - }); - - assert.deepStrictEqual(args, [4, 3, array]); - }); - - it('should work with `_.matches` shorthands', function() { - assert.deepStrictEqual(dropRightWhile(objects, { 'b': 2 }), objects.slice(0, 2)); - }); - - it('should work with `_.matchesProperty` shorthands', function() { - assert.deepStrictEqual(dropRightWhile(objects, ['b', 2]), objects.slice(0, 2)); - }); - - it('should work with `_.property` shorthands', function() { - assert.deepStrictEqual(dropRightWhile(objects, 'b'), objects.slice(0, 1)); - }); - - it('should return a wrapped value when chaining', function() { - var wrapped = _(array).dropRightWhile(function(n) { - return n > 2; - }); - - assert.ok(wrapped instanceof _); - assert.deepEqual(wrapped.value(), [1, 2]); - }); -}); diff --git a/test/dropRightWhile.spec.ts b/test/dropRightWhile.spec.ts new file mode 100644 index 000000000..d31ae5628 --- /dev/null +++ b/test/dropRightWhile.spec.ts @@ -0,0 +1,48 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import dropRightWhile from '../src/dropRightWhile'; + +describe('dropRightWhile', () => { + const array = [1, 2, 3, 4]; + + const objects = [ + { a: 0, b: 0 }, + { a: 1, b: 1 }, + { a: 2, b: 2 }, + ]; + + it('should drop elements while `predicate` returns truthy', () => { + const actual = dropRightWhile(array, (n) => n > 2); + + assert.deepStrictEqual(actual, [1, 2]); + }); + + it('should provide correct `predicate` arguments', () => { + let args; + + dropRightWhile(array, function () { + args = slice.call(arguments); + }); + + assert.deepStrictEqual(args, [4, 3, array]); + }); + + it('should work with `_.matches` shorthands', () => { + assert.deepStrictEqual(dropRightWhile(objects, { b: 2 }), objects.slice(0, 2)); + }); + + it('should work with `_.matchesProperty` shorthands', () => { + assert.deepStrictEqual(dropRightWhile(objects, ['b', 2]), objects.slice(0, 2)); + }); + + it('should work with `_.property` shorthands', () => { + assert.deepStrictEqual(dropRightWhile(objects, 'b'), objects.slice(0, 1)); + }); + + it('should return a wrapped value when chaining', () => { + const wrapped = _(array).dropRightWhile((n) => n > 2); + + assert.ok(wrapped instanceof _); + assert.deepEqual(wrapped.value(), [1, 2]); + }); +}); diff --git a/test/dropWhile.js b/test/dropWhile.js deleted file mode 100644 index f02088104..000000000 --- a/test/dropWhile.js +++ /dev/null @@ -1,67 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, LARGE_ARRAY_SIZE } from './utils.js'; -import dropWhile from '../dropWhile.js'; - -describe('dropWhile', function() { - var array = [1, 2, 3, 4]; - - var objects = [ - { 'a': 2, 'b': 2 }, - { 'a': 1, 'b': 1 }, - { 'a': 0, 'b': 0 } - ]; - - it('should drop elements while `predicate` returns truthy', function() { - var actual = dropWhile(array, function(n) { - return n < 3; - }); - - assert.deepStrictEqual(actual, [3, 4]); - }); - - it('should provide correct `predicate` arguments', function() { - var args; - - dropWhile(array, function() { - args = slice.call(arguments); - }); - - assert.deepStrictEqual(args, [1, 0, array]); - }); - - it('should work with `_.matches` shorthands', function() { - assert.deepStrictEqual(dropWhile(objects, { 'b': 2 }), objects.slice(1)); - }); - - it('should work with `_.matchesProperty` shorthands', function() { - assert.deepStrictEqual(dropWhile(objects, ['b', 2]), objects.slice(1)); - }); - - it('should work with `_.property` shorthands', function() { - assert.deepStrictEqual(dropWhile(objects, 'b'), objects.slice(2)); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 3), - predicate = function(n) { return n < 3; }, - expected = dropWhile(array, predicate), - wrapped = _(array).dropWhile(predicate); - - assert.deepEqual(wrapped.value(), expected); - assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); - assert.strictEqual(wrapped.last(), _.last(expected)); - }); - - it('should work in a lazy sequence with `drop`', function() { - var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 3); - - var actual = _(array) - .dropWhile(function(n) { return n == 1; }) - .drop() - .dropWhile(function(n) { return n == 3; }) - .value(); - - assert.deepEqual(actual, array.slice(3)); - }); -}); diff --git a/test/dropWhile.spec.ts b/test/dropWhile.spec.ts new file mode 100644 index 000000000..698f33a55 --- /dev/null +++ b/test/dropWhile.spec.ts @@ -0,0 +1,67 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, LARGE_ARRAY_SIZE } from './utils'; +import dropWhile from '../src/dropWhile'; + +describe('dropWhile', () => { + const array = [1, 2, 3, 4]; + + const objects = [ + { a: 2, b: 2 }, + { a: 1, b: 1 }, + { a: 0, b: 0 }, + ]; + + it('should drop elements while `predicate` returns truthy', () => { + const actual = dropWhile(array, (n) => n < 3); + + assert.deepStrictEqual(actual, [3, 4]); + }); + + it('should provide correct `predicate` arguments', () => { + let args; + + dropWhile(array, function () { + args = slice.call(arguments); + }); + + assert.deepStrictEqual(args, [1, 0, array]); + }); + + it('should work with `_.matches` shorthands', () => { + assert.deepStrictEqual(dropWhile(objects, { b: 2 }), objects.slice(1)); + }); + + it('should work with `_.matchesProperty` shorthands', () => { + assert.deepStrictEqual(dropWhile(objects, ['b', 2]), objects.slice(1)); + }); + + it('should work with `_.property` shorthands', () => { + assert.deepStrictEqual(dropWhile(objects, 'b'), objects.slice(2)); + }); + + it('should work in a lazy sequence', () => { + const array = lodashStable.range(1, LARGE_ARRAY_SIZE + 3), + predicate = function (n) { + return n < 3; + }, + expected = dropWhile(array, predicate), + wrapped = _(array).dropWhile(predicate); + + assert.deepEqual(wrapped.value(), expected); + assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); + assert.strictEqual(wrapped.last(), _.last(expected)); + }); + + it('should work in a lazy sequence with `drop`', () => { + const array = lodashStable.range(1, LARGE_ARRAY_SIZE + 3); + + const actual = _(array) + .dropWhile((n) => n == 1) + .drop() + .dropWhile((n) => n == 3) + .value(); + + assert.deepEqual(actual, array.slice(3)); + }); +}); diff --git a/test/endsWith.spec.ts b/test/endsWith.spec.ts new file mode 100644 index 000000000..01a92d92d --- /dev/null +++ b/test/endsWith.spec.ts @@ -0,0 +1,47 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { MAX_SAFE_INTEGER, falsey, stubTrue } from './utils'; +import endsWith from '../src/endsWith'; + +describe('endsWith', () => { + const string = 'abc'; + + it('should return `true` if a string ends with `target`', () => { + assert.strictEqual(endsWith(string, 'c'), true); + }); + + it('should return `false` if a string does not end with `target`', () => { + assert.strictEqual(endsWith(string, 'b'), false); + }); + + it('should work with a `position`', () => { + assert.strictEqual(endsWith(string, 'b', 2), true); + }); + + it('should work with `position` >= `length`', () => { + lodashStable.each([3, 5, MAX_SAFE_INTEGER, Infinity], (position) => { + assert.strictEqual(endsWith(string, 'c', position), true); + }); + }); + + it('should treat falsey `position` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (position) => + endsWith(string, position === undefined ? 'c' : '', position), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should treat a negative `position` as `0`', () => { + lodashStable.each([-1, -3, -Infinity], (position) => { + assert.ok(lodashStable.every(string, (chr) => !endsWith(string, chr, position))); + assert.strictEqual(endsWith(string, '', position), true); + }); + }); + + it('should coerce `position` to an integer', () => { + assert.strictEqual(endsWith(string, 'ab', 2.2), true); + }); +}); diff --git a/test/endsWith.test.js b/test/endsWith.test.js deleted file mode 100644 index ceb9dddd4..000000000 --- a/test/endsWith.test.js +++ /dev/null @@ -1,49 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { MAX_SAFE_INTEGER, falsey, stubTrue } from './utils.js'; -import endsWith from '../endsWith.js'; - -describe('endsWith', function() { - var string = 'abc'; - - it('should return `true` if a string ends with `target`', function() { - assert.strictEqual(endsWith(string, 'c'), true); - }); - - it('should return `false` if a string does not end with `target`', function() { - assert.strictEqual(endsWith(string, 'b'), false); - }); - - it('should work with a `position`', function() { - assert.strictEqual(endsWith(string, 'b', 2), true); - }); - - it('should work with `position` >= `length`', function() { - lodashStable.each([3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { - assert.strictEqual(endsWith(string, 'c', position), true); - }); - }); - - it('should treat falsey `position` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(position) { - return endsWith(string, position === undefined ? 'c' : '', position); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should treat a negative `position` as `0`', function() { - lodashStable.each([-1, -3, -Infinity], function(position) { - assert.ok(lodashStable.every(string, function(chr) { - return !endsWith(string, chr, position); - })); - assert.strictEqual(endsWith(string, '', position), true); - }); - }); - - it('should coerce `position` to an integer', function() { - assert.strictEqual(endsWith(string, 'ab', 2.2), true); - }); -}); diff --git a/test/eq.spec.ts b/test/eq.spec.ts new file mode 100644 index 000000000..443c9d811 --- /dev/null +++ b/test/eq.spec.ts @@ -0,0 +1,21 @@ +import assert from 'node:assert'; +import eq from '../src/eq'; + +describe('eq', () => { + it('should perform a `SameValueZero` comparison of two values', () => { + assert.strictEqual(eq(), true); + assert.strictEqual(eq(undefined), true); + assert.strictEqual(eq(0, -0), true); + assert.strictEqual(eq(NaN, NaN), true); + assert.strictEqual(eq(1, 1), true); + + assert.strictEqual(eq(null, undefined), false); + assert.strictEqual(eq(1, Object(1)), false); + assert.strictEqual(eq(1, '1'), false); + assert.strictEqual(eq(1, '1'), false); + + const object = { a: 1 }; + assert.strictEqual(eq(object, object), true); + assert.strictEqual(eq(object, { a: 1 }), false); + }); +}); diff --git a/test/eq.test.js b/test/eq.test.js deleted file mode 100644 index ec0c7adad..000000000 --- a/test/eq.test.js +++ /dev/null @@ -1,21 +0,0 @@ -import assert from 'assert'; -import eq from '../eq.js'; - -describe('eq', function() { - it('should perform a `SameValueZero` comparison of two values', function() { - assert.strictEqual(eq(), true); - assert.strictEqual(eq(undefined), true); - assert.strictEqual(eq(0, -0), true); - assert.strictEqual(eq(NaN, NaN), true); - assert.strictEqual(eq(1, 1), true); - - assert.strictEqual(eq(null, undefined), false); - assert.strictEqual(eq(1, Object(1)), false); - assert.strictEqual(eq(1, '1'), false); - assert.strictEqual(eq(1, '1'), false); - - var object = { 'a': 1 }; - assert.strictEqual(eq(object, object), true); - assert.strictEqual(eq(object, { 'a': 1 }), false); - }); -}); diff --git a/test/escape.spec.ts b/test/escape.spec.ts new file mode 100644 index 000000000..363bec1f5 --- /dev/null +++ b/test/escape.spec.ts @@ -0,0 +1,30 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import escape from '../src/escape'; +import unescape from '../src/unescape'; + +describe('escape', () => { + let escaped = '&<>"'/', + unescaped = '&<>"\'/'; + + escaped += escaped; + unescaped += unescaped; + + it('should escape values', () => { + assert.strictEqual(escape(unescaped), escaped); + }); + + it('should handle strings with nothing to escape', () => { + assert.strictEqual(escape('abc'), 'abc'); + }); + + it('should escape the same characters unescaped by `_.unescape`', () => { + assert.strictEqual(escape(unescape(escaped)), escaped); + }); + + lodashStable.each(['`', '/'], (chr) => { + it(`should not escape the "${chr}" character`, () => { + assert.strictEqual(escape(chr), chr); + }); + }); +}); diff --git a/test/escape.test.js b/test/escape.test.js deleted file mode 100644 index f5b7dbaba..000000000 --- a/test/escape.test.js +++ /dev/null @@ -1,30 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import escape from '../escape.js'; -import unescape from '../unescape.js'; - -describe('escape', function() { - var escaped = '&<>"'/', - unescaped = '&<>"\'/'; - - escaped += escaped; - unescaped += unescaped; - - it('should escape values', function() { - assert.strictEqual(escape(unescaped), escaped); - }); - - it('should handle strings with nothing to escape', function() { - assert.strictEqual(escape('abc'), 'abc'); - }); - - it('should escape the same characters unescaped by `_.unescape`', function() { - assert.strictEqual(escape(unescape(escaped)), escaped); - }); - - lodashStable.each(['`', '/'], function(chr) { - it('should not escape the "' + chr + '" character', function() { - assert.strictEqual(escape(chr), chr); - }); - }); -}); diff --git a/test/escapeRegExp.spec.ts b/test/escapeRegExp.spec.ts new file mode 100644 index 000000000..e475c0f4f --- /dev/null +++ b/test/escapeRegExp.spec.ts @@ -0,0 +1,28 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubString } from './utils'; +import escapeRegExp from '../src/escapeRegExp'; + +describe('escapeRegExp', () => { + const escaped = '\\^\\$\\.\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|\\\\', + unescaped = '^$.*+?()[]{}|\\'; + + it('should escape values', () => { + assert.strictEqual(escapeRegExp(unescaped + unescaped), escaped + escaped); + }); + + it('should handle strings with nothing to escape', () => { + assert.strictEqual(escapeRegExp('abc'), 'abc'); + }); + + it('should return an empty string for empty values', () => { + const values = [, null, undefined, ''], + expected = lodashStable.map(values, stubString); + + const actual = lodashStable.map(values, (value, index) => + index ? escapeRegExp(value) : escapeRegExp(), + ); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/escapeRegExp.test.js b/test/escapeRegExp.test.js deleted file mode 100644 index 3fa706274..000000000 --- a/test/escapeRegExp.test.js +++ /dev/null @@ -1,28 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubString } from './utils.js'; -import escapeRegExp from '../escapeRegExp.js'; - -describe('escapeRegExp', function() { - var escaped = '\\^\\$\\.\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|\\\\', - unescaped = '^$.*+?()[]{}|\\'; - - it('should escape values', function() { - assert.strictEqual(escapeRegExp(unescaped + unescaped), escaped + escaped); - }); - - it('should handle strings with nothing to escape', function() { - assert.strictEqual(escapeRegExp('abc'), 'abc'); - }); - - it('should return an empty string for empty values', function() { - var values = [, null, undefined, ''], - expected = lodashStable.map(values, stubString); - - var actual = lodashStable.map(values, function(value, index) { - return index ? escapeRegExp(value) : escapeRegExp(); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/every.js b/test/every.js deleted file mode 100644 index 76052aa9f..000000000 --- a/test/every.js +++ /dev/null @@ -1,74 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { identity, empties, stubTrue, stubFalse } from './utils.js'; -import every from '../every.js'; - -describe('every', function() { - it('should return `true` if `predicate` returns truthy for all elements', function() { - assert.strictEqual(lodashStable.every([true, 1, 'a'], identity), true); - }); - - it('should return `true` for empty collections', function() { - var expected = lodashStable.map(empties, stubTrue); - - var actual = lodashStable.map(empties, function(value) { - try { - return every(value, identity); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `false` as soon as `predicate` returns falsey', function() { - var count = 0; - - assert.strictEqual(every([true, null, true], function(value) { - count++; - return value; - }), false); - - assert.strictEqual(count, 2); - }); - - it('should work with collections of `undefined` values (test in IE < 9)', function() { - assert.strictEqual(every([undefined, undefined, undefined], identity), false); - }); - - it('should use `_.identity` when `predicate` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value, index) { - var array = [0]; - return index ? every(array, value) : every(array); - }); - - assert.deepStrictEqual(actual, expected); - - expected = lodashStable.map(values, stubTrue); - actual = lodashStable.map(values, function(value, index) { - var array = [1]; - return index ? every(array, value) : every(array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `_.property` shorthands', function() { - var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; - assert.strictEqual(every(objects, 'a'), false); - assert.strictEqual(every(objects, 'b'), true); - }); - - it('should work with `_.matches` shorthands', function() { - var objects = [{ 'a': 0, 'b': 0 }, { 'a': 0, 'b': 1 }]; - assert.strictEqual(every(objects, { 'a': 0 }), true); - assert.strictEqual(every(objects, { 'b': 1 }), false); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var actual = lodashStable.map([[1]], every); - assert.deepStrictEqual(actual, [true]); - }); -}); diff --git a/test/every.spec.ts b/test/every.spec.ts new file mode 100644 index 000000000..1e5cd926c --- /dev/null +++ b/test/every.spec.ts @@ -0,0 +1,83 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { identity, empties, stubTrue, stubFalse } from './utils'; +import every from '../src/every'; + +describe('every', () => { + it('should return `true` if `predicate` returns truthy for all elements', () => { + assert.strictEqual(lodashStable.every([true, 1, 'a'], identity), true); + }); + + it('should return `true` for empty collections', () => { + const expected = lodashStable.map(empties, stubTrue); + + const actual = lodashStable.map(empties, (value) => { + try { + return every(value, identity); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `false` as soon as `predicate` returns falsey', () => { + let count = 0; + + assert.strictEqual( + every([true, null, true], (value) => { + count++; + return value; + }), + false, + ); + + assert.strictEqual(count, 2); + }); + + it('should work with collections of `undefined` values (test in IE < 9)', () => { + assert.strictEqual(every([undefined, undefined, undefined], identity), false); + }); + + it('should use `_.identity` when `predicate` is nullish', () => { + let values = [, null, undefined], + expected = lodashStable.map(values, stubFalse); + + let actual = lodashStable.map(values, (value, index) => { + const array = [0]; + return index ? every(array, value) : every(array); + }); + + assert.deepStrictEqual(actual, expected); + + expected = lodashStable.map(values, stubTrue); + actual = lodashStable.map(values, (value, index) => { + const array = [1]; + return index ? every(array, value) : every(array); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `_.property` shorthands', () => { + const objects = [ + { a: 0, b: 1 }, + { a: 1, b: 2 }, + ]; + assert.strictEqual(every(objects, 'a'), false); + assert.strictEqual(every(objects, 'b'), true); + }); + + it('should work with `_.matches` shorthands', () => { + const objects = [ + { a: 0, b: 0 }, + { a: 0, b: 1 }, + ]; + assert.strictEqual(every(objects, { a: 0 }), true); + assert.strictEqual(every(objects, { b: 1 }), false); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const actual = lodashStable.map([[1]], every); + assert.deepStrictEqual(actual, [true]); + }); +}); diff --git a/test/exit-early.js b/test/exit-early.js deleted file mode 100644 index 090d6c893..000000000 --- a/test/exit-early.js +++ /dev/null @@ -1,37 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('exit early', function() { - lodashStable.each(['_baseEach', 'forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'transform'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` can exit early when iterating arrays', function() { - if (func) { - var array = [1, 2, 3], - values = []; - - func(array, function(value, other) { - values.push(lodashStable.isArray(value) ? other : value); - return false; - }); - - assert.deepStrictEqual(values, [lodashStable.endsWith(methodName, 'Right') ? 3 : 1]); - } - }); - - it('`_.' + methodName + '` can exit early when iterating objects', function() { - if (func) { - var object = { 'a': 1, 'b': 2, 'c': 3 }, - values = []; - - func(object, function(value, other) { - values.push(lodashStable.isArray(value) ? other : value); - return false; - }); - - assert.strictEqual(values.length, 1); - } - }); - }); -}); diff --git a/test/exit-early.spec.ts b/test/exit-early.spec.ts new file mode 100644 index 000000000..7d0ac68f0 --- /dev/null +++ b/test/exit-early.spec.ts @@ -0,0 +1,51 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('exit early', () => { + lodashStable.each( + [ + '_baseEach', + 'forEach', + 'forEachRight', + 'forIn', + 'forInRight', + 'forOwn', + 'forOwnRight', + 'transform', + ], + (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` can exit early when iterating arrays`, () => { + if (func) { + const array = [1, 2, 3], + values = []; + + func(array, (value, other) => { + values.push(lodashStable.isArray(value) ? other : value); + return false; + }); + + assert.deepStrictEqual(values, [ + lodashStable.endsWith(methodName, 'Right') ? 3 : 1, + ]); + } + }); + + it(`\`_.${methodName}\` can exit early when iterating objects`, () => { + if (func) { + const object = { a: 1, b: 2, c: 3 }, + values = []; + + func(object, (value, other) => { + values.push(lodashStable.isArray(value) ? other : value); + return false; + }); + + assert.strictEqual(values.length, 1); + } + }); + }, + ); +}); diff --git a/test/extremum-methods.js b/test/extremum-methods.js deleted file mode 100644 index 6dad236bd..000000000 --- a/test/extremum-methods.js +++ /dev/null @@ -1,64 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('extremum methods', function() { - lodashStable.each(['max', 'maxBy', 'min', 'minBy'], function(methodName) { - var func = _[methodName], - isMax = /^max/.test(methodName); - - it('`_.' + methodName + '` should work with Date objects', function() { - var curr = new Date, - past = new Date(0); - - assert.strictEqual(func([curr, past]), isMax ? curr : past); - }); - - it('`_.' + methodName + '` should work with extremely large arrays', function() { - var array = lodashStable.range(0, 5e5); - assert.strictEqual(func(array), isMax ? 499999 : 0); - }); - - it('`_.' + methodName + '` should work when chaining on an array with only one value', function() { - var actual = _([40])[methodName](); - assert.strictEqual(actual, 40); - }); - }); - - lodashStable.each(['maxBy', 'minBy'], function(methodName) { - var array = [1, 2, 3], - func = _[methodName], - isMax = methodName == 'maxBy'; - - it('`_.' + methodName + '` should work with an `iteratee`', function() { - var actual = func(array, function(n) { - return -n; - }); - - assert.strictEqual(actual, isMax ? 1 : 3); - }); - - it('should work with `_.property` shorthands', function() { - var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }], - actual = func(objects, 'a'); - - assert.deepStrictEqual(actual, objects[isMax ? 1 : 2]); - - var arrays = [[2], [3], [1]]; - actual = func(arrays, 0); - - assert.deepStrictEqual(actual, arrays[isMax ? 1 : 2]); - }); - - it('`_.' + methodName + '` should work when `iteratee` returns +/-Infinity', function() { - var value = isMax ? -Infinity : Infinity, - object = { 'a': value }; - - var actual = func([object, { 'a': value }], function(object) { - return object.a; - }); - - assert.strictEqual(actual, object); - }); - }); -}); diff --git a/test/extremum-methods.spec.ts b/test/extremum-methods.spec.ts new file mode 100644 index 000000000..85f44b218 --- /dev/null +++ b/test/extremum-methods.spec.ts @@ -0,0 +1,60 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('extremum methods', () => { + lodashStable.each(['max', 'maxBy', 'min', 'minBy'], (methodName) => { + const func = _[methodName], + isMax = /^max/.test(methodName); + + it(`\`_.${methodName}\` should work with Date objects`, () => { + const curr = new Date(), + past = new Date(0); + + assert.strictEqual(func([curr, past]), isMax ? curr : past); + }); + + it(`\`_.${methodName}\` should work with extremely large arrays`, () => { + const array = lodashStable.range(0, 5e5); + assert.strictEqual(func(array), isMax ? 499999 : 0); + }); + + it(`\`_.${methodName}\` should work when chaining on an array with only one value`, () => { + const actual = _([40])[methodName](); + assert.strictEqual(actual, 40); + }); + }); + + lodashStable.each(['maxBy', 'minBy'], (methodName) => { + const array = [1, 2, 3], + func = _[methodName], + isMax = methodName == 'maxBy'; + + it(`\`_.${methodName}\` should work with an \`iteratee\``, () => { + const actual = func(array, (n) => -n); + + assert.strictEqual(actual, isMax ? 1 : 3); + }); + + it('should work with `_.property` shorthands', () => { + let objects = [{ a: 2 }, { a: 3 }, { a: 1 }], + actual = func(objects, 'a'); + + assert.deepStrictEqual(actual, objects[isMax ? 1 : 2]); + + const arrays = [[2], [3], [1]]; + actual = func(arrays, 0); + + assert.deepStrictEqual(actual, arrays[isMax ? 1 : 2]); + }); + + it(`\`_.${methodName}\` should work when \`iteratee\` returns +/-Infinity`, () => { + const value = isMax ? -Infinity : Infinity, + object = { a: value }; + + const actual = func([object, { a: value }], (object) => object.a); + + assert.strictEqual(actual, object); + }); + }); +}); diff --git a/test/fill.js b/test/fill.js deleted file mode 100644 index 518e368a7..000000000 --- a/test/fill.js +++ /dev/null @@ -1,128 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey } from './utils.js'; -import fill from '../fill.js'; - -describe('fill', function() { - it('should use a default `start` of `0` and a default `end` of `length`', function() { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a'), ['a', 'a', 'a']); - }); - - it('should use `undefined` for `value` if not given', function() { - var array = [1, 2, 3], - actual = fill(array); - - assert.deepStrictEqual(actual, Array(3)); - assert.ok(lodashStable.every(actual, function(value, index) { - return index in actual; - })); - }); - - it('should work with a positive `start`', function() { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a', 1), [1, 'a', 'a']); - }); - - it('should work with a `start` >= `length`', function() { - lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(start) { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a', start), [1, 2, 3]); - }); - }); - - it('should treat falsey `start` values as `0`', function() { - var expected = lodashStable.map(falsey, lodashStable.constant(['a', 'a', 'a'])); - - var actual = lodashStable.map(falsey, function(start) { - var array = [1, 2, 3]; - return fill(array, 'a', start); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with a negative `start`', function() { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a', -1), [1, 2, 'a']); - }); - - it('should work with a negative `start` <= negative `length`', function() { - lodashStable.each([-3, -4, -Infinity], function(start) { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a', start), ['a', 'a', 'a']); - }); - }); - - it('should work with `start` >= `end`', function() { - lodashStable.each([2, 3], function(start) { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a', start, 2), [1, 2, 3]); - }); - }); - - it('should work with a positive `end`', function() { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a', 0, 1), ['a', 2, 3]); - }); - - it('should work with a `end` >= `length`', function() { - lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(end) { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a', 0, end), ['a', 'a', 'a']); - }); - }); - - it('should treat falsey `end` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? ['a', 'a', 'a'] : [1, 2, 3]; - }); - - var actual = lodashStable.map(falsey, function(end) { - var array = [1, 2, 3]; - return fill(array, 'a', 0, end); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with a negative `end`', function() { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a', 0, -1), ['a', 'a', 3]); - }); - - it('should work with a negative `end` <= negative `length`', function() { - lodashStable.each([-3, -4, -Infinity], function(end) { - var array = [1, 2, 3]; - assert.deepStrictEqual(fill(array, 'a', 0, end), [1, 2, 3]); - }); - }); - - it('should coerce `start` and `end` to integers', function() { - var positions = [[0.1, 1.6], ['0', 1], [0, '1'], ['1'], [NaN, 1], [1, NaN]]; - - var actual = lodashStable.map(positions, function(pos) { - var array = [1, 2, 3]; - return fill.apply(_, [array, 'a'].concat(pos)); - }); - - assert.deepStrictEqual(actual, [['a', 2, 3], ['a', 2, 3], ['a', 2, 3], [1, 'a', 'a'], ['a', 2, 3], [1, 2, 3]]); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [[1, 2], [3, 4]], - actual = lodashStable.map(array, fill); - - assert.deepStrictEqual(actual, [[0, 0], [1, 1]]); - }); - - it('should return a wrapped value when chaining', function() { - var array = [1, 2, 3], - wrapped = _(array).fill('a'), - actual = wrapped.value(); - - assert.ok(wrapped instanceof _); - assert.strictEqual(actual, array); - assert.deepEqual(actual, ['a', 'a', 'a']); - }); -}); diff --git a/test/fill.spec.ts b/test/fill.spec.ts new file mode 100644 index 000000000..7c3432f03 --- /dev/null +++ b/test/fill.spec.ts @@ -0,0 +1,139 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey } from './utils'; +import fill from '../src/fill'; + +describe('fill', () => { + it('should use a default `start` of `0` and a default `end` of `length`', () => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a'), ['a', 'a', 'a']); + }); + + it('should use `undefined` for `value` if not given', () => { + const array = [1, 2, 3], + actual = fill(array); + + assert.deepStrictEqual(actual, Array(3)); + assert.ok(lodashStable.every(actual, (value, index) => index in actual)); + }); + + it('should work with a positive `start`', () => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a', 1), [1, 'a', 'a']); + }); + + it('should work with a `start` >= `length`', () => { + lodashStable.each([3, 4, 2 ** 32, Infinity], (start) => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a', start), [1, 2, 3]); + }); + }); + + it('should treat falsey `start` values as `0`', () => { + const expected = lodashStable.map(falsey, lodashStable.constant(['a', 'a', 'a'])); + + const actual = lodashStable.map(falsey, (start) => { + const array = [1, 2, 3]; + return fill(array, 'a', start); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with a negative `start`', () => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a', -1), [1, 2, 'a']); + }); + + it('should work with a negative `start` <= negative `length`', () => { + lodashStable.each([-3, -4, -Infinity], (start) => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a', start), ['a', 'a', 'a']); + }); + }); + + it('should work with `start` >= `end`', () => { + lodashStable.each([2, 3], (start) => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a', start, 2), [1, 2, 3]); + }); + }); + + it('should work with a positive `end`', () => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a', 0, 1), ['a', 2, 3]); + }); + + it('should work with a `end` >= `length`', () => { + lodashStable.each([3, 4, 2 ** 32, Infinity], (end) => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a', 0, end), ['a', 'a', 'a']); + }); + }); + + it('should treat falsey `end` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, (value) => + value === undefined ? ['a', 'a', 'a'] : [1, 2, 3], + ); + + const actual = lodashStable.map(falsey, (end) => { + const array = [1, 2, 3]; + return fill(array, 'a', 0, end); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with a negative `end`', () => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a', 0, -1), ['a', 'a', 3]); + }); + + it('should work with a negative `end` <= negative `length`', () => { + lodashStable.each([-3, -4, -Infinity], (end) => { + const array = [1, 2, 3]; + assert.deepStrictEqual(fill(array, 'a', 0, end), [1, 2, 3]); + }); + }); + + it('should coerce `start` and `end` to integers', () => { + const positions = [[0.1, 1.6], ['0', 1], [0, '1'], ['1'], [NaN, 1], [1, NaN]]; + + const actual = lodashStable.map(positions, (pos) => { + const array = [1, 2, 3]; + return fill.apply(_, [array, 'a'].concat(pos)); + }); + + assert.deepStrictEqual(actual, [ + ['a', 2, 3], + ['a', 2, 3], + ['a', 2, 3], + [1, 'a', 'a'], + ['a', 2, 3], + [1, 2, 3], + ]); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [ + [1, 2], + [3, 4], + ], + actual = lodashStable.map(array, fill); + + assert.deepStrictEqual(actual, [ + [0, 0], + [1, 1], + ]); + }); + + it('should return a wrapped value when chaining', () => { + const array = [1, 2, 3], + wrapped = _(array).fill('a'), + actual = wrapped.value(); + + assert.ok(wrapped instanceof _); + assert.strictEqual(actual, array); + assert.deepEqual(actual, ['a', 'a', 'a']); + }); +}); diff --git a/test/filter-methods.js b/test/filter-methods.js deleted file mode 100644 index 2e98afc09..000000000 --- a/test/filter-methods.js +++ /dev/null @@ -1,100 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, LARGE_ARRAY_SIZE, isEven, square } from './utils.js'; - -describe('filter methods', function() { - lodashStable.each(['filter', 'reject'], function(methodName) { - var array = [1, 2, 3, 4], - func = _[methodName], - isFilter = methodName == 'filter', - objects = [{ 'a': 0 }, { 'a': 1 }]; - - it('`_.' + methodName + '` should not modify the resulting value from within `predicate`', function() { - var actual = func([0], function(value, index, array) { - array[index] = 1; - return isFilter; - }); - - assert.deepStrictEqual(actual, [0]); - }); - - it('`_.' + methodName + '` should work with `_.property` shorthands', function() { - assert.deepStrictEqual(func(objects, 'a'), [objects[isFilter ? 1 : 0]]); - }); - - it('`_.' + methodName + '` should work with `_.matches` shorthands', function() { - assert.deepStrictEqual(func(objects, objects[1]), [objects[isFilter ? 1 : 0]]); - }); - - it('`_.' + methodName + '` should not modify wrapped values', function() { - var wrapped = _(array); - - var actual = wrapped[methodName](function(n) { - return n < 3; - }); - - assert.deepEqual(actual.value(), isFilter ? [1, 2] : [3, 4]); - - actual = wrapped[methodName](function(n) { - return n > 2; - }); - - assert.deepEqual(actual.value(), isFilter ? [3, 4] : [1, 2]); - }); - - it('`_.' + methodName + '` should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE + 1), - predicate = function(value) { return isFilter ? isEven(value) : !isEven(value); }; - - var object = lodashStable.zipObject(lodashStable.times(LARGE_ARRAY_SIZE, function(index) { - return ['key' + index, index]; - })); - - var actual = _(array).slice(1).map(square)[methodName](predicate).value(); - assert.deepEqual(actual, _[methodName](lodashStable.map(array.slice(1), square), predicate)); - - actual = _(object).mapValues(square)[methodName](predicate).value(); - assert.deepEqual(actual, _[methodName](lodashStable.mapValues(object, square), predicate)); - }); - - it('`_.' + methodName + '` should provide correct `predicate` arguments in a lazy sequence', function() { - var args, - array = lodashStable.range(LARGE_ARRAY_SIZE + 1), - expected = [1, 0, lodashStable.map(array.slice(1), square)]; - - _(array).slice(1)[methodName](function(value, index, array) { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, [1, 0, array.slice(1)]); - - args = undefined; - _(array).slice(1).map(square)[methodName](function(value, index, array) { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, expected); - - args = undefined; - _(array).slice(1).map(square)[methodName](function(value, index) { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, expected); - - args = undefined; - _(array).slice(1).map(square)[methodName](function(value) { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, [1]); - - args = undefined; - _(array).slice(1).map(square)[methodName](function() { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, expected); - }); - }); -}); diff --git a/test/filter-methods.spec.ts b/test/filter-methods.spec.ts new file mode 100644 index 000000000..da00503de --- /dev/null +++ b/test/filter-methods.spec.ts @@ -0,0 +1,123 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, LARGE_ARRAY_SIZE, isEven, square } from './utils'; + +describe('filter methods', () => { + lodashStable.each(['filter', 'reject'], (methodName) => { + const array = [1, 2, 3, 4], + func = _[methodName], + isFilter = methodName == 'filter', + objects = [{ a: 0 }, { a: 1 }]; + + it(`\`_.${methodName}\` should not modify the resulting value from within \`predicate\``, () => { + const actual = func([0], (value, index, array) => { + array[index] = 1; + return isFilter; + }); + + assert.deepStrictEqual(actual, [0]); + }); + + it(`\`_.${methodName}\` should work with \`_.property\` shorthands`, () => { + assert.deepStrictEqual(func(objects, 'a'), [objects[isFilter ? 1 : 0]]); + }); + + it(`\`_.${methodName}\` should work with \`_.matches\` shorthands`, () => { + assert.deepStrictEqual(func(objects, objects[1]), [objects[isFilter ? 1 : 0]]); + }); + + it(`\`_.${methodName}\` should not modify wrapped values`, () => { + const wrapped = _(array); + + let actual = wrapped[methodName]((n) => n < 3); + + assert.deepEqual(actual.value(), isFilter ? [1, 2] : [3, 4]); + + actual = wrapped[methodName]((n) => n > 2); + + assert.deepEqual(actual.value(), isFilter ? [3, 4] : [1, 2]); + }); + + it(`\`_.${methodName}\` should work in a lazy sequence`, () => { + const array = lodashStable.range(LARGE_ARRAY_SIZE + 1), + predicate = function (value) { + return isFilter ? isEven(value) : !isEven(value); + }; + + const object = lodashStable.zipObject( + lodashStable.times(LARGE_ARRAY_SIZE, (index) => [`key${index}`, index]), + ); + + let actual = _(array).slice(1).map(square)[methodName](predicate).value(); + assert.deepEqual( + actual, + _[methodName](lodashStable.map(array.slice(1), square), predicate), + ); + + actual = _(object).mapValues(square)[methodName](predicate).value(); + assert.deepEqual( + actual, + _[methodName](lodashStable.mapValues(object, square), predicate), + ); + }); + + it(`\`_.${methodName}\` should provide correct \`predicate\` arguments in a lazy sequence`, () => { + let args, + array = lodashStable.range(LARGE_ARRAY_SIZE + 1), + expected = [1, 0, lodashStable.map(array.slice(1), square)]; + + _(array) + .slice(1) + [methodName](function (value, index, array) { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, [1, 0, array.slice(1)]); + + args = undefined; + _(array) + .slice(1) + .map(square) + [methodName](function (value, index, array) { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, expected); + + args = undefined; + _(array) + .slice(1) + .map(square) + [methodName](function (value, index) { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, expected); + + args = undefined; + _(array) + .slice(1) + .map(square) + [methodName](function (value) { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, [1]); + + args = undefined; + _(array) + .slice(1) + .map(square) + [methodName](function () { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, expected); + }); + }); +}); diff --git a/test/filter.spec.ts b/test/filter.spec.ts new file mode 100644 index 000000000..1b84908ae --- /dev/null +++ b/test/filter.spec.ts @@ -0,0 +1,11 @@ +import assert from 'node:assert'; +import { isEven } from './utils'; +import filter from '../src/filter'; + +describe('filter', () => { + const array = [1, 2, 3]; + + it('should return elements `predicate` returns truthy for', () => { + assert.deepStrictEqual(filter(array, isEven), [2]); + }); +}); diff --git a/test/filter.test.js b/test/filter.test.js deleted file mode 100644 index cff7d2555..000000000 --- a/test/filter.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import assert from 'assert'; -import { isEven } from './utils.js'; -import filter from '../filter.js'; - -describe('filter', function() { - var array = [1, 2, 3]; - - it('should return elements `predicate` returns truthy for', function() { - assert.deepStrictEqual(filter(array, isEven), [2]); - }); -}); diff --git a/test/find-and-findLast.js b/test/find-and-findLast.js deleted file mode 100644 index e55725e97..000000000 --- a/test/find-and-findLast.js +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE, square, isEven } from './utils.js'; - -describe('find and findLast', function() { - lodashStable.each(['find', 'findLast'], function(methodName) { - var isFind = methodName == 'find'; - - it('`_.' + methodName + '` should support shortcut fusion', function() { - var findCount = 0, - mapCount = 0, - array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), - iteratee = function(value) { mapCount++; return square(value); }, - predicate = function(value) { findCount++; return isEven(value); }, - actual = _(array).map(iteratee)[methodName](predicate); - - assert.strictEqual(findCount, isFind ? 2 : 1); - assert.strictEqual(mapCount, isFind ? 2 : 1); - assert.strictEqual(actual, isFind ? 4 : square(LARGE_ARRAY_SIZE)); - }); - }); -}); diff --git a/test/find-and-findLast.spec.ts b/test/find-and-findLast.spec.ts new file mode 100644 index 000000000..a5d374a50 --- /dev/null +++ b/test/find-and-findLast.spec.ts @@ -0,0 +1,28 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE, square, isEven } from './utils'; + +describe('find and findLast', () => { + lodashStable.each(['find', 'findLast'], (methodName) => { + const isFind = methodName == 'find'; + + it(`\`_.${methodName}\` should support shortcut fusion`, () => { + let findCount = 0, + mapCount = 0, + array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), + iteratee = function (value) { + mapCount++; + return square(value); + }, + predicate = function (value) { + findCount++; + return isEven(value); + }, + actual = _(array).map(iteratee)[methodName](predicate); + + assert.strictEqual(findCount, isFind ? 2 : 1); + assert.strictEqual(mapCount, isFind ? 2 : 1); + assert.strictEqual(actual, isFind ? 4 : square(LARGE_ARRAY_SIZE)); + }); + }); +}); diff --git a/test/find-and-includes.js b/test/find-and-includes.js deleted file mode 100644 index b6978b13b..000000000 --- a/test/find-and-includes.js +++ /dev/null @@ -1,103 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, identity, args, falsey } from './utils.js'; - -describe('find and includes', function() { - lodashStable.each(['includes', 'find'], function(methodName) { - var func = _[methodName], - isIncludes = methodName == 'includes', - resolve = methodName == 'find' ? lodashStable.curry(lodashStable.eq) : identity; - - lodashStable.each({ - 'an `arguments` object': args, - 'an array': [1, 2, 3] - }, - function(collection, key) { - var values = lodashStable.toArray(collection); - - it('`_.' + methodName + '` should work with ' + key + ' and a positive `fromIndex`', function() { - var expected = [ - isIncludes || values[2], - isIncludes ? false : undefined - ]; - - var actual = [ - func(collection, resolve(values[2]), 2), - func(collection, resolve(values[1]), 2) - ]; - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with ' + key + ' and a `fromIndex` >= `length`', function() { - var indexes = [4, 6, Math.pow(2, 32), Infinity]; - - var expected = lodashStable.map(indexes, function() { - var result = isIncludes ? false : undefined; - return [result, result, result]; - }); - - var actual = lodashStable.map(indexes, function(fromIndex) { - return [ - func(collection, resolve(1), fromIndex), - func(collection, resolve(undefined), fromIndex), - func(collection, resolve(''), fromIndex) - ]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with ' + key + ' and treat falsey `fromIndex` values as `0`', function() { - var expected = lodashStable.map(falsey, lodashStable.constant(isIncludes || values[0])); - - var actual = lodashStable.map(falsey, function(fromIndex) { - return func(collection, resolve(values[0]), fromIndex); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with ' + key + ' and coerce `fromIndex` to an integer', function() { - var expected = [ - isIncludes || values[0], - isIncludes || values[0], - isIncludes ? false : undefined - ]; - - var actual = [ - func(collection, resolve(values[0]), 0.1), - func(collection, resolve(values[0]), NaN), - func(collection, resolve(values[0]), '1') - ]; - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with ' + key + ' and a negative `fromIndex`', function() { - var expected = [ - isIncludes || values[2], - isIncludes ? false : undefined - ]; - - var actual = [ - func(collection, resolve(values[2]), -1), - func(collection, resolve(values[1]), -1) - ]; - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with ' + key + ' and a negative `fromIndex` <= `-length`', function() { - var indexes = [-4, -6, -Infinity], - expected = lodashStable.map(indexes, lodashStable.constant(isIncludes || values[0])); - - var actual = lodashStable.map(indexes, function(fromIndex) { - return func(collection, resolve(values[0]), fromIndex); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - }); -}); diff --git a/test/find-and-includes.spec.ts b/test/find-and-includes.spec.ts new file mode 100644 index 000000000..7a457a5f1 --- /dev/null +++ b/test/find-and-includes.spec.ts @@ -0,0 +1,103 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, identity, args, falsey } from './utils'; + +describe('find and includes', () => { + lodashStable.each(['includes', 'find'], (methodName) => { + const func = _[methodName], + isIncludes = methodName == 'includes', + resolve = methodName == 'find' ? lodashStable.curry(lodashStable.eq) : identity; + + lodashStable.each( + { + 'an `arguments` object': args, + 'an array': [1, 2, 3], + }, + (collection, key) => { + const values = lodashStable.toArray(collection); + + it(`\`_.${methodName}\` should work with ${key} and a positive \`fromIndex\``, () => { + const expected = [isIncludes || values[2], isIncludes ? false : undefined]; + + const actual = [ + func(collection, resolve(values[2]), 2), + func(collection, resolve(values[1]), 2), + ]; + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with ${key} and a \`fromIndex\` >= \`length\``, () => { + const indexes = [4, 6, 2 ** 32, Infinity]; + + const expected = lodashStable.map(indexes, () => { + const result = isIncludes ? false : undefined; + return [result, result, result]; + }); + + const actual = lodashStable.map(indexes, (fromIndex) => [ + func(collection, resolve(1), fromIndex), + func(collection, resolve(undefined), fromIndex), + func(collection, resolve(''), fromIndex), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with ${key} and treat falsey \`fromIndex\` values as \`0\``, () => { + const expected = lodashStable.map( + falsey, + lodashStable.constant(isIncludes || values[0]), + ); + + const actual = lodashStable.map(falsey, (fromIndex) => + func(collection, resolve(values[0]), fromIndex), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with ${key} and coerce \`fromIndex\` to an integer`, () => { + const expected = [ + isIncludes || values[0], + isIncludes || values[0], + isIncludes ? false : undefined, + ]; + + const actual = [ + func(collection, resolve(values[0]), 0.1), + func(collection, resolve(values[0]), NaN), + func(collection, resolve(values[0]), '1'), + ]; + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with ${key} and a negative \`fromIndex\``, () => { + const expected = [isIncludes || values[2], isIncludes ? false : undefined]; + + const actual = [ + func(collection, resolve(values[2]), -1), + func(collection, resolve(values[1]), -1), + ]; + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with ${key} and a negative \`fromIndex\` <= \`-length\``, () => { + const indexes = [-4, -6, -Infinity], + expected = lodashStable.map( + indexes, + lodashStable.constant(isIncludes || values[0]), + ); + + const actual = lodashStable.map(indexes, (fromIndex) => + func(collection, resolve(values[0]), fromIndex), + ); + + assert.deepStrictEqual(actual, expected); + }); + }, + ); + }); +}); diff --git a/test/find-methods.js b/test/find-methods.js deleted file mode 100644 index 8a0c24767..000000000 --- a/test/find-methods.js +++ /dev/null @@ -1,139 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, empties, LARGE_ARRAY_SIZE, slice } from './utils.js'; -import each from '../each.js'; - -describe('find methods', function() { - lodashStable.each(['find', 'findIndex', 'findKey', 'findLast', 'findLastIndex', 'findLastKey'], function(methodName) { - var array = [1, 2, 3, 4], - func = _[methodName]; - - var objects = [ - { 'a': 0, 'b': 0 }, - { 'a': 1, 'b': 1 }, - { 'a': 2, 'b': 2 } - ]; - - var expected = ({ - 'find': [objects[1], undefined, objects[2]], - 'findIndex': [1, -1, 2], - 'findKey': ['1', undefined, '2'], - 'findLast': [objects[2], undefined, objects[2]], - 'findLastIndex': [2, -1, 2], - 'findLastKey': ['2', undefined, '2'] - })[methodName]; - - it('`_.' + methodName + '` should return the found value', function() { - assert.strictEqual(func(objects, function(object) { return object.a; }), expected[0]); - }); - - it('`_.' + methodName + '` should return `' + expected[1] + '` if value is not found', function() { - assert.strictEqual(func(objects, function(object) { return object.a === 3; }), expected[1]); - }); - - it('`_.' + methodName + '` should work with `_.matches` shorthands', function() { - assert.strictEqual(func(objects, { 'b': 2 }), expected[2]); - }); - - it('`_.' + methodName + '` should work with `_.matchesProperty` shorthands', function() { - assert.strictEqual(func(objects, ['b', 2]), expected[2]); - }); - - it('`_.' + methodName + '` should work with `_.property` shorthands', function() { - assert.strictEqual(func(objects, 'b'), expected[0]); - }); - - it('`_.' + methodName + '` should return `' + expected[1] + '` for empty collections', function() { - var emptyValues = lodashStable.endsWith(methodName, 'Index') ? lodashStable.reject(empties, lodashStable.isPlainObject) : empties, - expecting = lodashStable.map(emptyValues, lodashStable.constant(expected[1])); - - var actual = lodashStable.map(emptyValues, function(value) { - try { - return func(value, { 'a': 3 }); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expecting); - }); - - it('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function() { - var expected = ({ - 'find': 1, - 'findIndex': 0, - 'findKey': '0', - 'findLast': 4, - 'findLastIndex': 3, - 'findLastKey': '3' - })[methodName]; - - assert.strictEqual(_(array)[methodName](), expected); - }); - - it('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function() { - assert.ok(_(array).chain()[methodName]() instanceof _); - }); - - it('`_.' + methodName + '` should not execute immediately when explicitly chaining', function() { - var wrapped = _(array).chain()[methodName](); - assert.strictEqual(wrapped.__wrapped__, array); - }); - - it('`_.' + methodName + '` should work in a lazy sequence', function() { - var largeArray = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), - smallArray = array; - - lodashStable.times(2, function(index) { - var array = index ? largeArray : smallArray, - wrapped = _(array).filter(isEven); - - assert.strictEqual(wrapped[methodName](), func(lodashStable.filter(array, isEven))); - }); - }); - }), - function() { - each(['find', 'findIndex', 'findLast', 'findLastIndex'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should provide correct `predicate` arguments for arrays', function() { - var args, - array = ['a']; - - func(array, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, ['a', 0, array]); - }); - }); - - each(['find', 'findKey', 'findLast', 'findLastKey'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should work with an object for `collection`', function() { - var actual = func({ 'a': 1, 'b': 2, 'c': 3 }, function(n) { - return n < 3; - }); - - var expected = ({ - 'find': 1, - 'findKey': 'a', - 'findLast': 2, - 'findLastKey': 'b' - })[methodName]; - - assert.strictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should provide correct `predicate` arguments for objects', function() { - var args, - object = { 'a': 1 }; - - func(object, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [1, 'a', object]); - }); - }); - } -}); diff --git a/test/find-methods.spec.ts b/test/find-methods.spec.ts new file mode 100644 index 000000000..7ce88dd4e --- /dev/null +++ b/test/find-methods.spec.ts @@ -0,0 +1,151 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, empties, LARGE_ARRAY_SIZE, slice } from './utils'; +import each from '../src/each'; + +describe('find methods', () => { + lodashStable.each( + ['find', 'findIndex', 'findKey', 'findLast', 'findLastIndex', 'findLastKey'], + (methodName) => { + const array = [1, 2, 3, 4], + func = _[methodName]; + + const objects = [ + { a: 0, b: 0 }, + { a: 1, b: 1 }, + { a: 2, b: 2 }, + ]; + + const expected = { + find: [objects[1], undefined, objects[2]], + findIndex: [1, -1, 2], + findKey: ['1', undefined, '2'], + findLast: [objects[2], undefined, objects[2]], + findLastIndex: [2, -1, 2], + findLastKey: ['2', undefined, '2'], + }[methodName]; + + it(`\`_.${methodName}\` should return the found value`, () => { + assert.strictEqual( + func(objects, (object) => object.a), + expected[0], + ); + }); + + it(`\`_.${methodName}\` should return \`${expected[1]}\` if value is not found`, () => { + assert.strictEqual( + func(objects, (object) => object.a === 3), + expected[1], + ); + }); + + it(`\`_.${methodName}\` should work with \`_.matches\` shorthands`, () => { + assert.strictEqual(func(objects, { b: 2 }), expected[2]); + }); + + it(`\`_.${methodName}\` should work with \`_.matchesProperty\` shorthands`, () => { + assert.strictEqual(func(objects, ['b', 2]), expected[2]); + }); + + it(`\`_.${methodName}\` should work with \`_.property\` shorthands`, () => { + assert.strictEqual(func(objects, 'b'), expected[0]); + }); + + it(`\`_.${methodName}\` should return \`${expected[1]}\` for empty collections`, () => { + const emptyValues = lodashStable.endsWith(methodName, 'Index') + ? lodashStable.reject(empties, lodashStable.isPlainObject) + : empties, + expecting = lodashStable.map(emptyValues, lodashStable.constant(expected[1])); + + const actual = lodashStable.map(emptyValues, (value) => { + try { + return func(value, { a: 3 }); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expecting); + }); + + it(`\`_.${methodName}\` should return an unwrapped value when implicitly chaining`, () => { + const expected = { + find: 1, + findIndex: 0, + findKey: '0', + findLast: 4, + findLastIndex: 3, + findLastKey: '3', + }[methodName]; + + assert.strictEqual(_(array)[methodName](), expected); + }); + + it(`\`_.${methodName}\` should return a wrapped value when explicitly chaining`, () => { + assert.ok(_(array).chain()[methodName]() instanceof _); + }); + + it(`\`_.${methodName}\` should not execute immediately when explicitly chaining`, () => { + const wrapped = _(array).chain()[methodName](); + assert.strictEqual(wrapped.__wrapped__, array); + }); + + it(`\`_.${methodName}\` should work in a lazy sequence`, () => { + const largeArray = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), + smallArray = array; + + lodashStable.times(2, (index) => { + const array = index ? largeArray : smallArray, + wrapped = _(array).filter(isEven); + + assert.strictEqual( + wrapped[methodName](), + func(lodashStable.filter(array, isEven)), + ); + }); + }); + }, + ), + function () { + each(['find', 'findIndex', 'findLast', 'findLastIndex'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should provide correct \`predicate\` arguments for arrays`, () => { + let args, + array = ['a']; + + func(array, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, ['a', 0, array]); + }); + }); + + each(['find', 'findKey', 'findLast', 'findLastKey'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should work with an object for \`collection\``, () => { + const actual = func({ a: 1, b: 2, c: 3 }, (n) => n < 3); + + const expected = { + find: 1, + findKey: 'a', + findLast: 2, + findLastKey: 'b', + }[methodName]; + + assert.strictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should provide correct \`predicate\` arguments for objects`, () => { + let args, + object = { a: 1 }; + + func(object, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [1, 'a', object]); + }); + }); + }; +}); diff --git a/test/findLast.spec.ts b/test/findLast.spec.ts new file mode 100644 index 000000000..2f167b7cf --- /dev/null +++ b/test/findLast.spec.ts @@ -0,0 +1,92 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, falsey } from './utils'; +import findLast from '../src/findLast'; + +describe('findLast', () => { + const resolve = lodashStable.curry(lodashStable.eq); + + lodashStable.each( + { + 'an `arguments` object': args, + 'an array': [1, 2, 3], + }, + (collection, key) => { + const values = lodashStable.toArray(collection); + + it(`should work with ${key} and a positive \`fromIndex\``, () => { + const expected = [values[1], undefined]; + + const actual = [ + findLast(collection, resolve(values[1]), 1), + findLast(collection, resolve(values[2]), 1), + ]; + + assert.deepStrictEqual(actual, expected); + }); + + it(`should work with ${key} and a \`fromIndex\` >= \`length\``, () => { + const indexes = [4, 6, 2 ** 32, Infinity]; + + const expected = lodashStable.map( + indexes, + lodashStable.constant([values[0], undefined, undefined]), + ); + + const actual = lodashStable.map(indexes, (fromIndex) => [ + findLast(collection, resolve(1), fromIndex), + findLast(collection, resolve(undefined), fromIndex), + findLast(collection, resolve(''), fromIndex), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it(`should work with ${key} and treat falsey \`fromIndex\` values correctly`, () => { + const expected = lodashStable.map(falsey, (value) => + value === undefined ? values[3] : undefined, + ); + + const actual = lodashStable.map(falsey, (fromIndex) => + findLast(collection, resolve(values[3]), fromIndex), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it(`should work with ${key} and coerce \`fromIndex\` to an integer`, () => { + const expected = [values[0], values[0], undefined]; + + const actual = [ + findLast(collection, resolve(values[0]), 0.1), + findLast(collection, resolve(values[0]), NaN), + findLast(collection, resolve(values[2]), '1'), + ]; + + assert.deepStrictEqual(actual, expected); + }); + + it(`should work with ${key} and a negative \`fromIndex\``, () => { + const expected = [values[1], undefined]; + + const actual = [ + findLast(collection, resolve(values[1]), -2), + findLast(collection, resolve(values[2]), -2), + ]; + + assert.deepStrictEqual(actual, expected); + }); + + it(`should work with ${key} and a negative \`fromIndex\` <= \`-length\``, () => { + const indexes = [-4, -6, -Infinity], + expected = lodashStable.map(indexes, lodashStable.constant(values[0])); + + const actual = lodashStable.map(indexes, (fromIndex) => + findLast(collection, resolve(values[0]), fromIndex), + ); + + assert.deepStrictEqual(actual, expected); + }); + }, + ); +}); diff --git a/test/findLast.test.js b/test/findLast.test.js deleted file mode 100644 index b303b55f5..000000000 --- a/test/findLast.test.js +++ /dev/null @@ -1,99 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, falsey } from './utils.js'; -import findLast from '../findLast.js'; - -describe('findLast', function() { - var resolve = lodashStable.curry(lodashStable.eq); - - lodashStable.each({ - 'an `arguments` object': args, - 'an array': [1, 2, 3] - }, - function(collection, key) { - var values = lodashStable.toArray(collection); - - it('should work with ' + key + ' and a positive `fromIndex`', function() { - var expected = [ - values[1], - undefined - ]; - - var actual = [ - findLast(collection, resolve(values[1]), 1), - findLast(collection, resolve(values[2]), 1) - ]; - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with ' + key + ' and a `fromIndex` >= `length`', function() { - var indexes = [4, 6, Math.pow(2, 32), Infinity]; - - var expected = lodashStable.map(indexes, lodashStable.constant([values[0], undefined, undefined])); - - var actual = lodashStable.map(indexes, function(fromIndex) { - return [ - findLast(collection, resolve(1), fromIndex), - findLast(collection, resolve(undefined), fromIndex), - findLast(collection, resolve(''), fromIndex) - ]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with ' + key + ' and treat falsey `fromIndex` values correctly', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? values[3] : undefined; - }); - - var actual = lodashStable.map(falsey, function(fromIndex) { - return findLast(collection, resolve(values[3]), fromIndex); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with ' + key + ' and coerce `fromIndex` to an integer', function() { - var expected = [ - values[0], - values[0], - undefined - ]; - - var actual = [ - findLast(collection, resolve(values[0]), 0.1), - findLast(collection, resolve(values[0]), NaN), - findLast(collection, resolve(values[2]), '1') - ]; - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with ' + key + ' and a negative `fromIndex`', function() { - var expected = [ - values[1], - undefined - ]; - - var actual = [ - findLast(collection, resolve(values[1]), -2), - findLast(collection, resolve(values[2]), -2) - ]; - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with ' + key + ' and a negative `fromIndex` <= `-length`', function() { - var indexes = [-4, -6, -Infinity], - expected = lodashStable.map(indexes, lodashStable.constant(values[0])); - - var actual = lodashStable.map(indexes, function(fromIndex) { - return findLast(collection, resolve(values[0]), fromIndex); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/findLastIndex-and-lastIndexOf.spec.ts b/test/findLastIndex-and-lastIndexOf.spec.ts new file mode 100644 index 000000000..6f8485b28 --- /dev/null +++ b/test/findLastIndex-and-lastIndexOf.spec.ts @@ -0,0 +1,69 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { identity, stubZero, falsey } from './utils'; +import findLastIndex from '../src/findLastIndex'; +import lastIndexOf from '../src/lastIndexOf'; + +const methods = { + findLastIndex, + lastIndexOf, +}; + +describe('findLastIndex and lastIndexOf', () => { + lodashStable.each(['findLastIndex', 'lastIndexOf'], (methodName) => { + const array = [1, 2, 3, 1, 2, 3], + func = methods[methodName], + resolve = + methodName == 'findLastIndex' ? lodashStable.curry(lodashStable.eq) : identity; + + it(`\`_.${methodName}\` should return the index of the last matched value`, () => { + assert.strictEqual(func(array, resolve(3)), 5); + }); + + it(`\`_.${methodName}\` should work with a positive \`fromIndex\``, () => { + assert.strictEqual(func(array, resolve(1), 2), 0); + }); + + it(`\`_.${methodName}\` should work with a \`fromIndex\` >= \`length\``, () => { + const values = [6, 8, 2 ** 32, Infinity], + expected = lodashStable.map(values, lodashStable.constant([-1, 3, -1])); + + const actual = lodashStable.map(values, (fromIndex) => [ + func(array, resolve(undefined), fromIndex), + func(array, resolve(1), fromIndex), + func(array, resolve(''), fromIndex), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with a negative \`fromIndex\``, () => { + assert.strictEqual(func(array, resolve(2), -3), 1); + }); + + it(`\`_.${methodName}\` should work with a negative \`fromIndex\` <= \`-length\``, () => { + const values = [-6, -8, -Infinity], + expected = lodashStable.map(values, stubZero); + + const actual = lodashStable.map(values, (fromIndex) => + func(array, resolve(1), fromIndex), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should treat falsey \`fromIndex\` values correctly`, () => { + const expected = lodashStable.map(falsey, (value) => (value === undefined ? 5 : -1)); + + const actual = lodashStable.map(falsey, (fromIndex) => + func(array, resolve(3), fromIndex), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should coerce \`fromIndex\` to an integer`, () => { + assert.strictEqual(func(array, resolve(2), 4.2), 4); + }); + }); +}); diff --git a/test/findLastIndex-and-lastIndexOf.test.js b/test/findLastIndex-and-lastIndexOf.test.js deleted file mode 100644 index e28803e39..000000000 --- a/test/findLastIndex-and-lastIndexOf.test.js +++ /dev/null @@ -1,72 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { identity, stubZero, falsey } from './utils.js'; -import findLastIndex from '../findLastIndex.js'; -import lastIndexOf from '../lastIndexOf.js'; - -const methods = { - findLastIndex, - lastIndexOf -}; - -describe('findLastIndex and lastIndexOf', function() { - lodashStable.each(['findLastIndex', 'lastIndexOf'], function(methodName) { - var array = [1, 2, 3, 1, 2, 3], - func = methods[methodName], - resolve = methodName == 'findLastIndex' ? lodashStable.curry(lodashStable.eq) : identity; - - it('`_.' + methodName + '` should return the index of the last matched value', function() { - assert.strictEqual(func(array, resolve(3)), 5); - }); - - it('`_.' + methodName + '` should work with a positive `fromIndex`', function() { - assert.strictEqual(func(array, resolve(1), 2), 0); - }); - - it('`_.' + methodName + '` should work with a `fromIndex` >= `length`', function() { - var values = [6, 8, Math.pow(2, 32), Infinity], - expected = lodashStable.map(values, lodashStable.constant([-1, 3, -1])); - - var actual = lodashStable.map(values, function(fromIndex) { - return [ - func(array, resolve(undefined), fromIndex), - func(array, resolve(1), fromIndex), - func(array, resolve(''), fromIndex) - ]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with a negative `fromIndex`', function() { - assert.strictEqual(func(array, resolve(2), -3), 1); - }); - - it('`_.' + methodName + '` should work with a negative `fromIndex` <= `-length`', function() { - var values = [-6, -8, -Infinity], - expected = lodashStable.map(values, stubZero); - - var actual = lodashStable.map(values, function(fromIndex) { - return func(array, resolve(1), fromIndex); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should treat falsey `fromIndex` values correctly', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? 5 : -1; - }); - - var actual = lodashStable.map(falsey, function(fromIndex) { - return func(array, resolve(3), fromIndex); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should coerce `fromIndex` to an integer', function() { - assert.strictEqual(func(array, resolve(2), 4.2), 4); - }); - }); -}); diff --git a/test/flatMap-methods.js b/test/flatMap-methods.js deleted file mode 100644 index 4508e0a2b..000000000 --- a/test/flatMap-methods.js +++ /dev/null @@ -1,72 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, identity, falsey, stubArray } from './utils.js'; - -describe('flatMap methods', function() { - lodashStable.each(['flatMap', 'flatMapDeep', 'flatMapDepth'], function(methodName) { - var func = _[methodName], - array = [1, 2, 3, 4]; - - function duplicate(n) { - return [n, n]; - } - - it('`_.' + methodName + '` should map values in `array` to a new flattened array', function() { - var actual = func(array, duplicate), - expected = lodashStable.flatten(lodashStable.map(array, duplicate)); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with `_.property` shorthands', function() { - var objects = [{ 'a': [1, 2] }, { 'a': [3, 4] }]; - assert.deepStrictEqual(func(objects, 'a'), array); - }); - - it('`_.' + methodName + '` should iterate over own string keyed properties of objects', function() { - function Foo() { - this.a = [1, 2]; - } - Foo.prototype.b = [3, 4]; - - var actual = func(new Foo, identity); - assert.deepStrictEqual(actual, [1, 2]); - }); - - it('`_.' + methodName + '` should use `_.identity` when `iteratee` is nullish', function() { - var array = [[1, 2], [3, 4]], - object = { 'a': [1, 2], 'b': [3, 4] }, - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant([1, 2, 3, 4])); - - lodashStable.each([array, object], function(collection) { - var actual = lodashStable.map(values, function(value, index) { - return index ? func(collection, value) : func(collection); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('`_.' + methodName + '` should accept a falsey `collection`', function() { - var expected = lodashStable.map(falsey, stubArray); - - var actual = lodashStable.map(falsey, function(collection, index) { - try { - return index ? func(collection) : func(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should treat number values for `collection` as empty', function() { - assert.deepStrictEqual(func(1), []); - }); - - it('`_.' + methodName + '` should work with objects with non-number length properties', function() { - var object = { 'length': [1, 2] }; - assert.deepStrictEqual(func(object, identity), [1, 2]); - }); - }); -}); diff --git a/test/flatMap-methods.spec.ts b/test/flatMap-methods.spec.ts new file mode 100644 index 000000000..05a9d0537 --- /dev/null +++ b/test/flatMap-methods.spec.ts @@ -0,0 +1,75 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, identity, falsey, stubArray } from './utils'; + +describe('flatMap methods', () => { + lodashStable.each(['flatMap', 'flatMapDeep', 'flatMapDepth'], (methodName) => { + const func = _[methodName], + array = [1, 2, 3, 4]; + + function duplicate(n) { + return [n, n]; + } + + it(`\`_.${methodName}\` should map values in \`array\` to a new flattened array`, () => { + const actual = func(array, duplicate), + expected = lodashStable.flatten(lodashStable.map(array, duplicate)); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with \`_.property\` shorthands`, () => { + const objects = [{ a: [1, 2] }, { a: [3, 4] }]; + assert.deepStrictEqual(func(objects, 'a'), array); + }); + + it(`\`_.${methodName}\` should iterate over own string keyed properties of objects`, () => { + function Foo() { + this.a = [1, 2]; + } + Foo.prototype.b = [3, 4]; + + const actual = func(new Foo(), identity); + assert.deepStrictEqual(actual, [1, 2]); + }); + + it(`\`_.${methodName}\` should use \`_.identity\` when \`iteratee\` is nullish`, () => { + const array = [ + [1, 2], + [3, 4], + ], + object = { a: [1, 2], b: [3, 4] }, + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant([1, 2, 3, 4])); + + lodashStable.each([array, object], (collection) => { + const actual = lodashStable.map(values, (value, index) => + index ? func(collection, value) : func(collection), + ); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it(`\`_.${methodName}\` should accept a falsey \`collection\``, () => { + const expected = lodashStable.map(falsey, stubArray); + + const actual = lodashStable.map(falsey, (collection, index) => { + try { + return index ? func(collection) : func(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should treat number values for \`collection\` as empty`, () => { + assert.deepStrictEqual(func(1), []); + }); + + it(`\`_.${methodName}\` should work with objects with non-number length properties`, () => { + const object = { length: [1, 2] }; + assert.deepStrictEqual(func(object, identity), [1, 2]); + }); + }); +}); diff --git a/test/flatMapDepth.js b/test/flatMapDepth.js deleted file mode 100644 index 365ce8fcb..000000000 --- a/test/flatMapDepth.js +++ /dev/null @@ -1,33 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { identity } from './utils.js'; -import flatMapDepth from '../flatMapDepth.js'; - -describe('flatMapDepth', function() { - var array = [1, [2, [3, [4]], 5]]; - - it('should use a default `depth` of `1`', function() { - assert.deepStrictEqual(flatMapDepth(array, identity), [1, 2, [3, [4]], 5]); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant([1, 2, [3, [4]], 5])); - - var actual = lodashStable.map(values, function(value, index) { - return index ? flatMapDepth(array, value) : flatMapDepth(array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should treat a `depth` of < `1` as a shallow clone', function() { - lodashStable.each([-1, 0], function(depth) { - assert.deepStrictEqual(flatMapDepth(array, identity, depth), [1, [2, [3, [4]], 5]]); - }); - }); - - it('should coerce `depth` to an integer', function() { - assert.deepStrictEqual(flatMapDepth(array, identity, 2.2), [1, 2, 3, [4], 5]); - }); -}); diff --git a/test/flatMapDepth.spec.ts b/test/flatMapDepth.spec.ts new file mode 100644 index 000000000..d8b3e80bb --- /dev/null +++ b/test/flatMapDepth.spec.ts @@ -0,0 +1,33 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { identity } from './utils'; +import flatMapDepth from '../src/flatMapDepth'; + +describe('flatMapDepth', () => { + const array = [1, [2, [3, [4]], 5]]; + + it('should use a default `depth` of `1`', () => { + assert.deepStrictEqual(flatMapDepth(array, identity), [1, 2, [3, [4]], 5]); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant([1, 2, [3, [4]], 5])); + + const actual = lodashStable.map(values, (value, index) => + index ? flatMapDepth(array, value) : flatMapDepth(array), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should treat a `depth` of < `1` as a shallow clone', () => { + lodashStable.each([-1, 0], (depth) => { + assert.deepStrictEqual(flatMapDepth(array, identity, depth), [1, [2, [3, [4]], 5]]); + }); + }); + + it('should coerce `depth` to an integer', () => { + assert.deepStrictEqual(flatMapDepth(array, identity, 2.2), [1, 2, 3, [4], 5]); + }); +}); diff --git a/test/flatten-methods.js b/test/flatten-methods.js deleted file mode 100644 index 63b01e8c4..000000000 --- a/test/flatten-methods.js +++ /dev/null @@ -1,106 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, _ } from './utils.js'; -import flatten from '../flatten.js'; -import flattenDeep from '../flattenDeep.js'; -import flattenDepth from '../flattenDepth.js'; - -describe('flatten methods', function() { - var array = [1, [2, [3, [4]], 5]], - methodNames = ['flatten', 'flattenDeep', 'flattenDepth']; - - it('should flatten `arguments` objects', function() { - var array = [args, [args]]; - - assert.deepStrictEqual(flatten(array), [1, 2, 3, args]); - assert.deepStrictEqual(flattenDeep(array), [1, 2, 3, 1, 2, 3]); - assert.deepStrictEqual(flattenDepth(array, 2), [1, 2, 3, 1, 2, 3]); - }); - - it('should treat sparse arrays as dense', function() { - var array = [[1, 2, 3], Array(3)], - expected = [1, 2, 3]; - - expected.push(undefined, undefined, undefined); - - lodashStable.each(methodNames, function(methodName) { - var actual = _[methodName](array); - assert.deepStrictEqual(actual, expected); - assert.ok('4' in actual); - }); - }); - - it('should flatten objects with a truthy `Symbol.isConcatSpreadable` value', function() { - if (Symbol && Symbol.isConcatSpreadable) { - var object = { '0': 'a', 'length': 1 }, - array = [object], - expected = lodashStable.map(methodNames, lodashStable.constant(['a'])); - - object[Symbol.isConcatSpreadable] = true; - - var actual = lodashStable.map(methodNames, function(methodName) { - return _[methodName](array); - }); - - assert.deepStrictEqual(actual, expected); - } - }); - - it('should work with extremely large arrays', function() { - lodashStable.times(3, function(index) { - var expected = Array(5e5); - try { - var func = flatten; - if (index == 1) { - func = flattenDeep; - } else if (index == 2) { - func = flattenDepth; - } - assert.deepStrictEqual(func([expected]), expected); - } catch (e) { - assert.ok(false, e.message); - } - }); - }); - - it('should work with empty arrays', function() { - var array = [[], [[]], [[], [[[]]]]]; - - assert.deepStrictEqual(flatten(array), [[], [], [[[]]]]); - assert.deepStrictEqual(flattenDeep(array), []); - assert.deepStrictEqual(flattenDepth(array, 2), [[[]]]); - }); - - it('should support flattening of nested arrays', function() { - assert.deepStrictEqual(flatten(array), [1, 2, [3, [4]], 5]); - assert.deepStrictEqual(flattenDeep(array), [1, 2, 3, 4, 5]); - assert.deepStrictEqual(flattenDepth(array, 2), [1, 2, 3, [4], 5]); - }); - - it('should return an empty array for non array-like objects', function() { - var expected = [], - nonArray = { '0': 'a' }; - - assert.deepStrictEqual(flatten(nonArray), expected); - assert.deepStrictEqual(flattenDeep(nonArray), expected); - assert.deepStrictEqual(flattenDepth(nonArray, 2), expected); - }); - - it('should return a wrapped value when chaining', function() { - var wrapped = _(array), - actual = wrapped.flatten(); - - assert.ok(actual instanceof _); - assert.deepEqual(actual.value(), [1, 2, [3, [4]], 5]); - - actual = wrapped.flattenDeep(); - - assert.ok(actual instanceof _); - assert.deepEqual(actual.value(), [1, 2, 3, 4, 5]); - - actual = wrapped.flattenDepth(2); - - assert.ok(actual instanceof _); - assert.deepEqual(actual.value(), [1, 2, 3, [4], 5]); - }); -}); diff --git a/test/flatten-methods.spec.ts b/test/flatten-methods.spec.ts new file mode 100644 index 000000000..ca58d9baf --- /dev/null +++ b/test/flatten-methods.spec.ts @@ -0,0 +1,104 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, _ } from './utils'; +import flatten from '../src/flatten'; +import flattenDeep from '../src/flattenDeep'; +import flattenDepth from '../src/flattenDepth'; + +describe('flatten methods', () => { + const array = [1, [2, [3, [4]], 5]], + methodNames = ['flatten', 'flattenDeep', 'flattenDepth']; + + it('should flatten `arguments` objects', () => { + const array = [args, [args]]; + + assert.deepStrictEqual(flatten(array), [1, 2, 3, args]); + assert.deepStrictEqual(flattenDeep(array), [1, 2, 3, 1, 2, 3]); + assert.deepStrictEqual(flattenDepth(array, 2), [1, 2, 3, 1, 2, 3]); + }); + + it('should treat sparse arrays as dense', () => { + const array = [[1, 2, 3], Array(3)], + expected = [1, 2, 3]; + + expected.push(undefined, undefined, undefined); + + lodashStable.each(methodNames, (methodName) => { + const actual = _[methodName](array); + assert.deepStrictEqual(actual, expected); + assert.ok('4' in actual); + }); + }); + + it('should flatten objects with a truthy `Symbol.isConcatSpreadable` value', () => { + if (Symbol && Symbol.isConcatSpreadable) { + const object = { '0': 'a', length: 1 }, + array = [object], + expected = lodashStable.map(methodNames, lodashStable.constant(['a'])); + + object[Symbol.isConcatSpreadable] = true; + + const actual = lodashStable.map(methodNames, (methodName) => _[methodName](array)); + + assert.deepStrictEqual(actual, expected); + } + }); + + it('should work with extremely large arrays', () => { + lodashStable.times(3, (index) => { + const expected = Array(5e5); + try { + let func = flatten; + if (index == 1) { + func = flattenDeep; + } else if (index == 2) { + func = flattenDepth; + } + assert.deepStrictEqual(func([expected]), expected); + } catch (e) { + assert.ok(false, e.message); + } + }); + }); + + it('should work with empty arrays', () => { + const array = [[], [[]], [[], [[[]]]]]; + + assert.deepStrictEqual(flatten(array), [[], [], [[[]]]]); + assert.deepStrictEqual(flattenDeep(array), []); + assert.deepStrictEqual(flattenDepth(array, 2), [[[]]]); + }); + + it('should support flattening of nested arrays', () => { + assert.deepStrictEqual(flatten(array), [1, 2, [3, [4]], 5]); + assert.deepStrictEqual(flattenDeep(array), [1, 2, 3, 4, 5]); + assert.deepStrictEqual(flattenDepth(array, 2), [1, 2, 3, [4], 5]); + }); + + it('should return an empty array for non array-like objects', () => { + const expected = [], + nonArray = { '0': 'a' }; + + assert.deepStrictEqual(flatten(nonArray), expected); + assert.deepStrictEqual(flattenDeep(nonArray), expected); + assert.deepStrictEqual(flattenDepth(nonArray, 2), expected); + }); + + it('should return a wrapped value when chaining', () => { + let wrapped = _(array), + actual = wrapped.flatten(); + + assert.ok(actual instanceof _); + assert.deepEqual(actual.value(), [1, 2, [3, [4]], 5]); + + actual = wrapped.flattenDeep(); + + assert.ok(actual instanceof _); + assert.deepEqual(actual.value(), [1, 2, 3, 4, 5]); + + actual = wrapped.flattenDepth(2); + + assert.ok(actual instanceof _); + assert.deepEqual(actual.value(), [1, 2, 3, [4], 5]); + }); +}); diff --git a/test/flattenDepth.js b/test/flattenDepth.js deleted file mode 100644 index 6b6374e8d..000000000 --- a/test/flattenDepth.js +++ /dev/null @@ -1,21 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import flattenDepth from '../flattenDepth.js'; - -describe('flattenDepth', function() { - var array = [1, [2, [3, [4]], 5]]; - - it('should use a default `depth` of `1`', function() { - assert.deepStrictEqual(flattenDepth(array), [1, 2, [3, [4]], 5]); - }); - - it('should treat a `depth` of < `1` as a shallow clone', function() { - lodashStable.each([-1, 0], function(depth) { - assert.deepStrictEqual(flattenDepth(array, depth), [1, [2, [3, [4]], 5]]); - }); - }); - - it('should coerce `depth` to an integer', function() { - assert.deepStrictEqual(flattenDepth(array, 2.2), [1, 2, 3, [4], 5]); - }); -}); diff --git a/test/flattenDepth.spec.ts b/test/flattenDepth.spec.ts new file mode 100644 index 000000000..0888f30aa --- /dev/null +++ b/test/flattenDepth.spec.ts @@ -0,0 +1,21 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import flattenDepth from '../src/flattenDepth'; + +describe('flattenDepth', () => { + const array = [1, [2, [3, [4]], 5]]; + + it('should use a default `depth` of `1`', () => { + assert.deepStrictEqual(flattenDepth(array), [1, 2, [3, [4]], 5]); + }); + + it('should treat a `depth` of < `1` as a shallow clone', () => { + lodashStable.each([-1, 0], (depth) => { + assert.deepStrictEqual(flattenDepth(array, depth), [1, [2, [3, [4]], 5]]); + }); + }); + + it('should coerce `depth` to an integer', () => { + assert.deepStrictEqual(flattenDepth(array, 2.2), [1, 2, 3, [4], 5]); + }); +}); diff --git a/test/flip.spec.ts b/test/flip.spec.ts new file mode 100644 index 000000000..a8d47005b --- /dev/null +++ b/test/flip.spec.ts @@ -0,0 +1,14 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import flip from '../src/flip'; + +describe('flip', () => { + function fn() { + return slice.call(arguments); + } + + it('should flip arguments provided to `func`', () => { + const flipped = flip(fn); + assert.deepStrictEqual(flipped('a', 'b', 'c', 'd'), ['d', 'c', 'b', 'a']); + }); +}); diff --git a/test/flip.test.js b/test/flip.test.js deleted file mode 100644 index c8423ece4..000000000 --- a/test/flip.test.js +++ /dev/null @@ -1,14 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import flip from '../flip.js'; - -describe('flip', function() { - function fn() { - return slice.call(arguments); - } - - it('should flip arguments provided to `func`', function() { - var flipped = flip(fn); - assert.deepStrictEqual(flipped('a', 'b', 'c', 'd'), ['d', 'c', 'b', 'a']); - }); -}); diff --git a/test/flow-methods.spec.ts b/test/flow-methods.spec.ts new file mode 100644 index 000000000..6693a4049 --- /dev/null +++ b/test/flow-methods.spec.ts @@ -0,0 +1,51 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { add, square, noop, identity } from './utils'; +import head from '../src/head'; +import map from '../src/map'; +import uniq from '../src/uniq'; +import flow from '../src/flow'; +import flowRight from '../src/flowRight'; + +const methods = { + flow, + flowRight, +}; + +describe('flow methods', () => { + lodashStable.each(['flow', 'flowRight'], (methodName) => { + const func = methods[methodName], + isFlow = methodName == 'flow'; + + it(`\`_.${methodName}\` should supply each function with the return value of the previous`, () => { + const fixed = function (n) { + return n.toFixed(1); + }, + combined = isFlow ? func(add, square, fixed) : func(fixed, square, add); + + assert.strictEqual(combined(1, 2), '9.0'); + }); + + it(`\`_.${methodName}\` should return a new function`, () => { + assert.notStrictEqual(func(noop), noop); + }); + + it(`\`_.${methodName}\` should work with a curried function and \`_.head\``, () => { + const curried = lodashStable.curry(identity); + + const combined = isFlow ? func(head, curried) : func(curried, head); + + assert.strictEqual(combined([1]), 1); + }); + + it(`\`_.${methodName}\` should work with curried functions with placeholders`, () => { + const curried = lodashStable.curry(lodashStable.ary(map, 2), 2), + getProp = curried(curried.placeholder, (value) => value.a), + objects = [{ a: 1 }, { a: 2 }, { a: 1 }]; + + const combined = isFlow ? func(getProp, uniq) : func(uniq, getProp); + + assert.deepStrictEqual(combined(objects), [1, 2]); + }); + }); +}); diff --git a/test/flow-methods.test.js b/test/flow-methods.test.js deleted file mode 100644 index c1706ab1e..000000000 --- a/test/flow-methods.test.js +++ /dev/null @@ -1,53 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { add, square, noop, identity } from './utils.js'; -import head from '../head.js'; -import map from '../map.js'; -import uniq from '../uniq.js'; -import flow from '../flow.js'; -import flowRight from '../flowRight.js'; - -const methods = { - flow, - flowRight -} - -describe('flow methods', function() { - lodashStable.each(['flow', 'flowRight'], function(methodName) { - var func = methods[methodName], - isFlow = methodName == 'flow'; - - it('`_.' + methodName + '` should supply each function with the return value of the previous', function() { - var fixed = function(n) { return n.toFixed(1); }, - combined = isFlow ? func(add, square, fixed) : func(fixed, square, add); - - assert.strictEqual(combined(1, 2), '9.0'); - }); - - it('`_.' + methodName + '` should return a new function', function() { - assert.notStrictEqual(func(noop), noop); - }); - - it('`_.' + methodName + '` should work with a curried function and `_.head`', function() { - var curried = lodashStable.curry(identity); - - var combined = isFlow - ? func(head, curried) - : func(curried, head); - - assert.strictEqual(combined([1]), 1); - }); - - it('`_.' + methodName + '` should work with curried functions with placeholders', function() { - var curried = lodashStable.curry(lodashStable.ary(map, 2), 2), - getProp = curried(curried.placeholder, (value) => value.a), - objects = [{ 'a': 1 }, { 'a': 2 }, { 'a': 1 }]; - - var combined = isFlow - ? func(getProp, uniq) - : func(uniq, getProp); - - assert.deepStrictEqual(combined(objects), [1, 2]); - }); - }); -}); diff --git a/test/forEach.spec.ts b/test/forEach.spec.ts new file mode 100644 index 000000000..9b892b789 --- /dev/null +++ b/test/forEach.spec.ts @@ -0,0 +1,9 @@ +import assert from 'node:assert'; +import each from '../src/each'; +import forEach from '../src/forEach'; + +describe('forEach', () => { + it('should be aliased', () => { + assert.strictEqual(each, forEach); + }); +}); diff --git a/test/forEach.test.js b/test/forEach.test.js deleted file mode 100644 index 8770ffdf9..000000000 --- a/test/forEach.test.js +++ /dev/null @@ -1,9 +0,0 @@ -import assert from 'assert'; -import each from '../each.js'; -import forEach from '../forEach.js'; - -describe('forEach', function() { - it('should be aliased', function() { - assert.strictEqual(each, forEach); - }); -}); diff --git a/test/forEachRight.spec.ts b/test/forEachRight.spec.ts new file mode 100644 index 000000000..3632ea249 --- /dev/null +++ b/test/forEachRight.spec.ts @@ -0,0 +1,9 @@ +import assert from 'node:assert'; +import eachRight from '../src/eachRight'; +import forEachRight from '../src/forEachRight'; + +describe('forEachRight', () => { + it('should be aliased', () => { + assert.strictEqual(eachRight, forEachRight); + }); +}); diff --git a/test/forEachRight.test.js b/test/forEachRight.test.js deleted file mode 100644 index 29494d9a4..000000000 --- a/test/forEachRight.test.js +++ /dev/null @@ -1,9 +0,0 @@ -import assert from 'assert'; -import eachRight from '../eachRight.js'; -import forEachRight from '../forEachRight.js'; - -describe('forEachRight', function() { - it('should be aliased', function() { - assert.strictEqual(eachRight, forEachRight); - }); -}); diff --git a/test/forIn-methods.js b/test/forIn-methods.js deleted file mode 100644 index f806201db..000000000 --- a/test/forIn-methods.js +++ /dev/null @@ -1,20 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('forIn methods', function() { - lodashStable.each(['forIn', 'forInRight'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` iterates over inherited string keyed properties', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var keys = []; - func(new Foo, function(value, key) { keys.push(key); }); - assert.deepStrictEqual(keys.sort(), ['a', 'b']); - }); - }); -}); diff --git a/test/forIn-methods.spec.ts b/test/forIn-methods.spec.ts new file mode 100644 index 000000000..8897cb2d5 --- /dev/null +++ b/test/forIn-methods.spec.ts @@ -0,0 +1,22 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('forIn methods', () => { + lodashStable.each(['forIn', 'forInRight'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` iterates over inherited string keyed properties`, () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const keys = []; + func(new Foo(), (value, key) => { + keys.push(key); + }); + assert.deepStrictEqual(keys.sort(), ['a', 'b']); + }); + }); +}); diff --git a/test/forOwn-methods.js b/test/forOwn-methods.js deleted file mode 100644 index a8a4fbbef..000000000 --- a/test/forOwn-methods.js +++ /dev/null @@ -1,17 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('forOwn methods', function() { - lodashStable.each(['forOwn', 'forOwnRight'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should iterate over `length` properties', function() { - var object = { '0': 'zero', '1': 'one', 'length': 2 }, - props = []; - - func(object, function(value, prop) { props.push(prop); }); - assert.deepStrictEqual(props.sort(), ['0', '1', 'length']); - }); - }); -}); diff --git a/test/forOwn-methods.spec.ts b/test/forOwn-methods.spec.ts new file mode 100644 index 000000000..2381cc945 --- /dev/null +++ b/test/forOwn-methods.spec.ts @@ -0,0 +1,19 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('forOwn methods', () => { + lodashStable.each(['forOwn', 'forOwnRight'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should iterate over \`length\` properties`, () => { + const object = { '0': 'zero', '1': 'one', length: 2 }, + props = []; + + func(object, (value, prop) => { + props.push(prop); + }); + assert.deepStrictEqual(props.sort(), ['0', '1', 'length']); + }); + }); +}); diff --git a/test/fromPairs.js b/test/fromPairs.js deleted file mode 100644 index 5e94ad131..000000000 --- a/test/fromPairs.js +++ /dev/null @@ -1,47 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubObject, LARGE_ARRAY_SIZE } from './utils.js'; -import fromPairs from '../fromPairs.js'; -import toPairs from '../toPairs.js'; - -describe('fromPairs', function() { - it('should accept a two dimensional array', function() { - var array = [['a', 1], ['b', 2]], - object = { 'a': 1, 'b': 2 }, - actual = fromPairs(array); - - assert.deepStrictEqual(actual, object); - }); - - it('should accept a falsey `array`', function() { - var expected = lodashStable.map(falsey, stubObject); - - var actual = lodashStable.map(falsey, function(array, index) { - try { - return index ? fromPairs(array) : fromPairs(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should not support deep paths', function() { - var actual = fromPairs([['a.b', 1]]); - assert.deepStrictEqual(actual, { 'a.b': 1 }); - }); - - it('should support consuming the return value of `_.toPairs`', function() { - var object = { 'a.b': 1 }; - assert.deepStrictEqual(fromPairs(toPairs(object)), object); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { - return ['key' + index, index]; - }); - - var actual = _(array).fromPairs().map(square).filter(isEven).take().value(); - - assert.deepEqual(actual, _.take(_.filter(_.map(fromPairs(array), square), isEven))); - }); -}); diff --git a/test/fromPairs.spec.ts b/test/fromPairs.spec.ts new file mode 100644 index 000000000..4dd83152a --- /dev/null +++ b/test/fromPairs.spec.ts @@ -0,0 +1,48 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubObject, LARGE_ARRAY_SIZE } from './utils'; +import fromPairs from '../src/fromPairs'; +import toPairs from '../src/toPairs'; + +describe('fromPairs', () => { + it('should accept a two dimensional array', () => { + const array = [ + ['a', 1], + ['b', 2], + ], + object = { a: 1, b: 2 }, + actual = fromPairs(array); + + assert.deepStrictEqual(actual, object); + }); + + it('should accept a falsey `array`', () => { + const expected = lodashStable.map(falsey, stubObject); + + const actual = lodashStable.map(falsey, (array, index) => { + try { + return index ? fromPairs(array) : fromPairs(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should not support deep paths', () => { + const actual = fromPairs([['a.b', 1]]); + assert.deepStrictEqual(actual, { 'a.b': 1 }); + }); + + it('should support consuming the return value of `_.toPairs`', () => { + const object = { 'a.b': 1 }; + assert.deepStrictEqual(fromPairs(toPairs(object)), object); + }); + + it('should work in a lazy sequence', () => { + const array = lodashStable.times(LARGE_ARRAY_SIZE, (index) => [`key${index}`, index]); + + const actual = _(array).fromPairs().map(square).filter(isEven).take().value(); + + assert.deepEqual(actual, _.take(_.filter(_.map(fromPairs(array), square), isEven))); + }); +}); diff --git a/test/functions.spec.ts b/test/functions.spec.ts new file mode 100644 index 000000000..d4d298e03 --- /dev/null +++ b/test/functions.spec.ts @@ -0,0 +1,22 @@ +import assert from 'node:assert'; +import { identity, noop } from './utils'; +import functions from '../src/functions'; + +describe('functions', () => { + it('should return the function names of an object', () => { + const object = { a: 'a', b: identity, c: /x/, d: noop }, + actual = functions(object).sort(); + + assert.deepStrictEqual(actual, ['b', 'd']); + }); + + it('should not include inherited functions', () => { + function Foo() { + this.a = identity; + this.b = 'b'; + } + Foo.prototype.c = noop; + + assert.deepStrictEqual(functions(new Foo()), ['a']); + }); +}); diff --git a/test/functions.test.js b/test/functions.test.js deleted file mode 100644 index 1d1daeeb1..000000000 --- a/test/functions.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; -import { identity, noop } from './utils.js'; -import functions from '../functions.js'; - -describe('functions', function() { - it('should return the function names of an object', function() { - var object = { 'a': 'a', 'b': identity, 'c': /x/, 'd': noop }, - actual = functions(object).sort(); - - assert.deepStrictEqual(actual, ['b', 'd']); - }); - - it('should not include inherited functions', function() { - function Foo() { - this.a = identity; - this.b = 'b'; - } - Foo.prototype.c = noop; - - assert.deepStrictEqual(functions(new Foo), ['a']); - }); -}); diff --git a/test/get-and-result.js b/test/get-and-result.js deleted file mode 100644 index 194f40f68..000000000 --- a/test/get-and-result.js +++ /dev/null @@ -1,148 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, symbol, noop, numberProto, empties } from './utils.js'; - -describe('get and result', function() { - lodashStable.each(['get', 'result'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should get string keyed property values', function() { - var object = { 'a': 1 }; - - lodashStable.each(['a', ['a']], function(path) { - assert.strictEqual(func(object, path), 1); - }); - }); - - it('`_.' + methodName + '` should preserve the sign of `0`', function() { - var object = { '-0': 'a', '0': 'b' }, - props = [-0, Object(-0), 0, Object(0)]; - - var actual = lodashStable.map(props, function(key) { - return func(object, key); - }); - - assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']); - }); - - it('`_.' + methodName + '` should get symbol keyed property values', function() { - if (Symbol) { - var object = {}; - object[symbol] = 1; - - assert.strictEqual(func(object, symbol), 1); - } - }); - - it('`_.' + methodName + '` should get deep property values', function() { - var object = { 'a': { 'b': 2 } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.strictEqual(func(object, path), 2); - }); - }); - - it('`_.' + methodName + '` should get a key over a path', function() { - var object = { 'a.b': 1, 'a': { 'b': 2 } }; - - lodashStable.each(['a.b', ['a.b']], function(path) { - assert.strictEqual(func(object, path), 1); - }); - }); - - it('`_.' + methodName + '` should not coerce array paths to strings', function() { - var object = { 'a,b,c': 3, 'a': { 'b': { 'c': 4 } } }; - assert.strictEqual(func(object, ['a', 'b', 'c']), 4); - }); - - it('`_.' + methodName + '` should not ignore empty brackets', function() { - var object = { 'a': { '': 1 } }; - assert.strictEqual(func(object, 'a[]'), 1); - }); - - it('`_.' + methodName + '` should handle empty paths', function() { - lodashStable.each([['', ''], [[], ['']]], function(pair) { - assert.strictEqual(func({}, pair[0]), undefined); - assert.strictEqual(func({ '': 3 }, pair[1]), 3); - }); - }); - - it('`_.' + methodName + '` should handle complex paths', function() { - var object = { 'a': { '-1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } }; - - var paths = [ - 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', - ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'] - ]; - - lodashStable.each(paths, function(path) { - assert.strictEqual(func(object, path), 8); - }); - }); - - it('`_.' + methodName + '` should return `undefined` when `object` is nullish', function() { - lodashStable.each(['constructor', ['constructor']], function(path) { - assert.strictEqual(func(null, path), undefined); - assert.strictEqual(func(undefined, path), undefined); - }); - }); - - it('`_.' + methodName + '` should return `undefined` for deep paths when `object` is nullish', function() { - var values = [null, undefined], - expected = lodashStable.map(values, noop), - paths = ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']]; - - lodashStable.each(paths, function(path) { - var actual = lodashStable.map(values, function(value) { - return func(value, path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('`_.' + methodName + '` should return `undefined` if parts of `path` are missing', function() { - var object = { 'a': [, null] }; - - lodashStable.each(['a[1].b.c', ['a', '1', 'b', 'c']], function(path) { - assert.strictEqual(func(object, path), undefined); - }); - }); - - it('`_.' + methodName + '` should be able to return `null` values', function() { - var object = { 'a': { 'b': null } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.strictEqual(func(object, path), null); - }); - }); - - it('`_.' + methodName + '` should follow `path` over non-plain objects', function() { - var paths = ['a.b', ['a', 'b']]; - - lodashStable.each(paths, function(path) { - numberProto.a = { 'b': 2 }; - assert.strictEqual(func(0, path), 2); - delete numberProto.a; - }); - }); - - it('`_.' + methodName + '` should return the default value for `undefined` values', function() { - var object = { 'a': {} }, - values = empties.concat(true, new Date, 1, /x/, 'a'), - expected = lodashStable.map(values, function(value) { return [value, value]; }); - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var actual = lodashStable.map(values, function(value) { - return [func(object, path, value), func(null, path, value)]; - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('`_.' + methodName + '` should return the default value when `path` is empty', function() { - assert.strictEqual(func({}, [], 'a'), 'a'); - }); - }); -}); diff --git a/test/get-and-result.spec.ts b/test/get-and-result.spec.ts new file mode 100644 index 000000000..431faf2eb --- /dev/null +++ b/test/get-and-result.spec.ts @@ -0,0 +1,153 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, symbol, noop, numberProto, empties } from './utils'; + +describe('get and result', () => { + lodashStable.each(['get', 'result'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should get string keyed property values`, () => { + const object = { a: 1 }; + + lodashStable.each(['a', ['a']], (path) => { + assert.strictEqual(func(object, path), 1); + }); + }); + + it(`\`_.${methodName}\` should preserve the sign of \`0\``, () => { + const object = { '-0': 'a', '0': 'b' }, + props = [-0, Object(-0), 0, Object(0)]; + + const actual = lodashStable.map(props, (key) => func(object, key)); + + assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']); + }); + + it(`\`_.${methodName}\` should get symbol keyed property values`, () => { + if (Symbol) { + const object = {}; + object[symbol] = 1; + + assert.strictEqual(func(object, symbol), 1); + } + }); + + it(`\`_.${methodName}\` should get deep property values`, () => { + const object = { a: { b: 2 } }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.strictEqual(func(object, path), 2); + }); + }); + + it(`\`_.${methodName}\` should get a key over a path`, () => { + const object = { 'a.b': 1, a: { b: 2 } }; + + lodashStable.each(['a.b', ['a.b']], (path) => { + assert.strictEqual(func(object, path), 1); + }); + }); + + it(`\`_.${methodName}\` should not coerce array paths to strings`, () => { + const object = { 'a,b,c': 3, a: { b: { c: 4 } } }; + assert.strictEqual(func(object, ['a', 'b', 'c']), 4); + }); + + it(`\`_.${methodName}\` should not ignore empty brackets`, () => { + const object = { a: { '': 1 } }; + assert.strictEqual(func(object, 'a[]'), 1); + }); + + it(`\`_.${methodName}\` should handle empty paths`, () => { + lodashStable.each( + [ + ['', ''], + [[], ['']], + ], + (pair) => { + assert.strictEqual(func({}, pair[0]), undefined); + assert.strictEqual(func({ '': 3 }, pair[1]), 3); + }, + ); + }); + + it(`\`_.${methodName}\` should handle complex paths`, () => { + const object = { + a: { '-1.23': { '["b"]': { c: { "['d']": { '\ne\n': { f: { g: 8 } } } } } } }, + }; + + const paths = [ + 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', + ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'], + ]; + + lodashStable.each(paths, (path) => { + assert.strictEqual(func(object, path), 8); + }); + }); + + it(`\`_.${methodName}\` should return \`undefined\` when \`object\` is nullish`, () => { + lodashStable.each(['constructor', ['constructor']], (path) => { + assert.strictEqual(func(null, path), undefined); + assert.strictEqual(func(undefined, path), undefined); + }); + }); + + it(`\`_.${methodName}\` should return \`undefined\` for deep paths when \`object\` is nullish`, () => { + const values = [null, undefined], + expected = lodashStable.map(values, noop), + paths = ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']]; + + lodashStable.each(paths, (path) => { + const actual = lodashStable.map(values, (value) => func(value, path)); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it(`\`_.${methodName}\` should return \`undefined\` if parts of \`path\` are missing`, () => { + const object = { a: [, null] }; + + lodashStable.each(['a[1].b.c', ['a', '1', 'b', 'c']], (path) => { + assert.strictEqual(func(object, path), undefined); + }); + }); + + it(`\`_.${methodName}\` should be able to return \`null\` values`, () => { + const object = { a: { b: null } }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.strictEqual(func(object, path), null); + }); + }); + + it(`\`_.${methodName}\` should follow \`path\` over non-plain objects`, () => { + const paths = ['a.b', ['a', 'b']]; + + lodashStable.each(paths, (path) => { + numberProto.a = { b: 2 }; + assert.strictEqual(func(0, path), 2); + delete numberProto.a; + }); + }); + + it(`\`_.${methodName}\` should return the default value for \`undefined\` values`, () => { + const object = { a: {} }, + values = empties.concat(true, new Date(), 1, /x/, 'a'), + expected = lodashStable.map(values, (value) => [value, value]); + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const actual = lodashStable.map(values, (value) => [ + func(object, path, value), + func(null, path, value), + ]); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it(`\`_.${methodName}\` should return the default value when \`path\` is empty`, () => { + assert.strictEqual(func({}, [], 'a'), 'a'); + }); + }); +}); diff --git a/test/groupBy.js b/test/groupBy.js deleted file mode 100644 index e20b12316..000000000 --- a/test/groupBy.js +++ /dev/null @@ -1,68 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE } from './utils.js'; -import groupBy from '../groupBy.js'; - -describe('groupBy', function() { - var array = [6.1, 4.2, 6.3]; - - it('should transform keys by `iteratee`', function() { - var actual = groupBy(array, Math.floor); - assert.deepStrictEqual(actual, { '4': [4.2], '6': [6.1, 6.3] }); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var array = [6, 4, 6], - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant({ '4': [4], '6': [6, 6] })); - - var actual = lodashStable.map(values, function(value, index) { - return index ? groupBy(array, value) : groupBy(array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `_.property` shorthands', function() { - var actual = groupBy(['one', 'two', 'three'], 'length'); - assert.deepStrictEqual(actual, { '3': ['one', 'two'], '5': ['three'] }); - }); - - it('should only add values to own, not inherited, properties', function() { - var actual = groupBy(array, function(n) { - return Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor'; - }); - - assert.deepStrictEqual(actual.constructor, [4.2]); - assert.deepStrictEqual(actual.hasOwnProperty, [6.1, 6.3]); - }); - - it('should work with a number for `iteratee`', function() { - var array = [ - [1, 'a'], - [2, 'a'], - [2, 'b'] - ]; - - assert.deepStrictEqual(groupBy(array, 0), { '1': [[1, 'a']], '2': [[2, 'a'], [2, 'b']] }); - assert.deepStrictEqual(groupBy(array, 1), { 'a': [[1, 'a'], [2, 'a']], 'b': [[2, 'b']] }); - }); - - it('should work with an object for `collection`', function() { - var actual = groupBy({ 'a': 6.1, 'b': 4.2, 'c': 6.3 }, Math.floor); - assert.deepStrictEqual(actual, { '4': [4.2], '6': [6.1, 6.3] }); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE).concat( - lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), - lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE) - ); - - var iteratee = function(value) { value.push(value[0]); return value; }, - predicate = function(value) { return isEven(value[0]); }, - actual = _(array).groupBy().map(iteratee).filter(predicate).take().value(); - - assert.deepEqual(actual, _.take(_.filter(lodashStable.map(groupBy(array), iteratee), predicate))); - }); -}); diff --git a/test/groupBy.spec.ts b/test/groupBy.spec.ts new file mode 100644 index 000000000..4e30bb870 --- /dev/null +++ b/test/groupBy.spec.ts @@ -0,0 +1,90 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE } from './utils'; +import groupBy from '../src/groupBy'; + +describe('groupBy', () => { + const array = [6.1, 4.2, 6.3]; + + it('should transform keys by `iteratee`', () => { + const actual = groupBy(array, Math.floor); + assert.deepStrictEqual(actual, { '4': [4.2], '6': [6.1, 6.3] }); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const array = [6, 4, 6], + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant({ '4': [4], '6': [6, 6] })); + + const actual = lodashStable.map(values, (value, index) => + index ? groupBy(array, value) : groupBy(array), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `_.property` shorthands', () => { + const actual = groupBy(['one', 'two', 'three'], 'length'); + assert.deepStrictEqual(actual, { '3': ['one', 'two'], '5': ['three'] }); + }); + + it('should only add values to own, not inherited, properties', () => { + const actual = groupBy(array, (n) => + Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor', + ); + + assert.deepStrictEqual(actual.constructor, [4.2]); + assert.deepStrictEqual(actual.hasOwnProperty, [6.1, 6.3]); + }); + + it('should work with a number for `iteratee`', () => { + const array = [ + [1, 'a'], + [2, 'a'], + [2, 'b'], + ]; + + assert.deepStrictEqual(groupBy(array, 0), { + '1': [[1, 'a']], + '2': [ + [2, 'a'], + [2, 'b'], + ], + }); + assert.deepStrictEqual(groupBy(array, 1), { + a: [ + [1, 'a'], + [2, 'a'], + ], + b: [[2, 'b']], + }); + }); + + it('should work with an object for `collection`', () => { + const actual = groupBy({ a: 6.1, b: 4.2, c: 6.3 }, Math.floor); + assert.deepStrictEqual(actual, { '4': [4.2], '6': [6.1, 6.3] }); + }); + + it('should work in a lazy sequence', () => { + const array = lodashStable + .range(LARGE_ARRAY_SIZE) + .concat( + lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), + lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE), + ); + + const iteratee = function (value) { + value.push(value[0]); + return value; + }, + predicate = function (value) { + return isEven(value[0]); + }, + actual = _(array).groupBy().map(iteratee).filter(predicate).take().value(); + + assert.deepEqual( + actual, + _.take(_.filter(lodashStable.map(groupBy(array), iteratee), predicate)), + ); + }); +}); diff --git a/test/gt.spec.ts b/test/gt.spec.ts new file mode 100644 index 000000000..798029631 --- /dev/null +++ b/test/gt.spec.ts @@ -0,0 +1,16 @@ +import assert from 'node:assert'; +import gt from '../src/gt'; + +describe('gt', () => { + it('should return `true` if `value` > `other`', () => { + assert.strictEqual(gt(3, 1), true); + assert.strictEqual(gt('def', 'abc'), true); + }); + + it('should return `false` if `value` is <= `other`', () => { + assert.strictEqual(gt(1, 3), false); + assert.strictEqual(gt(3, 3), false); + assert.strictEqual(gt('abc', 'def'), false); + assert.strictEqual(gt('def', 'def'), false); + }); +}); diff --git a/test/gt.test.js b/test/gt.test.js deleted file mode 100644 index c46995770..000000000 --- a/test/gt.test.js +++ /dev/null @@ -1,16 +0,0 @@ -import assert from 'assert'; -import gt from '../gt.js'; - -describe('gt', function() { - it('should return `true` if `value` > `other`', function() { - assert.strictEqual(gt(3, 1), true); - assert.strictEqual(gt('def', 'abc'), true); - }); - - it('should return `false` if `value` is <= `other`', function() { - assert.strictEqual(gt(1, 3), false); - assert.strictEqual(gt(3, 3), false); - assert.strictEqual(gt('abc', 'def'), false); - assert.strictEqual(gt('def', 'def'), false); - }); -}); diff --git a/test/gte.spec.ts b/test/gte.spec.ts new file mode 100644 index 000000000..003f7a8ae --- /dev/null +++ b/test/gte.spec.ts @@ -0,0 +1,16 @@ +import assert from 'node:assert'; +import gte from '../src/gte'; + +describe('gte', () => { + it('should return `true` if `value` >= `other`', () => { + assert.strictEqual(gte(3, 1), true); + assert.strictEqual(gte(3, 3), true); + assert.strictEqual(gte('def', 'abc'), true); + assert.strictEqual(gte('def', 'def'), true); + }); + + it('should return `false` if `value` is less than `other`', () => { + assert.strictEqual(gte(1, 3), false); + assert.strictEqual(gte('abc', 'def'), false); + }); +}); diff --git a/test/gte.test.js b/test/gte.test.js deleted file mode 100644 index d49ffaa2b..000000000 --- a/test/gte.test.js +++ /dev/null @@ -1,16 +0,0 @@ -import assert from 'assert'; -import gte from '../gte.js'; - -describe('gte', function() { - it('should return `true` if `value` >= `other`', function() { - assert.strictEqual(gte(3, 1), true); - assert.strictEqual(gte(3, 3), true); - assert.strictEqual(gte('def', 'abc'), true); - assert.strictEqual(gte('def', 'def'), true); - }); - - it('should return `false` if `value` is less than `other`', function() { - assert.strictEqual(gte(1, 3), false); - assert.strictEqual(gte('abc', 'def'), false); - }); -}); diff --git a/test/has-methods.js b/test/has-methods.js deleted file mode 100644 index ebd01b7cb..000000000 --- a/test/has-methods.js +++ /dev/null @@ -1,205 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, toArgs, stubTrue, args, symbol, defineProperty, stubFalse } from './utils.js'; - -describe('has methods', function() { - lodashStable.each(['has', 'hasIn'], function(methodName) { - var func = _[methodName], - isHas = methodName == 'has', - sparseArgs = toArgs([1]), - sparseArray = Array(1), - sparseString = Object('a'); - - delete sparseArgs[0]; - delete sparseString[0]; - - it('`_.' + methodName + '` should check for own properties', function() { - var object = { 'a': 1 }; - - lodashStable.each(['a', ['a']], function(path) { - assert.strictEqual(func(object, path), true); - }); - }); - - it('`_.' + methodName + '` should not use the `hasOwnProperty` method of `object`', function() { - var object = { 'hasOwnProperty': null, 'a': 1 }; - assert.strictEqual(func(object, 'a'), true); - }); - - it('`_.' + methodName + '` should support deep paths', function() { - var object = { 'a': { 'b': 2 } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.strictEqual(func(object, path), true); - }); - - lodashStable.each(['a.a', ['a', 'a']], function(path) { - assert.strictEqual(func(object, path), false); - }); - }); - - it('`_.' + methodName + '` should coerce `path` to a string', function() { - function fn() {} - fn.toString = lodashStable.constant('fn'); - - var object = { 'null': 1 , 'undefined': 2, 'fn': 3, '[object Object]': 4 }, - paths = [null, undefined, fn, {}], - expected = lodashStable.map(paths, stubTrue); - - lodashStable.times(2, function(index) { - var actual = lodashStable.map(paths, function(path) { - return func(object, index ? [path] : path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('`_.' + methodName + '` should work with `arguments` objects', function() { - assert.strictEqual(func(args, 1), true); - }); - - it('`_.' + methodName + '` should work with a non-string `path`', function() { - var array = [1, 2, 3]; - - lodashStable.each([1, [1]], function(path) { - assert.strictEqual(func(array, path), true); - }); - }); - - it('`_.' + methodName + '` should preserve the sign of `0`', function() { - var object = { '-0': 'a', '0': 'b' }, - props = [-0, Object(-0), 0, Object(0)], - expected = lodashStable.map(props, stubTrue); - - var actual = lodashStable.map(props, function(key) { - return func(object, key); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with a symbol `path`', function() { - function Foo() {} - - if (Symbol) { - Foo.prototype[symbol] = 1; - - var symbol2 = Symbol('b'); - defineProperty(Foo.prototype, symbol2, { - 'configurable': true, - 'enumerable': false, - 'writable': true, - 'value': 2 - }); - - var object = isHas ? Foo.prototype : new Foo; - assert.strictEqual(func(object, symbol), true); - assert.strictEqual(func(object, symbol2), true); - } - }); - - it('`_.' + methodName + '` should check for a key over a path', function() { - var object = { 'a.b': 1 }; - - lodashStable.each(['a.b', ['a.b']], function(path) { - assert.strictEqual(func(object, path), true); - }); - }); - - it('`_.' + methodName + '` should return `true` for indexes of sparse values', function() { - var values = [sparseArgs, sparseArray, sparseString], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value) { - return func(value, 0); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return `true` for indexes of sparse values with deep paths', function() { - var values = [sparseArgs, sparseArray, sparseString], - expected = lodashStable.map(values, lodashStable.constant([true, true])); - - var actual = lodashStable.map(values, function(value) { - return lodashStable.map(['a[0]', ['a', '0']], function(path) { - return func({ 'a': value }, path); - }); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return `' + (isHas ? 'false' : 'true') + '` for inherited properties', function() { - function Foo() {} - Foo.prototype.a = 1; - - lodashStable.each(['a', ['a']], function(path) { - assert.strictEqual(func(new Foo, path), !isHas); - }); - }); - - it('`_.' + methodName + '` should return `' + (isHas ? 'false' : 'true') + '` for nested inherited properties', function() { - function Foo() {} - Foo.prototype.a = { 'b': 1 }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.strictEqual(func(new Foo, path), !isHas); - }); - }); - - it('`_.' + methodName + '` should return `false` when `object` is nullish', function() { - var values = [null, undefined], - expected = lodashStable.map(values, stubFalse); - - lodashStable.each(['constructor', ['constructor']], function(path) { - var actual = lodashStable.map(values, function(value) { - return func(value, path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('`_.' + methodName + '` should return `false` for deep paths when `object` is nullish', function() { - var values = [null, undefined], - expected = lodashStable.map(values, stubFalse); - - lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { - var actual = lodashStable.map(values, function(value) { - return func(value, path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('`_.' + methodName + '` should return `false` for nullish values of nested objects', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubFalse); - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var actual = lodashStable.map(values, function(value, index) { - var object = index ? { 'a': value } : {}; - return func(object, path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('`_.' + methodName + '` should return `false` over sparse values of deep paths', function() { - var values = [sparseArgs, sparseArray, sparseString], - expected = lodashStable.map(values, lodashStable.constant([false, false])); - - var actual = lodashStable.map(values, function(value) { - return lodashStable.map(['a[0].b', ['a', '0', 'b']], function(path) { - return func({ 'a': value }, path); - }); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/has-methods.spec.ts b/test/has-methods.spec.ts new file mode 100644 index 000000000..19e2f03e1 --- /dev/null +++ b/test/has-methods.spec.ts @@ -0,0 +1,200 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, toArgs, stubTrue, args, symbol, defineProperty, stubFalse } from './utils'; + +describe('has methods', () => { + lodashStable.each(['has', 'hasIn'], (methodName) => { + const func = _[methodName], + isHas = methodName == 'has', + sparseArgs = toArgs([1]), + sparseArray = Array(1), + sparseString = Object('a'); + + delete sparseArgs[0]; + delete sparseString[0]; + + it(`\`_.${methodName}\` should check for own properties`, () => { + const object = { a: 1 }; + + lodashStable.each(['a', ['a']], (path) => { + assert.strictEqual(func(object, path), true); + }); + }); + + it(`\`_.${methodName}\` should not use the \`hasOwnProperty\` method of \`object\``, () => { + const object = { hasOwnProperty: null, a: 1 }; + assert.strictEqual(func(object, 'a'), true); + }); + + it(`\`_.${methodName}\` should support deep paths`, () => { + const object = { a: { b: 2 } }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.strictEqual(func(object, path), true); + }); + + lodashStable.each(['a.a', ['a', 'a']], (path) => { + assert.strictEqual(func(object, path), false); + }); + }); + + it(`\`_.${methodName}\` should coerce \`path\` to a string`, () => { + function fn() {} + fn.toString = lodashStable.constant('fn'); + + const object = { null: 1, undefined: 2, fn: 3, '[object Object]': 4 }, + paths = [null, undefined, fn, {}], + expected = lodashStable.map(paths, stubTrue); + + lodashStable.times(2, (index) => { + const actual = lodashStable.map(paths, (path) => + func(object, index ? [path] : path), + ); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it(`\`_.${methodName}\` should work with \`arguments\` objects`, () => { + assert.strictEqual(func(args, 1), true); + }); + + it(`\`_.${methodName}\` should work with a non-string \`path\``, () => { + const array = [1, 2, 3]; + + lodashStable.each([1, [1]], (path) => { + assert.strictEqual(func(array, path), true); + }); + }); + + it(`\`_.${methodName}\` should preserve the sign of \`0\``, () => { + const object = { '-0': 'a', '0': 'b' }, + props = [-0, Object(-0), 0, Object(0)], + expected = lodashStable.map(props, stubTrue); + + const actual = lodashStable.map(props, (key) => func(object, key)); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with a symbol \`path\``, () => { + function Foo() {} + + if (Symbol) { + Foo.prototype[symbol] = 1; + + const symbol2 = Symbol('b'); + defineProperty(Foo.prototype, symbol2, { + configurable: true, + enumerable: false, + writable: true, + value: 2, + }); + + const object = isHas ? Foo.prototype : new Foo(); + assert.strictEqual(func(object, symbol), true); + assert.strictEqual(func(object, symbol2), true); + } + }); + + it(`\`_.${methodName}\` should check for a key over a path`, () => { + const object = { 'a.b': 1 }; + + lodashStable.each(['a.b', ['a.b']], (path) => { + assert.strictEqual(func(object, path), true); + }); + }); + + it(`\`_.${methodName}\` should return \`true\` for indexes of sparse values`, () => { + const values = [sparseArgs, sparseArray, sparseString], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (value) => func(value, 0)); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return \`true\` for indexes of sparse values with deep paths`, () => { + const values = [sparseArgs, sparseArray, sparseString], + expected = lodashStable.map(values, lodashStable.constant([true, true])); + + const actual = lodashStable.map(values, (value) => + lodashStable.map(['a[0]', ['a', '0']], (path) => func({ a: value }, path)), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return \`${ + isHas ? 'false' : 'true' + }\` for inherited properties`, () => { + function Foo() {} + Foo.prototype.a = 1; + + lodashStable.each(['a', ['a']], (path) => { + assert.strictEqual(func(new Foo(), path), !isHas); + }); + }); + + it(`\`_.${methodName}\` should return \`${ + isHas ? 'false' : 'true' + }\` for nested inherited properties`, () => { + function Foo() {} + Foo.prototype.a = { b: 1 }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.strictEqual(func(new Foo(), path), !isHas); + }); + }); + + it(`\`_.${methodName}\` should return \`false\` when \`object\` is nullish`, () => { + const values = [null, undefined], + expected = lodashStable.map(values, stubFalse); + + lodashStable.each(['constructor', ['constructor']], (path) => { + const actual = lodashStable.map(values, (value) => func(value, path)); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it(`\`_.${methodName}\` should return \`false\` for deep paths when \`object\` is nullish`, () => { + const values = [null, undefined], + expected = lodashStable.map(values, stubFalse); + + lodashStable.each( + ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], + (path) => { + const actual = lodashStable.map(values, (value) => func(value, path)); + + assert.deepStrictEqual(actual, expected); + }, + ); + }); + + it(`\`_.${methodName}\` should return \`false\` for nullish values of nested objects`, () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubFalse); + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const actual = lodashStable.map(values, (value, index) => { + const object = index ? { a: value } : {}; + return func(object, path); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it(`\`_.${methodName}\` should return \`false\` over sparse values of deep paths`, () => { + const values = [sparseArgs, sparseArray, sparseString], + expected = lodashStable.map(values, lodashStable.constant([false, false])); + + const actual = lodashStable.map(values, (value) => + lodashStable.map(['a[0].b', ['a', '0', 'b']], (path) => func({ a: value }, path)), + ); + + assert.deepStrictEqual(actual, expected); + }); + }); +}); diff --git a/test/head.js b/test/head.js deleted file mode 100644 index c04a788d5..000000000 --- a/test/head.js +++ /dev/null @@ -1,62 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { arrayProto, LARGE_ARRAY_SIZE } from './utils.js'; -import head from '../head.js'; -import first from '../first.js'; - -describe('head', function() { - var array = [1, 2, 3, 4]; - - it('should return the first element', function() { - assert.strictEqual(head(array), 1); - }); - - it('should return `undefined` when querying empty arrays', function() { - arrayProto[0] = 1; - assert.strictEqual(head([]), undefined); - arrayProto.length = 0; - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = lodashStable.map(array, head); - - assert.deepStrictEqual(actual, [1, 4, 7]); - }); - - it('should be aliased', function() { - assert.strictEqual(first, head); - }); - - it('should return an unwrapped value when implicitly chaining', function() { - var wrapped = _(array); - assert.strictEqual(wrapped.head(), 1); - assert.strictEqual(wrapped.first(), 1); - }); - - it('should return a wrapped value when explicitly chaining', function() { - var wrapped = _(array).chain(); - assert.ok(wrapped.head() instanceof _); - assert.ok(wrapped.first() instanceof _); - }); - - it('should not execute immediately when explicitly chaining', function() { - var wrapped = _(array).chain(); - assert.strictEqual(wrapped.head().__wrapped__, array); - assert.strictEqual(wrapped.first().__wrapped__, array); - }); - - it('should work in a lazy sequence', function() { - var largeArray = lodashStable.range(LARGE_ARRAY_SIZE), - smallArray = array; - - lodashStable.each(['head', 'first'], function(methodName) { - lodashStable.times(2, function(index) { - var array = index ? largeArray : smallArray, - actual = _(array).filter(isEven)[methodName](); - - assert.strictEqual(actual, _[methodName](_.filter(array, isEven))); - }); - }); - }); -}); diff --git a/test/head.spec.ts b/test/head.spec.ts new file mode 100644 index 000000000..90fe13303 --- /dev/null +++ b/test/head.spec.ts @@ -0,0 +1,66 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { arrayProto, LARGE_ARRAY_SIZE } from './utils'; +import head from '../src/head'; +import first from '../src/first'; + +describe('head', () => { + const array = [1, 2, 3, 4]; + + it('should return the first element', () => { + assert.strictEqual(head(array), 1); + }); + + it('should return `undefined` when querying empty arrays', () => { + arrayProto[0] = 1; + assert.strictEqual(head([]), undefined); + arrayProto.length = 0; + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + actual = lodashStable.map(array, head); + + assert.deepStrictEqual(actual, [1, 4, 7]); + }); + + it('should be aliased', () => { + assert.strictEqual(first, head); + }); + + it('should return an unwrapped value when implicitly chaining', () => { + const wrapped = _(array); + assert.strictEqual(wrapped.head(), 1); + assert.strictEqual(wrapped.first(), 1); + }); + + it('should return a wrapped value when explicitly chaining', () => { + const wrapped = _(array).chain(); + assert.ok(wrapped.head() instanceof _); + assert.ok(wrapped.first() instanceof _); + }); + + it('should not execute immediately when explicitly chaining', () => { + const wrapped = _(array).chain(); + assert.strictEqual(wrapped.head().__wrapped__, array); + assert.strictEqual(wrapped.first().__wrapped__, array); + }); + + it('should work in a lazy sequence', () => { + const largeArray = lodashStable.range(LARGE_ARRAY_SIZE), + smallArray = array; + + lodashStable.each(['head', 'first'], (methodName) => { + lodashStable.times(2, (index) => { + const array = index ? largeArray : smallArray, + actual = _(array).filter(isEven)[methodName](); + + assert.strictEqual(actual, _[methodName](_.filter(array, isEven))); + }); + }); + }); +}); diff --git a/test/identity.js b/test/identity.js deleted file mode 100644 index ced20b853..000000000 --- a/test/identity.js +++ /dev/null @@ -1,9 +0,0 @@ -import assert from 'assert'; -import identity from '../identity.js'; - -describe('identity', function() { - it('should return the first argument given', function() { - var object = { 'name': 'fred' }; - assert.strictEqual(identity(object), object); - }); -}); diff --git a/test/identity.spec.ts b/test/identity.spec.ts new file mode 100644 index 000000000..ca39e10cb --- /dev/null +++ b/test/identity.spec.ts @@ -0,0 +1,9 @@ +import assert from 'node:assert'; +import identity from '../src/identity'; + +describe('identity', () => { + it('should return the first argument given', () => { + const object = { name: 'fred' }; + assert.strictEqual(identity(object), object); + }); +}); diff --git a/test/inRange.js b/test/inRange.js deleted file mode 100644 index 2efe128c4..000000000 --- a/test/inRange.js +++ /dev/null @@ -1,54 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubTrue } from './utils.js'; -import inRange from '../inRange.js'; - -describe('inRange', function() { - it('should work with an `end`', function() { - assert.strictEqual(inRange(3, 5), true); - assert.strictEqual(inRange(5, 5), false); - assert.strictEqual(inRange(6, 5), false); - }); - - it('should work with a `start` and `end`', function() { - assert.strictEqual(inRange(1, 1, 5), true); - assert.strictEqual(inRange(3, 1, 5), true); - assert.strictEqual(inRange(0, 1, 5), false); - assert.strictEqual(inRange(5, 1, 5), false); - }); - - it('should treat falsey `start` as `0`', function() { - lodashStable.each(falsey, function(value, index) { - if (index) { - assert.strictEqual(inRange(0, value), false); - assert.strictEqual(inRange(0, value, 1), true); - } else { - assert.strictEqual(inRange(0), false); - } - }); - }); - - it('should swap `start` and `end` when `start` > `end`', function() { - assert.strictEqual(inRange(2, 5, 1), true); - assert.strictEqual(inRange(-3, -2, -6), true); - }); - - it('should work with a floating point `n` value', function() { - assert.strictEqual(inRange(0.5, 5), true); - assert.strictEqual(inRange(1.2, 1, 5), true); - assert.strictEqual(inRange(5.2, 5), false); - assert.strictEqual(inRange(0.5, 1, 5), false); - }); - - it('should coerce arguments to finite numbers', function() { - var actual = [ - inRange(0, '1'), - inRange(0, '0', 1), - inRange(0, 0, '1'), - inRange(0, NaN, 1), - inRange(-1, -1, NaN) - ]; - - assert.deepStrictEqual(actual, lodashStable.map(actual, stubTrue)); - }); -}); diff --git a/test/inRange.spec.ts b/test/inRange.spec.ts new file mode 100644 index 000000000..6e48523e7 --- /dev/null +++ b/test/inRange.spec.ts @@ -0,0 +1,54 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubTrue } from './utils'; +import inRange from '../src/inRange'; + +describe('inRange', () => { + it('should work with an `end`', () => { + assert.strictEqual(inRange(3, 5), true); + assert.strictEqual(inRange(5, 5), false); + assert.strictEqual(inRange(6, 5), false); + }); + + it('should work with a `start` and `end`', () => { + assert.strictEqual(inRange(1, 1, 5), true); + assert.strictEqual(inRange(3, 1, 5), true); + assert.strictEqual(inRange(0, 1, 5), false); + assert.strictEqual(inRange(5, 1, 5), false); + }); + + it('should treat falsey `start` as `0`', () => { + lodashStable.each(falsey, (value, index) => { + if (index) { + assert.strictEqual(inRange(0, value), false); + assert.strictEqual(inRange(0, value, 1), true); + } else { + assert.strictEqual(inRange(0), false); + } + }); + }); + + it('should swap `start` and `end` when `start` > `end`', () => { + assert.strictEqual(inRange(2, 5, 1), true); + assert.strictEqual(inRange(-3, -2, -6), true); + }); + + it('should work with a floating point `n` value', () => { + assert.strictEqual(inRange(0.5, 5), true); + assert.strictEqual(inRange(1.2, 1, 5), true); + assert.strictEqual(inRange(5.2, 5), false); + assert.strictEqual(inRange(0.5, 1, 5), false); + }); + + it('should coerce arguments to finite numbers', () => { + const actual = [ + inRange(0, '1'), + inRange(0, '0', 1), + inRange(0, 0, '1'), + inRange(0, NaN, 1), + inRange(-1, -1, NaN), + ]; + + assert.deepStrictEqual(actual, lodashStable.map(actual, stubTrue)); + }); +}); diff --git a/test/includes.js b/test/includes.js deleted file mode 100644 index b9147a80c..000000000 --- a/test/includes.js +++ /dev/null @@ -1,95 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { empties, stubFalse } from './utils.js'; -import includes from '../includes.js'; - -describe('includes', function() { - (function() { - lodashStable.each({ - 'an `arguments` object': arguments, - 'an array': [1, 2, 3, 4], - 'an object': { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, - 'a string': '1234' - }, - function(collection, key) { - it('should work with ' + key + ' and return `true` for matched values', function() { - assert.strictEqual(includes(collection, 3), true); - }); - - it('should work with ' + key + ' and return `false` for unmatched values', function() { - assert.strictEqual(includes(collection, 5), false); - }); - - it('should work with ' + key + ' and floor `position` values', function() { - assert.strictEqual(includes(collection, 2, 1.2), true); - }); - - it('should work with ' + key + ' and return an unwrapped value implicitly when chaining', function() { - assert.strictEqual(_(collection).includes(3), true); - }); - - it('should work with ' + key + ' and return a wrapped value when explicitly chaining', function() { - assert.ok(_(collection).chain().includes(3) instanceof _); - }); - }); - - lodashStable.each({ - 'literal': 'abc', - 'object': Object('abc') - }, - function(collection, key) { - it('should work with a string ' + key + ' for `collection`', function() { - assert.strictEqual(includes(collection, 'bc'), true); - assert.strictEqual(includes(collection, 'd'), false); - }); - }); - - it('should return `false` for empty collections', function() { - var expected = lodashStable.map(empties, stubFalse); - - var actual = lodashStable.map(empties, function(value) { - try { - return includes(value); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with a string and a `fromIndex` >= `length`', function() { - var string = '1234', - length = string.length, - indexes = [4, 6, Math.pow(2, 32), Infinity]; - - var expected = lodashStable.map(indexes, function(index) { - return [false, false, index == length]; - }); - - var actual = lodashStable.map(indexes, function(fromIndex) { - return [ - includes(string, 1, fromIndex), - includes(string, undefined, fromIndex), - includes(string, '', fromIndex) - ]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should match `NaN`', function() { - assert.strictEqual(includes([1, NaN, 3], NaN), true); - }); - - it('should match `-0` as `0`', function() { - assert.strictEqual(includes([-0], 0), true); - assert.strictEqual(includes([0], -0), true); - }); - - it('should work as an iteratee for methods like `_.every`', function() { - var array = [2, 3, 1], - values = [1, 2, 3]; - - assert.ok(lodashStable.every(values, lodashStable.partial(includes, array))); - }); - })(1, 2, 3, 4); -}); diff --git a/test/includes.spec.ts b/test/includes.spec.ts new file mode 100644 index 000000000..eb94a193a --- /dev/null +++ b/test/includes.spec.ts @@ -0,0 +1,95 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { empties, stubFalse } from './utils'; +import includes from '../src/includes'; + +describe('includes', () => { + (function () { + lodashStable.each( + { + 'an `arguments` object': arguments, + 'an array': [1, 2, 3, 4], + 'an object': { a: 1, b: 2, c: 3, d: 4 }, + 'a string': '1234', + }, + (collection, key) => { + it(`should work with ${key} and return \`true\` for matched values`, () => { + assert.strictEqual(includes(collection, 3), true); + }); + + it(`should work with ${key} and return \`false\` for unmatched values`, () => { + assert.strictEqual(includes(collection, 5), false); + }); + + it(`should work with ${key} and floor \`position\` values`, () => { + assert.strictEqual(includes(collection, 2, 1.2), true); + }); + + it(`should work with ${key} and return an unwrapped value implicitly when chaining`, () => { + assert.strictEqual(_(collection).includes(3), true); + }); + + it(`should work with ${key} and return a wrapped value when explicitly chaining`, () => { + assert.ok(_(collection).chain().includes(3) instanceof _); + }); + }, + ); + + lodashStable.each( + { + literal: 'abc', + object: Object('abc'), + }, + (collection, key) => { + it(`should work with a string ${key} for \`collection\``, () => { + assert.strictEqual(includes(collection, 'bc'), true); + assert.strictEqual(includes(collection, 'd'), false); + }); + }, + ); + + it('should return `false` for empty collections', () => { + const expected = lodashStable.map(empties, stubFalse); + + const actual = lodashStable.map(empties, (value) => { + try { + return includes(value); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with a string and a `fromIndex` >= `length`', () => { + const string = '1234', + length = string.length, + indexes = [4, 6, 2 ** 32, Infinity]; + + const expected = lodashStable.map(indexes, (index) => [false, false, index == length]); + + const actual = lodashStable.map(indexes, (fromIndex) => [ + includes(string, 1, fromIndex), + includes(string, undefined, fromIndex), + includes(string, '', fromIndex), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it('should match `NaN`', () => { + assert.strictEqual(includes([1, NaN, 3], NaN), true); + }); + + it('should match `-0` as `0`', () => { + assert.strictEqual(includes([-0], 0), true); + assert.strictEqual(includes([0], -0), true); + }); + + it('should work as an iteratee for methods like `_.every`', () => { + const array = [2, 3, 1], + values = [1, 2, 3]; + + assert.ok(lodashStable.every(values, lodashStable.partial(includes, array))); + }); + })(1, 2, 3, 4); +}); diff --git a/test/indexOf-methods.js b/test/indexOf-methods.js deleted file mode 100644 index 05b506f33..000000000 --- a/test/indexOf-methods.js +++ /dev/null @@ -1,63 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, falsey } from './utils.js'; - -describe('indexOf methods', function() { - lodashStable.each(['indexOf', 'lastIndexOf', 'sortedIndexOf', 'sortedLastIndexOf'], function(methodName) { - var func = _[methodName], - isIndexOf = !/last/i.test(methodName), - isSorted = /^sorted/.test(methodName); - - it('`_.' + methodName + '` should accept a falsey `array`', function() { - var expected = lodashStable.map(falsey, lodashStable.constant(-1)); - - var actual = lodashStable.map(falsey, function(array, index) { - try { - return index ? func(array) : func(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return `-1` for an unmatched value', function() { - var array = [1, 2, 3], - empty = []; - - assert.strictEqual(func(array, 4), -1); - assert.strictEqual(func(array, 4, true), -1); - assert.strictEqual(func(array, undefined, true), -1); - - assert.strictEqual(func(empty, undefined), -1); - assert.strictEqual(func(empty, undefined, true), -1); - }); - - it('`_.' + methodName + '` should not match values on empty arrays', function() { - var array = []; - array[-1] = 0; - - assert.strictEqual(func(array, undefined), -1); - assert.strictEqual(func(array, 0, true), -1); - }); - - it('`_.' + methodName + '` should match `NaN`', function() { - var array = isSorted - ? [1, 2, NaN, NaN] - : [1, NaN, 3, NaN, 5, NaN]; - - if (isSorted) { - assert.strictEqual(func(array, NaN, true), isIndexOf ? 2 : 3); - } - else { - assert.strictEqual(func(array, NaN), isIndexOf ? 1 : 5); - assert.strictEqual(func(array, NaN, 2), isIndexOf ? 3 : 1); - assert.strictEqual(func(array, NaN, -2), isIndexOf ? 5 : 3); - } - }); - - it('`_.' + methodName + '` should match `-0` as `0`', function() { - assert.strictEqual(func([-0], 0), 0); - assert.strictEqual(func([0], -0), 0); - }); - }); -}); diff --git a/test/indexOf-methods.spec.ts b/test/indexOf-methods.spec.ts new file mode 100644 index 000000000..f339207dd --- /dev/null +++ b/test/indexOf-methods.spec.ts @@ -0,0 +1,63 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, falsey } from './utils'; + +describe('indexOf methods', () => { + lodashStable.each( + ['indexOf', 'lastIndexOf', 'sortedIndexOf', 'sortedLastIndexOf'], + (methodName) => { + const func = _[methodName], + isIndexOf = !/last/i.test(methodName), + isSorted = /^sorted/.test(methodName); + + it(`\`_.${methodName}\` should accept a falsey \`array\``, () => { + const expected = lodashStable.map(falsey, lodashStable.constant(-1)); + + const actual = lodashStable.map(falsey, (array, index) => { + try { + return index ? func(array) : func(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return \`-1\` for an unmatched value`, () => { + const array = [1, 2, 3], + empty = []; + + assert.strictEqual(func(array, 4), -1); + assert.strictEqual(func(array, 4, true), -1); + assert.strictEqual(func(array, undefined, true), -1); + + assert.strictEqual(func(empty, undefined), -1); + assert.strictEqual(func(empty, undefined, true), -1); + }); + + it(`\`_.${methodName}\` should not match values on empty arrays`, () => { + const array = []; + array[-1] = 0; + + assert.strictEqual(func(array, undefined), -1); + assert.strictEqual(func(array, 0, true), -1); + }); + + it(`\`_.${methodName}\` should match \`NaN\``, () => { + const array = isSorted ? [1, 2, NaN, NaN] : [1, NaN, 3, NaN, 5, NaN]; + + if (isSorted) { + assert.strictEqual(func(array, NaN, true), isIndexOf ? 2 : 3); + } else { + assert.strictEqual(func(array, NaN), isIndexOf ? 1 : 5); + assert.strictEqual(func(array, NaN, 2), isIndexOf ? 3 : 1); + assert.strictEqual(func(array, NaN, -2), isIndexOf ? 5 : 3); + } + }); + + it(`\`_.${methodName}\` should match \`-0\` as \`0\``, () => { + assert.strictEqual(func([-0], 0), 0); + assert.strictEqual(func([0], -0), 0); + }); + }, + ); +}); diff --git a/test/indexOf.spec.ts b/test/indexOf.spec.ts new file mode 100644 index 000000000..8a4899323 --- /dev/null +++ b/test/indexOf.spec.ts @@ -0,0 +1,54 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubZero, falsey } from './utils'; +import indexOf from '../src/indexOf'; + +describe('indexOf', () => { + const array = [1, 2, 3, 1, 2, 3]; + + it('`_.indexOf` should return the index of the first matched value', () => { + assert.strictEqual(indexOf(array, 3), 2); + }); + + it('`_.indexOf` should work with a positive `fromIndex`', () => { + assert.strictEqual(indexOf(array, 1, 2), 3); + }); + + it('`_.indexOf` should work with a `fromIndex` >= `length`', () => { + const values = [6, 8, 2 ** 32, Infinity], + expected = lodashStable.map(values, lodashStable.constant([-1, -1, -1])); + + const actual = lodashStable.map(values, (fromIndex) => [ + indexOf(array, undefined, fromIndex), + indexOf(array, 1, fromIndex), + indexOf(array, '', fromIndex), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it('`_.indexOf` should work with a negative `fromIndex`', () => { + assert.strictEqual(indexOf(array, 2, -3), 4); + }); + + it('`_.indexOf` should work with a negative `fromIndex` <= `-length`', () => { + const values = [-6, -8, -Infinity], + expected = lodashStable.map(values, stubZero); + + const actual = lodashStable.map(values, (fromIndex) => indexOf(array, 1, fromIndex)); + + assert.deepStrictEqual(actual, expected); + }); + + it('`_.indexOf` should treat falsey `fromIndex` values as `0`', () => { + const expected = lodashStable.map(falsey, stubZero); + + const actual = lodashStable.map(falsey, (fromIndex) => indexOf(array, 1, fromIndex)); + + assert.deepStrictEqual(actual, expected); + }); + + it('`_.indexOf` should coerce `fromIndex` to an integer', () => { + assert.strictEqual(indexOf(array, 2, 1.2), 1); + }); +}); diff --git a/test/indexOf.test.js b/test/indexOf.test.js deleted file mode 100644 index 49fc80861..000000000 --- a/test/indexOf.test.js +++ /dev/null @@ -1,60 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubZero, falsey } from './utils.js'; -import indexOf from '../indexOf.js'; - -describe('indexOf', function() { - var array = [1, 2, 3, 1, 2, 3]; - - it('`_.indexOf` should return the index of the first matched value', function() { - assert.strictEqual(indexOf(array, 3), 2); - }); - - it('`_.indexOf` should work with a positive `fromIndex`', function() { - assert.strictEqual(indexOf(array, 1, 2), 3); - }); - - it('`_.indexOf` should work with a `fromIndex` >= `length`', function() { - var values = [6, 8, Math.pow(2, 32), Infinity], - expected = lodashStable.map(values, lodashStable.constant([-1, -1, -1])); - - var actual = lodashStable.map(values, function(fromIndex) { - return [ - indexOf(array, undefined, fromIndex), - indexOf(array, 1, fromIndex), - indexOf(array, '', fromIndex) - ]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.indexOf` should work with a negative `fromIndex`', function() { - assert.strictEqual(indexOf(array, 2, -3), 4); - }); - - it('`_.indexOf` should work with a negative `fromIndex` <= `-length`', function() { - var values = [-6, -8, -Infinity], - expected = lodashStable.map(values, stubZero); - - var actual = lodashStable.map(values, function(fromIndex) { - return indexOf(array, 1, fromIndex); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.indexOf` should treat falsey `fromIndex` values as `0`', function() { - var expected = lodashStable.map(falsey, stubZero); - - var actual = lodashStable.map(falsey, function(fromIndex) { - return indexOf(array, 1, fromIndex); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.indexOf` should coerce `fromIndex` to an integer', function() { - assert.strictEqual(indexOf(array, 2, 1.2), 1); - }); -}); diff --git a/test/initial.js b/test/initial.js deleted file mode 100644 index c2891ca85..000000000 --- a/test/initial.js +++ /dev/null @@ -1,61 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubArray, LARGE_ARRAY_SIZE } from './utils.js'; -import initial from '../initial.js'; - -describe('initial', function() { - var array = [1, 2, 3]; - - it('should accept a falsey `array`', function() { - var expected = lodashStable.map(falsey, stubArray); - - var actual = lodashStable.map(falsey, function(array, index) { - try { - return index ? initial(array) : initial(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should exclude last element', function() { - assert.deepStrictEqual(initial(array), [1, 2]); - }); - - it('should return an empty when querying empty arrays', function() { - assert.deepStrictEqual(initial([]), []); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = lodashStable.map(array, initial); - - assert.deepStrictEqual(actual, [[1, 2], [4, 5], [7, 8]]); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE), - values = []; - - var actual = _(array).initial().filter(function(value) { - values.push(value); - return false; - }) - .value(); - - assert.deepEqual(actual, []); - assert.deepEqual(values, initial(array)); - - values = []; - - actual = _(array).filter(function(value) { - values.push(value); - return isEven(value); - }) - .initial() - .value(); - - assert.deepEqual(actual, initial(lodashStable.filter(array, isEven))); - assert.deepEqual(values, array); - }); -}); diff --git a/test/initial.spec.ts b/test/initial.spec.ts new file mode 100644 index 000000000..451dd23ff --- /dev/null +++ b/test/initial.spec.ts @@ -0,0 +1,72 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubArray, LARGE_ARRAY_SIZE } from './utils'; +import initial from '../src/initial'; + +describe('initial', () => { + const array = [1, 2, 3]; + + it('should accept a falsey `array`', () => { + const expected = lodashStable.map(falsey, stubArray); + + const actual = lodashStable.map(falsey, (array, index) => { + try { + return index ? initial(array) : initial(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should exclude last element', () => { + assert.deepStrictEqual(initial(array), [1, 2]); + }); + + it('should return an empty when querying empty arrays', () => { + assert.deepStrictEqual(initial([]), []); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + actual = lodashStable.map(array, initial); + + assert.deepStrictEqual(actual, [ + [1, 2], + [4, 5], + [7, 8], + ]); + }); + + it('should work in a lazy sequence', () => { + let array = lodashStable.range(LARGE_ARRAY_SIZE), + values = []; + + let actual = _(array) + .initial() + .filter((value) => { + values.push(value); + return false; + }) + .value(); + + assert.deepEqual(actual, []); + assert.deepEqual(values, initial(array)); + + values = []; + + actual = _(array) + .filter((value) => { + values.push(value); + return isEven(value); + }) + .initial() + .value(); + + assert.deepEqual(actual, initial(lodashStable.filter(array, isEven))); + assert.deepEqual(values, array); + }); +}); diff --git a/test/intersection-methods.js b/test/intersection-methods.js deleted file mode 100644 index d90104da7..000000000 --- a/test/intersection-methods.js +++ /dev/null @@ -1,91 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, args, LARGE_ARRAY_SIZE, stubNaN } from './utils.js'; - -describe('intersection methods', function() { - lodashStable.each(['intersection', 'intersectionBy', 'intersectionWith'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should return the intersection of two arrays', function() { - var actual = func([2, 1], [2, 3]); - assert.deepStrictEqual(actual, [2]); - }); - - it('`_.' + methodName + '` should return the intersection of multiple arrays', function() { - var actual = func([2, 1, 2, 3], [3, 4], [3, 2]); - assert.deepStrictEqual(actual, [3]); - }); - - it('`_.' + methodName + '` should return an array of unique values', function() { - var actual = func([1, 1, 3, 2, 2], [5, 2, 2, 1, 4], [2, 1, 1]); - assert.deepStrictEqual(actual, [1, 2]); - }); - - it('`_.' + methodName + '` should work with a single array', function() { - var actual = func([1, 1, 3, 2, 2]); - assert.deepStrictEqual(actual, [1, 3, 2]); - }); - - it('`_.' + methodName + '` should work with `arguments` objects', function() { - var array = [0, 1, null, 3], - expected = [1, 3]; - - assert.deepStrictEqual(func(array, args), expected); - assert.deepStrictEqual(func(args, array), expected); - }); - - it('`_.' + methodName + '` should treat `-0` as `0`', function() { - var values = [-0, 0], - expected = lodashStable.map(values, lodashStable.constant(['0'])); - - var actual = lodashStable.map(values, function(value) { - return lodashStable.map(func(values, [value]), lodashStable.toString); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should match `NaN`', function() { - var actual = func([1, NaN, 3], [NaN, 5, NaN]); - assert.deepStrictEqual(actual, [NaN]); - }); - - it('`_.' + methodName + '` should work with large arrays of `-0` as `0`', function() { - var values = [-0, 0], - expected = lodashStable.map(values, lodashStable.constant(['0'])); - - var actual = lodashStable.map(values, function(value) { - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(value)); - return lodashStable.map(func(values, largeArray), lodashStable.toString); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with large arrays of `NaN`', function() { - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubNaN); - assert.deepStrictEqual(func([1, NaN, 3], largeArray), [NaN]); - }); - - it('`_.' + methodName + '` should work with large arrays of objects', function() { - var object = {}, - largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object)); - - assert.deepStrictEqual(func([object], largeArray), [object]); - assert.deepStrictEqual(func(lodashStable.range(LARGE_ARRAY_SIZE), [1]), [1]); - }); - - it('`_.' + methodName + '` should treat values that are not arrays or `arguments` objects as empty', function() { - var array = [0, 1, null, 3]; - assert.deepStrictEqual(func(array, 3, { '0': 1 }, null), []); - assert.deepStrictEqual(func(null, array, null, [2, 3]), []); - assert.deepStrictEqual(func(array, null, args, null), []); - }); - - it('`_.' + methodName + '` should return a wrapped value when chaining', function() { - var wrapped = _([1, 3, 2])[methodName]([5, 2, 1, 4]); - assert.ok(wrapped instanceof _); - assert.deepEqual(wrapped.value(), [1, 2]); - }); - }); -}); diff --git a/test/intersection-methods.spec.ts b/test/intersection-methods.spec.ts new file mode 100644 index 000000000..6c5ee75aa --- /dev/null +++ b/test/intersection-methods.spec.ts @@ -0,0 +1,94 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, args, LARGE_ARRAY_SIZE, stubNaN } from './utils'; + +describe('intersection methods', () => { + lodashStable.each(['intersection', 'intersectionBy', 'intersectionWith'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should return the intersection of two arrays`, () => { + const actual = func([2, 1], [2, 3]); + assert.deepStrictEqual(actual, [2]); + }); + + it(`\`_.${methodName}\` should return the intersection of multiple arrays`, () => { + const actual = func([2, 1, 2, 3], [3, 4], [3, 2]); + assert.deepStrictEqual(actual, [3]); + }); + + it(`\`_.${methodName}\` should return an array of unique values`, () => { + const actual = func([1, 1, 3, 2, 2], [5, 2, 2, 1, 4], [2, 1, 1]); + assert.deepStrictEqual(actual, [1, 2]); + }); + + it(`\`_.${methodName}\` should work with a single array`, () => { + const actual = func([1, 1, 3, 2, 2]); + assert.deepStrictEqual(actual, [1, 3, 2]); + }); + + it(`\`_.${methodName}\` should work with \`arguments\` objects`, () => { + const array = [0, 1, null, 3], + expected = [1, 3]; + + assert.deepStrictEqual(func(array, args), expected); + assert.deepStrictEqual(func(args, array), expected); + }); + + it(`\`_.${methodName}\` should treat \`-0\` as \`0\``, () => { + const values = [-0, 0], + expected = lodashStable.map(values, lodashStable.constant(['0'])); + + const actual = lodashStable.map(values, (value) => + lodashStable.map(func(values, [value]), lodashStable.toString), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should match \`NaN\``, () => { + const actual = func([1, NaN, 3], [NaN, 5, NaN]); + assert.deepStrictEqual(actual, [NaN]); + }); + + it(`\`_.${methodName}\` should work with large arrays of \`-0\` as \`0\``, () => { + const values = [-0, 0], + expected = lodashStable.map(values, lodashStable.constant(['0'])); + + const actual = lodashStable.map(values, (value) => { + const largeArray = lodashStable.times( + LARGE_ARRAY_SIZE, + lodashStable.constant(value), + ); + return lodashStable.map(func(values, largeArray), lodashStable.toString); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with large arrays of \`NaN\``, () => { + const largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubNaN); + assert.deepStrictEqual(func([1, NaN, 3], largeArray), [NaN]); + }); + + it(`\`_.${methodName}\` should work with large arrays of objects`, () => { + const object = {}, + largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object)); + + assert.deepStrictEqual(func([object], largeArray), [object]); + assert.deepStrictEqual(func(lodashStable.range(LARGE_ARRAY_SIZE), [1]), [1]); + }); + + it(`\`_.${methodName}\` should treat values that are not arrays or \`arguments\` objects as empty`, () => { + const array = [0, 1, null, 3]; + assert.deepStrictEqual(func(array, 3, { '0': 1 }, null), []); + assert.deepStrictEqual(func(null, array, null, [2, 3]), []); + assert.deepStrictEqual(func(array, null, args, null), []); + }); + + it(`\`_.${methodName}\` should return a wrapped value when chaining`, () => { + const wrapped = _([1, 3, 2])[methodName]([5, 2, 1, 4]); + assert.ok(wrapped instanceof _); + assert.deepEqual(wrapped.value(), [1, 2]); + }); + }); +}); diff --git a/test/intersectionBy.js b/test/intersectionBy.js deleted file mode 100644 index c2a988f1c..000000000 --- a/test/intersectionBy.js +++ /dev/null @@ -1,23 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import intersectionBy from '../intersectionBy.js'; - -describe('intersectionBy', function() { - it('should accept an `iteratee`', function() { - var actual = intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); - assert.deepStrictEqual(actual, [2.1]); - - actual = intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - assert.deepStrictEqual(actual, [{ 'x': 1 }]); - }); - - it('should provide correct `iteratee` arguments', function() { - var args; - - intersectionBy([2.1, 1.2], [2.3, 3.4], function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [2.3]); - }); -}); diff --git a/test/intersectionBy.spec.ts b/test/intersectionBy.spec.ts new file mode 100644 index 000000000..abdc0e0c1 --- /dev/null +++ b/test/intersectionBy.spec.ts @@ -0,0 +1,23 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import intersectionBy from '../src/intersectionBy'; + +describe('intersectionBy', () => { + it('should accept an `iteratee`', () => { + let actual = intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); + assert.deepStrictEqual(actual, [2.1]); + + actual = intersectionBy([{ x: 1 }], [{ x: 2 }, { x: 1 }], 'x'); + assert.deepStrictEqual(actual, [{ x: 1 }]); + }); + + it('should provide correct `iteratee` arguments', () => { + let args; + + intersectionBy([2.1, 1.2], [2.3, 3.4], function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [2.3]); + }); +}); diff --git a/test/intersectionWith.spec.ts b/test/intersectionWith.spec.ts new file mode 100644 index 000000000..0a41447b7 --- /dev/null +++ b/test/intersectionWith.spec.ts @@ -0,0 +1,36 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE, stubZero } from './utils'; +import intersectionWith from '../src/intersectionWith'; + +describe('intersectionWith', () => { + it('should work with a `comparator`', () => { + const objects = [ + { x: 1, y: 2 }, + { x: 2, y: 1 }, + ], + others = [ + { x: 1, y: 1 }, + { x: 1, y: 2 }, + ], + actual = intersectionWith(objects, others, lodashStable.isEqual); + + assert.deepStrictEqual(actual, [objects[0]]); + }); + + it('should preserve the sign of `0`', () => { + const array = [-0], + largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubZero), + others = [[0], largeArray], + expected = lodashStable.map(others, lodashStable.constant(['-0'])); + + const actual = lodashStable.map(others, (other) => + lodashStable.map( + intersectionWith(array, other, lodashStable.eq), + lodashStable.toString, + ), + ); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/intersectionWith.test.js b/test/intersectionWith.test.js deleted file mode 100644 index 72b3cbee3..000000000 --- a/test/intersectionWith.test.js +++ /dev/null @@ -1,27 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE, stubZero } from './utils.js'; -import intersectionWith from '../intersectionWith.js'; - -describe('intersectionWith', function() { - it('should work with a `comparator`', function() { - var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }], - others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }], - actual = intersectionWith(objects, others, lodashStable.isEqual); - - assert.deepStrictEqual(actual, [objects[0]]); - }); - - it('should preserve the sign of `0`', function() { - var array = [-0], - largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubZero), - others = [[0], largeArray], - expected = lodashStable.map(others, lodashStable.constant(['-0'])); - - var actual = lodashStable.map(others, function(other) { - return lodashStable.map(intersectionWith(array, other, lodashStable.eq), lodashStable.toString); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/invert.spec.ts b/test/invert.spec.ts new file mode 100644 index 000000000..68a0ecc8d --- /dev/null +++ b/test/invert.spec.ts @@ -0,0 +1,30 @@ +import assert from 'node:assert'; +import invert from '../src/invert'; + +describe('invert', () => { + it('should invert an object', () => { + const object = { a: 1, b: 2 }, + actual = invert(object); + + assert.deepStrictEqual(actual, { '1': 'a', '2': 'b' }); + assert.deepStrictEqual(invert(actual), { a: '1', b: '2' }); + }); + + it('should work with values that shadow keys on `Object.prototype`', () => { + const object = { a: 'hasOwnProperty', b: 'constructor' }; + assert.deepStrictEqual(invert(object), { hasOwnProperty: 'a', constructor: 'b' }); + }); + + it('should work with an object that has a `length` property', () => { + const object = { '0': 'a', '1': 'b', length: 2 }; + assert.deepStrictEqual(invert(object), { a: '0', b: '1', '2': 'length' }); + }); + + it('should return a wrapped value when chaining', () => { + const object = { a: 1, b: 2 }, + wrapped = _(object).invert(); + + assert.ok(wrapped instanceof _); + assert.deepEqual(wrapped.value(), { '1': 'a', '2': 'b' }); + }); +}); diff --git a/test/invert.test.js b/test/invert.test.js deleted file mode 100644 index 5fbfd22f2..000000000 --- a/test/invert.test.js +++ /dev/null @@ -1,30 +0,0 @@ -import assert from 'assert'; -import invert from '../invert.js'; - -describe('invert', function() { - it('should invert an object', function() { - var object = { 'a': 1, 'b': 2 }, - actual = invert(object); - - assert.deepStrictEqual(actual, { '1': 'a', '2': 'b' }); - assert.deepStrictEqual(invert(actual), { 'a': '1', 'b': '2' }); - }); - - it('should work with values that shadow keys on `Object.prototype`', function() { - var object = { 'a': 'hasOwnProperty', 'b': 'constructor' }; - assert.deepStrictEqual(invert(object), { 'hasOwnProperty': 'a', 'constructor': 'b' }); - }); - - it('should work with an object that has a `length` property', function() { - var object = { '0': 'a', '1': 'b', 'length': 2 }; - assert.deepStrictEqual(invert(object), { 'a': '0', 'b': '1', '2': 'length' }); - }); - - it('should return a wrapped value when chaining', function() { - var object = { 'a': 1, 'b': 2 }, - wrapped = _(object).invert(); - - assert.ok(wrapped instanceof _); - assert.deepEqual(wrapped.value(), { '1': 'a', '2': 'b' }); - }); -}); diff --git a/test/invertBy.js b/test/invertBy.js deleted file mode 100644 index 42379222e..000000000 --- a/test/invertBy.js +++ /dev/null @@ -1,42 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import invertBy from '../invertBy.js'; - -describe('invertBy', function() { - var object = { 'a': 1, 'b': 2, 'c': 1 }; - - it('should transform keys by `iteratee`', function() { - var expected = { 'group1': ['a', 'c'], 'group2': ['b'] }; - - var actual = invertBy(object, function(value) { - return 'group' + value; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant({ '1': ['a', 'c'], '2': ['b'] })); - - var actual = lodashStable.map(values, function(value, index) { - return index ? invertBy(object, value) : invertBy(object); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should only add multiple values to own, not inherited, properties', function() { - var object = { 'a': 'hasOwnProperty', 'b': 'constructor' }, - expected = { 'hasOwnProperty': ['a'], 'constructor': ['b'] }; - - assert.ok(lodashStable.isEqual(invertBy(object), expected)); - }); - - it('should return a wrapped value when chaining', function() { - var wrapped = _(object).invertBy(); - - assert.ok(wrapped instanceof _); - assert.deepEqual(wrapped.value(), { '1': ['a', 'c'], '2': ['b'] }); - }); -}); diff --git a/test/invertBy.spec.ts b/test/invertBy.spec.ts new file mode 100644 index 000000000..9749123c7 --- /dev/null +++ b/test/invertBy.spec.ts @@ -0,0 +1,43 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import invertBy from '../src/invertBy'; + +describe('invertBy', () => { + const object = { a: 1, b: 2, c: 1 }; + + it('should transform keys by `iteratee`', () => { + const expected = { group1: ['a', 'c'], group2: ['b'] }; + + const actual = invertBy(object, (value) => `group${value}`); + + assert.deepStrictEqual(actual, expected); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map( + values, + lodashStable.constant({ '1': ['a', 'c'], '2': ['b'] }), + ); + + const actual = lodashStable.map(values, (value, index) => + index ? invertBy(object, value) : invertBy(object), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should only add multiple values to own, not inherited, properties', () => { + const object = { a: 'hasOwnProperty', b: 'constructor' }, + expected = { hasOwnProperty: ['a'], constructor: ['b'] }; + + assert.ok(lodashStable.isEqual(invertBy(object), expected)); + }); + + it('should return a wrapped value when chaining', () => { + const wrapped = _(object).invertBy(); + + assert.ok(wrapped instanceof _); + assert.deepEqual(wrapped.value(), { '1': ['a', 'c'], '2': ['b'] }); + }); +}); diff --git a/test/invoke.js b/test/invoke.js deleted file mode 100644 index 4d046a80e..000000000 --- a/test/invoke.js +++ /dev/null @@ -1,71 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { noop, stubA, stubB, stubOne } from './utils.js'; -import invoke from '../invoke.js'; - -describe('invoke', function() { - it('should invoke a method on `object`', function() { - var object = { 'a': lodashStable.constant('A') }, - actual = invoke(object, 'a'); - - assert.strictEqual(actual, 'A'); - }); - - it('should support invoking with arguments', function() { - var object = { 'a': function(a, b) { return [a, b]; } }, - actual = invoke(object, 'a', 1, 2); - - assert.deepStrictEqual(actual, [1, 2]); - }); - - it('should not error on nullish elements', function() { - var values = [null, undefined], - expected = lodashStable.map(values, noop); - - var actual = lodashStable.map(values, function(value) { - try { - return invoke(value, 'a.b', 1, 2); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should preserve the sign of `0`', function() { - var object = { '-0': stubA, '0': stubB }, - props = [-0, Object(-0), 0, Object(0)]; - - var actual = lodashStable.map(props, function(key) { - return invoke(object, key); - }); - - assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']); - }); - - it('should support deep paths', function() { - var object = { 'a': { 'b': function(a, b) { return [a, b]; } } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var actual = invoke(object, path, 1, 2); - assert.deepStrictEqual(actual, [1, 2]); - }); - }); - - it('should invoke deep property methods with the correct `this` binding', function() { - var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.deepStrictEqual(invoke(object, path), 1); - }); - }); - - it('should return an unwrapped value when implicitly chaining', function() { - var object = { 'a': stubOne }; - assert.strictEqual(_(object).invoke('a'), 1); - }); - - it('should return a wrapped value when explicitly chaining', function() { - var object = { 'a': stubOne }; - assert.ok(_(object).chain().invoke('a') instanceof _); - }); -}); diff --git a/test/invoke.spec.ts b/test/invoke.spec.ts new file mode 100644 index 000000000..264ba6370 --- /dev/null +++ b/test/invoke.spec.ts @@ -0,0 +1,86 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { noop, stubA, stubB, stubOne } from './utils'; +import invoke from '../src/invoke'; + +describe('invoke', () => { + it('should invoke a method on `object`', () => { + const object = { a: lodashStable.constant('A') }, + actual = invoke(object, 'a'); + + assert.strictEqual(actual, 'A'); + }); + + it('should support invoking with arguments', () => { + const object = { + a: function (a, b) { + return [a, b]; + }, + }, + actual = invoke(object, 'a', 1, 2); + + assert.deepStrictEqual(actual, [1, 2]); + }); + + it('should not error on nullish elements', () => { + const values = [null, undefined], + expected = lodashStable.map(values, noop); + + const actual = lodashStable.map(values, (value) => { + try { + return invoke(value, 'a.b', 1, 2); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should preserve the sign of `0`', () => { + const object = { '-0': stubA, '0': stubB }, + props = [-0, Object(-0), 0, Object(0)]; + + const actual = lodashStable.map(props, (key) => invoke(object, key)); + + assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']); + }); + + it('should support deep paths', () => { + const object = { + a: { + b: function (a, b) { + return [a, b]; + }, + }, + }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const actual = invoke(object, path, 1, 2); + assert.deepStrictEqual(actual, [1, 2]); + }); + }); + + it('should invoke deep property methods with the correct `this` binding', () => { + const object = { + a: { + b: function () { + return this.c; + }, + c: 1, + }, + }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.deepStrictEqual(invoke(object, path), 1); + }); + }); + + it('should return an unwrapped value when implicitly chaining', () => { + const object = { a: stubOne }; + assert.strictEqual(_(object).invoke('a'), 1); + }); + + it('should return a wrapped value when explicitly chaining', () => { + const object = { a: stubOne }; + assert.ok(_(object).chain().invoke('a') instanceof _); + }); +}); diff --git a/test/invokeMap.js b/test/invokeMap.js deleted file mode 100644 index bb3ba944f..000000000 --- a/test/invokeMap.js +++ /dev/null @@ -1,105 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, stubOne } from './utils.js'; -import invokeMap from '../invokeMap.js'; - -describe('invokeMap', function() { - it('should invoke a methods on each element of `collection`', function() { - var array = ['a', 'b', 'c'], - actual = invokeMap(array, 'toUpperCase'); - - assert.deepStrictEqual(actual, ['A', 'B', 'C']); - }); - - it('should support invoking with arguments', function() { - var array = [function() { return slice.call(arguments); }], - actual = invokeMap(array, 'call', null, 'a', 'b', 'c'); - - assert.deepStrictEqual(actual, [['a', 'b', 'c']]); - }); - - it('should work with a function for `methodName`', function() { - var array = ['a', 'b', 'c']; - - var actual = invokeMap(array, function(left, right) { - return left + this.toUpperCase() + right; - }, '(', ')'); - - assert.deepStrictEqual(actual, ['(A)', '(B)', '(C)']); - }); - - it('should work with an object for `collection`', function() { - var object = { 'a': 1, 'b': 2, 'c': 3 }, - actual = invokeMap(object, 'toFixed', 1); - - assert.deepStrictEqual(actual, ['1.0', '2.0', '3.0']); - }); - - it('should treat number values for `collection` as empty', function() { - assert.deepStrictEqual(invokeMap(1), []); - }); - - it('should not error on nullish elements', function() { - var array = ['a', null, undefined, 'd']; - - try { - var actual = invokeMap(array, 'toUpperCase'); - } catch (e) {} - - assert.deepStrictEqual(actual, ['A', undefined, undefined, 'D']); - }); - - it('should not error on elements with missing properties', function() { - var objects = lodashStable.map([null, undefined, stubOne], function(value) { - return { 'a': value }; - }); - - var expected = lodashStable.map(objects, function(object) { - return object.a ? object.a() : undefined; - }); - - try { - var actual = invokeMap(objects, 'a'); - } catch (e) {} - - assert.deepStrictEqual(actual, expected); - }); - - it('should invoke deep property methods with the correct `this` binding', function() { - var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.deepStrictEqual(invokeMap([object], path), [1]); - }); - }); - - it('should return a wrapped value when chaining', function() { - var array = ['a', 'b', 'c'], - wrapped = _(array), - actual = wrapped.invokeMap('toUpperCase'); - - assert.ok(actual instanceof _); - assert.deepEqual(actual.valueOf(), ['A', 'B', 'C']); - - actual = wrapped.invokeMap(function(left, right) { - return left + this.toUpperCase() + right; - }, '(', ')'); - - assert.ok(actual instanceof _); - assert.deepEqual(actual.valueOf(), ['(A)', '(B)', '(C)']); - }); - - it('should support shortcut fusion', function() { - var count = 0, - method = function() { count++; return this.index; }; - - var array = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { - return { 'index': index, 'method': method }; - }); - - var actual = _(array).invokeMap('method').take(1).value(); - - assert.strictEqual(count, 1); - assert.deepEqual(actual, [0]); - }); -}); diff --git a/test/invokeMap.spec.ts b/test/invokeMap.spec.ts new file mode 100644 index 000000000..5a3edba17 --- /dev/null +++ b/test/invokeMap.spec.ts @@ -0,0 +1,125 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, stubOne } from './utils'; +import invokeMap from '../src/invokeMap'; + +describe('invokeMap', () => { + it('should invoke a methods on each element of `collection`', () => { + const array = ['a', 'b', 'c'], + actual = invokeMap(array, 'toUpperCase'); + + assert.deepStrictEqual(actual, ['A', 'B', 'C']); + }); + + it('should support invoking with arguments', () => { + const array = [ + function () { + return slice.call(arguments); + }, + ], + actual = invokeMap(array, 'call', null, 'a', 'b', 'c'); + + assert.deepStrictEqual(actual, [['a', 'b', 'c']]); + }); + + it('should work with a function for `methodName`', () => { + const array = ['a', 'b', 'c']; + + const actual = invokeMap( + array, + function (left, right) { + return left + this.toUpperCase() + right; + }, + '(', + ')', + ); + + assert.deepStrictEqual(actual, ['(A)', '(B)', '(C)']); + }); + + it('should work with an object for `collection`', () => { + const object = { a: 1, b: 2, c: 3 }, + actual = invokeMap(object, 'toFixed', 1); + + assert.deepStrictEqual(actual, ['1.0', '2.0', '3.0']); + }); + + it('should treat number values for `collection` as empty', () => { + assert.deepStrictEqual(invokeMap(1), []); + }); + + it('should not error on nullish elements', () => { + const array = ['a', null, undefined, 'd']; + + try { + var actual = invokeMap(array, 'toUpperCase'); + } catch (e) {} + + assert.deepStrictEqual(actual, ['A', undefined, undefined, 'D']); + }); + + it('should not error on elements with missing properties', () => { + const objects = lodashStable.map([null, undefined, stubOne], (value) => ({ a: value })); + + const expected = lodashStable.map(objects, (object) => (object.a ? object.a() : undefined)); + + try { + var actual = invokeMap(objects, 'a'); + } catch (e) {} + + assert.deepStrictEqual(actual, expected); + }); + + it('should invoke deep property methods with the correct `this` binding', () => { + const object = { + a: { + b: function () { + return this.c; + }, + c: 1, + }, + }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.deepStrictEqual(invokeMap([object], path), [1]); + }); + }); + + it('should return a wrapped value when chaining', () => { + let array = ['a', 'b', 'c'], + wrapped = _(array), + actual = wrapped.invokeMap('toUpperCase'); + + assert.ok(actual instanceof _); + assert.deepEqual(actual.valueOf(), ['A', 'B', 'C']); + + actual = wrapped.invokeMap( + function (left, right) { + return left + this.toUpperCase() + right; + }, + '(', + ')', + ); + + assert.ok(actual instanceof _); + assert.deepEqual(actual.valueOf(), ['(A)', '(B)', '(C)']); + }); + + it('should support shortcut fusion', () => { + let count = 0, + method = function () { + count++; + return this.index; + }; + + const array = lodashStable.times(LARGE_ARRAY_SIZE, (index) => ({ + index: index, + method: method, + })); + + const actual = _(array).invokeMap('method').take(1).value(); + + assert.strictEqual(count, 1); + assert.deepEqual(actual, [0]); + }); +}); diff --git a/test/isArguments.spec.ts b/test/isArguments.spec.ts new file mode 100644 index 000000000..96cbce456 --- /dev/null +++ b/test/isArguments.spec.ts @@ -0,0 +1,38 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, strictArgs, falsey, stubFalse, slice, noop, symbol, realm } from './utils'; +import isArguments from '../src/isArguments'; + +describe('isArguments', () => { + it('should return `true` for `arguments` objects', () => { + assert.strictEqual(isArguments(args), true); + assert.strictEqual(isArguments(strictArgs), true); + }); + + it('should return `false` for non `arguments` objects', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isArguments(value) : isArguments(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isArguments([1, 2, 3]), false); + assert.strictEqual(isArguments(true), false); + assert.strictEqual(isArguments(new Date()), false); + assert.strictEqual(isArguments(new Error()), false); + assert.strictEqual(isArguments(slice), false); + assert.strictEqual(isArguments({ '0': 1, callee: noop, length: 1 }), false); + assert.strictEqual(isArguments(1), false); + assert.strictEqual(isArguments(/x/), false); + assert.strictEqual(isArguments('a'), false); + assert.strictEqual(isArguments(symbol), false); + }); + + it('should work with an `arguments` object from another realm', () => { + if (realm.arguments) { + assert.strictEqual(isArguments(realm.arguments), true); + } + }); +}); diff --git a/test/isArguments.test.js b/test/isArguments.test.js deleted file mode 100644 index 87c62a980..000000000 --- a/test/isArguments.test.js +++ /dev/null @@ -1,39 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, strictArgs, falsey, stubFalse, slice, noop, symbol, realm } from './utils.js'; -import isArguments from '../isArguments.js'; - -describe('isArguments', function() { - it('should return `true` for `arguments` objects', function() { - assert.strictEqual(isArguments(args), true); - assert.strictEqual(isArguments(strictArgs), true); - }); - - it('should return `false` for non `arguments` objects', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isArguments(value) : isArguments(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isArguments([1, 2, 3]), false); - assert.strictEqual(isArguments(true), false); - assert.strictEqual(isArguments(new Date), false); - assert.strictEqual(isArguments(new Error), false); - assert.strictEqual(isArguments(_), false); - assert.strictEqual(isArguments(slice), false); - assert.strictEqual(isArguments({ '0': 1, 'callee': noop, 'length': 1 }), false); - assert.strictEqual(isArguments(1), false); - assert.strictEqual(isArguments(/x/), false); - assert.strictEqual(isArguments('a'), false); - assert.strictEqual(isArguments(symbol), false); - }); - - it('should work with an `arguments` object from another realm', function() { - if (realm.arguments) { - assert.strictEqual(isArguments(realm.arguments), true); - } - }); -}); diff --git a/test/isArray.js b/test/isArray.js deleted file mode 100644 index 552796755..000000000 --- a/test/isArray.js +++ /dev/null @@ -1,38 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubFalse, args, slice, symbol, realm } from './utils.js'; -import isArray from '../isArray.js'; - -describe('isArray', function() { - it('should return `true` for arrays', function() { - assert.strictEqual(isArray([1, 2, 3]), true); - }); - - it('should return `false` for non-arrays', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isArray(value) : isArray(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isArray(args), false); - assert.strictEqual(isArray(true), false); - assert.strictEqual(isArray(new Date), false); - assert.strictEqual(isArray(new Error), false); - assert.strictEqual(isArray(_), false); - assert.strictEqual(isArray(slice), false); - assert.strictEqual(isArray({ '0': 1, 'length': 1 }), false); - assert.strictEqual(isArray(1), false); - assert.strictEqual(isArray(/x/), false); - assert.strictEqual(isArray('a'), false); - assert.strictEqual(isArray(symbol), false); - }); - - it('should work with an array from another realm', function() { - if (realm.array) { - assert.strictEqual(isArray(realm.array), true); - } - }); -}); diff --git a/test/isArray.spec.ts b/test/isArray.spec.ts new file mode 100644 index 000000000..1e55fe1e3 --- /dev/null +++ b/test/isArray.spec.ts @@ -0,0 +1,37 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubFalse, args, slice, symbol, realm } from './utils'; +import isArray from '../src/isArray'; + +describe('isArray', () => { + it('should return `true` for arrays', () => { + assert.strictEqual(isArray([1, 2, 3]), true); + }); + + it('should return `false` for non-arrays', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isArray(value) : isArray(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isArray(args), false); + assert.strictEqual(isArray(true), false); + assert.strictEqual(isArray(new Date()), false); + assert.strictEqual(isArray(new Error()), false); + assert.strictEqual(isArray(slice), false); + assert.strictEqual(isArray({ '0': 1, length: 1 }), false); + assert.strictEqual(isArray(1), false); + assert.strictEqual(isArray(/x/), false); + assert.strictEqual(isArray('a'), false); + assert.strictEqual(isArray(symbol), false); + }); + + it('should work with an array from another realm', () => { + if (realm.array) { + assert.strictEqual(isArray(realm.array), true); + } + }); +}); diff --git a/test/isArrayBuffer.spec.ts b/test/isArrayBuffer.spec.ts new file mode 100644 index 000000000..6ca6ee059 --- /dev/null +++ b/test/isArrayBuffer.spec.ts @@ -0,0 +1,40 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { arrayBuffer, falsey, stubFalse, args, slice, symbol, realm } from './utils'; +import isArrayBuffer from '../src/isArrayBuffer'; + +describe('isArrayBuffer', () => { + it('should return `true` for array buffers', () => { + if (ArrayBuffer) { + assert.strictEqual(isArrayBuffer(arrayBuffer), true); + } + }); + + it('should return `false` for non array buffers', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isArrayBuffer(value) : isArrayBuffer(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isArrayBuffer(args), false); + assert.strictEqual(isArrayBuffer([1]), false); + assert.strictEqual(isArrayBuffer(true), false); + assert.strictEqual(isArrayBuffer(new Date()), false); + assert.strictEqual(isArrayBuffer(new Error()), false); + assert.strictEqual(isArrayBuffer(slice), false); + assert.strictEqual(isArrayBuffer({ a: 1 }), false); + assert.strictEqual(isArrayBuffer(1), false); + assert.strictEqual(isArrayBuffer(/x/), false); + assert.strictEqual(isArrayBuffer('a'), false); + assert.strictEqual(isArrayBuffer(symbol), false); + }); + + it('should work with array buffers from another realm', () => { + if (realm.arrayBuffer) { + assert.strictEqual(isArrayBuffer(realm.arrayBuffer), true); + } + }); +}); diff --git a/test/isArrayBuffer.test.js b/test/isArrayBuffer.test.js deleted file mode 100644 index 7ac1bf098..000000000 --- a/test/isArrayBuffer.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { arrayBuffer, falsey, stubFalse, args, slice, symbol, realm } from './utils.js'; -import isArrayBuffer from '../isArrayBuffer.js'; - -describe('isArrayBuffer', function() { - it('should return `true` for array buffers', function() { - if (ArrayBuffer) { - assert.strictEqual(isArrayBuffer(arrayBuffer), true); - } - }); - - it('should return `false` for non array buffers', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isArrayBuffer(value) : isArrayBuffer(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isArrayBuffer(args), false); - assert.strictEqual(isArrayBuffer([1]), false); - assert.strictEqual(isArrayBuffer(true), false); - assert.strictEqual(isArrayBuffer(new Date), false); - assert.strictEqual(isArrayBuffer(new Error), false); - assert.strictEqual(isArrayBuffer(_), false); - assert.strictEqual(isArrayBuffer(slice), false); - assert.strictEqual(isArrayBuffer({ 'a': 1 }), false); - assert.strictEqual(isArrayBuffer(1), false); - assert.strictEqual(isArrayBuffer(/x/), false); - assert.strictEqual(isArrayBuffer('a'), false); - assert.strictEqual(isArrayBuffer(symbol), false); - }); - - it('should work with array buffers from another realm', function() { - if (realm.arrayBuffer) { - assert.strictEqual(isArrayBuffer(realm.arrayBuffer), true); - } - }); -}); diff --git a/test/isArrayLike.spec.ts b/test/isArrayLike.spec.ts new file mode 100644 index 000000000..250aa9f81 --- /dev/null +++ b/test/isArrayLike.spec.ts @@ -0,0 +1,45 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, stubTrue, falsey, asyncFunc, genFunc, slice, symbol, realm } from './utils'; +import isArrayLike from '../src/isArrayLike'; + +describe('isArrayLike', () => { + it('should return `true` for array-like values', () => { + const values = [args, [1, 2, 3], { '0': 'a', length: 1 }, 'a'], + expected = lodashStable.map(values, stubTrue), + actual = lodashStable.map(values, isArrayLike); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `false` for non-arrays', () => { + const expected = lodashStable.map(falsey, (value) => value === ''); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isArrayLike(value) : isArrayLike(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isArrayLike(true), false); + assert.strictEqual(isArrayLike(new Date()), false); + assert.strictEqual(isArrayLike(new Error()), false); + assert.strictEqual(isArrayLike(asyncFunc), false); + assert.strictEqual(isArrayLike(genFunc), false); + assert.strictEqual(isArrayLike(slice), false); + assert.strictEqual(isArrayLike({ a: 1 }), false); + assert.strictEqual(isArrayLike(1), false); + assert.strictEqual(isArrayLike(/x/), false); + assert.strictEqual(isArrayLike(symbol), false); + }); + + it('should work with an array from another realm', () => { + if (realm.object) { + const values = [realm.arguments, realm.array, realm.string], + expected = lodashStable.map(values, stubTrue), + actual = lodashStable.map(values, isArrayLike); + + assert.deepStrictEqual(actual, expected); + } + }); +}); diff --git a/test/isArrayLike.test.js b/test/isArrayLike.test.js deleted file mode 100644 index 6e332dd2d..000000000 --- a/test/isArrayLike.test.js +++ /dev/null @@ -1,48 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, stubTrue, falsey, asyncFunc, genFunc, slice, symbol, realm } from './utils.js'; -import isArrayLike from '../isArrayLike.js'; - -describe('isArrayLike', function() { - it('should return `true` for array-like values', function() { - var values = [args, [1, 2, 3], { '0': 'a', 'length': 1 }, 'a'], - expected = lodashStable.map(values, stubTrue), - actual = lodashStable.map(values, isArrayLike); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `false` for non-arrays', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === ''; - }); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isArrayLike(value) : isArrayLike(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isArrayLike(true), false); - assert.strictEqual(isArrayLike(new Date), false); - assert.strictEqual(isArrayLike(new Error), false); - assert.strictEqual(isArrayLike(_), false); - assert.strictEqual(isArrayLike(asyncFunc), false); - assert.strictEqual(isArrayLike(genFunc), false); - assert.strictEqual(isArrayLike(slice), false); - assert.strictEqual(isArrayLike({ 'a': 1 }), false); - assert.strictEqual(isArrayLike(1), false); - assert.strictEqual(isArrayLike(/x/), false); - assert.strictEqual(isArrayLike(symbol), false); - }); - - it('should work with an array from another realm', function() { - if (realm.object) { - var values = [realm.arguments, realm.array, realm.string], - expected = lodashStable.map(values, stubTrue), - actual = lodashStable.map(values, isArrayLike); - - assert.deepStrictEqual(actual, expected); - } - }); -}); diff --git a/test/isBoolean.spec.ts b/test/isBoolean.spec.ts new file mode 100644 index 000000000..05bc55888 --- /dev/null +++ b/test/isBoolean.spec.ts @@ -0,0 +1,40 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, args, slice, symbol, realm } from './utils'; +import isBoolean from '../src/isBoolean'; + +describe('isBoolean', () => { + it('should return `true` for booleans', () => { + assert.strictEqual(isBoolean(true), true); + assert.strictEqual(isBoolean(false), true); + assert.strictEqual(isBoolean(Object(true)), true); + assert.strictEqual(isBoolean(Object(false)), true); + }); + + it('should return `false` for non-booleans', () => { + const expected = lodashStable.map(falsey, (value) => value === false); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isBoolean(value) : isBoolean(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isBoolean(args), false); + assert.strictEqual(isBoolean([1, 2, 3]), false); + assert.strictEqual(isBoolean(new Date()), false); + assert.strictEqual(isBoolean(new Error()), false); + assert.strictEqual(isBoolean(slice), false); + assert.strictEqual(isBoolean({ a: 1 }), false); + assert.strictEqual(isBoolean(1), false); + assert.strictEqual(isBoolean(/x/), false); + assert.strictEqual(isBoolean('a'), false); + assert.strictEqual(isBoolean(symbol), false); + }); + + it('should work with a boolean from another realm', () => { + if (realm.boolean) { + assert.strictEqual(isBoolean(realm.boolean), true); + } + }); +}); diff --git a/test/isBoolean.test.js b/test/isBoolean.test.js deleted file mode 100644 index 6f6c2e3d4..000000000 --- a/test/isBoolean.test.js +++ /dev/null @@ -1,43 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, args, slice, symbol, realm } from './utils.js'; -import isBoolean from '../isBoolean.js'; - -describe('isBoolean', function() { - it('should return `true` for booleans', function() { - assert.strictEqual(isBoolean(true), true); - assert.strictEqual(isBoolean(false), true); - assert.strictEqual(isBoolean(Object(true)), true); - assert.strictEqual(isBoolean(Object(false)), true); - }); - - it('should return `false` for non-booleans', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === false; - }); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isBoolean(value) : isBoolean(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isBoolean(args), false); - assert.strictEqual(isBoolean([1, 2, 3]), false); - assert.strictEqual(isBoolean(new Date), false); - assert.strictEqual(isBoolean(new Error), false); - assert.strictEqual(isBoolean(_), false); - assert.strictEqual(isBoolean(slice), false); - assert.strictEqual(isBoolean({ 'a': 1 }), false); - assert.strictEqual(isBoolean(1), false); - assert.strictEqual(isBoolean(/x/), false); - assert.strictEqual(isBoolean('a'), false); - assert.strictEqual(isBoolean(symbol), false); - }); - - it('should work with a boolean from another realm', function() { - if (realm.boolean) { - assert.strictEqual(isBoolean(realm.boolean), true); - } - }); -}); diff --git a/test/isBuffer.spec.ts b/test/isBuffer.spec.ts new file mode 100644 index 000000000..41cd3a60c --- /dev/null +++ b/test/isBuffer.spec.ts @@ -0,0 +1,41 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubFalse, args, slice, symbol, isStrict, lodashBizarro } from './utils'; +import isBuffer from '../src/isBuffer'; + +describe('isBuffer', () => { + it('should return `true` for buffers', () => { + if (Buffer) { + assert.equal(`${isBuffer}`, ''); + assert.strictEqual(isBuffer(Buffer.alloc(2)), true); + } + }); + + it('should return `false` for non-buffers', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value: false, index: number) => + index ? isBuffer(value) : isBuffer(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isBuffer(args), false); + assert.strictEqual(isBuffer([1]), false); + assert.strictEqual(isBuffer(true), false); + assert.strictEqual(isBuffer(new Date()), false); + assert.strictEqual(isBuffer(new Error()), false); + assert.strictEqual(isBuffer(slice), false); + assert.strictEqual(isBuffer({ a: 1 }), false); + assert.strictEqual(isBuffer(1), false); + assert.strictEqual(isBuffer(/x/), false); + assert.strictEqual(isBuffer('a'), false); + assert.strictEqual(isBuffer(symbol), false); + }); + + it('should return `false` if `Buffer` is not defined', () => { + if (!isStrict && Buffer && lodashBizarro) { + assert.strictEqual(lodashBizarro.isBuffer(Buffer.alloc(2)), false); + } + }); +}); diff --git a/test/isBuffer.test.js b/test/isBuffer.test.js deleted file mode 100644 index a81af76f8..000000000 --- a/test/isBuffer.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubFalse, args, slice, symbol, isStrict, lodashBizarro } from './utils.js'; -import isBuffer from '../isBuffer.js'; - -describe('isBuffer', function() { - it('should return `true` for buffers', function() { - if (Buffer) { - assert.strictEqual(isBuffer(new Buffer(2)), true); - } - }); - - it('should return `false` for non-buffers', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isBuffer(value) : isBuffer(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isBuffer(args), false); - assert.strictEqual(isBuffer([1]), false); - assert.strictEqual(isBuffer(true), false); - assert.strictEqual(isBuffer(new Date), false); - assert.strictEqual(isBuffer(new Error), false); - assert.strictEqual(isBuffer(_), false); - assert.strictEqual(isBuffer(slice), false); - assert.strictEqual(isBuffer({ 'a': 1 }), false); - assert.strictEqual(isBuffer(1), false); - assert.strictEqual(isBuffer(/x/), false); - assert.strictEqual(isBuffer('a'), false); - assert.strictEqual(isBuffer(symbol), false); - }); - - it('should return `false` if `Buffer` is not defined', function() { - if (!isStrict && Buffer && lodashBizarro) { - assert.strictEqual(lodashBizarro.isBuffer(new Buffer(2)), false); - } - }); -}); diff --git a/test/isDate.spec.ts b/test/isDate.spec.ts new file mode 100644 index 000000000..0e5bc3da9 --- /dev/null +++ b/test/isDate.spec.ts @@ -0,0 +1,37 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubFalse, args, slice, symbol, realm } from './utils'; +import isDate from '../src/isDate'; + +describe('isDate', () => { + it('should return `true` for dates', () => { + assert.strictEqual(isDate(new Date()), true); + }); + + it('should return `false` for non-dates', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isDate(value) : isDate(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isDate(args), false); + assert.strictEqual(isDate([1, 2, 3]), false); + assert.strictEqual(isDate(true), false); + assert.strictEqual(isDate(new Error()), false); + assert.strictEqual(isDate(slice), false); + assert.strictEqual(isDate({ a: 1 }), false); + assert.strictEqual(isDate(1), false); + assert.strictEqual(isDate(/x/), false); + assert.strictEqual(isDate('a'), false); + assert.strictEqual(isDate(symbol), false); + }); + + it('should work with a date object from another realm', () => { + if (realm.date) { + assert.strictEqual(isDate(realm.date), true); + } + }); +}); diff --git a/test/isDate.test.js b/test/isDate.test.js deleted file mode 100644 index 8da8064c2..000000000 --- a/test/isDate.test.js +++ /dev/null @@ -1,38 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubFalse, args, slice, symbol, realm } from './utils.js'; -import isDate from '../isDate.js'; - -describe('isDate', function() { - it('should return `true` for dates', function() { - assert.strictEqual(isDate(new Date), true); - }); - - it('should return `false` for non-dates', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isDate(value) : isDate(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isDate(args), false); - assert.strictEqual(isDate([1, 2, 3]), false); - assert.strictEqual(isDate(true), false); - assert.strictEqual(isDate(new Error), false); - assert.strictEqual(isDate(_), false); - assert.strictEqual(isDate(slice), false); - assert.strictEqual(isDate({ 'a': 1 }), false); - assert.strictEqual(isDate(1), false); - assert.strictEqual(isDate(/x/), false); - assert.strictEqual(isDate('a'), false); - assert.strictEqual(isDate(symbol), false); - }); - - it('should work with a date object from another realm', function() { - if (realm.date) { - assert.strictEqual(isDate(realm.date), true); - } - }); -}); diff --git a/test/isElement.spec.ts b/test/isElement.spec.ts new file mode 100644 index 000000000..22761911c --- /dev/null +++ b/test/isElement.spec.ts @@ -0,0 +1,57 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { document, body, falsey, stubFalse, args, slice, symbol, realm } from './utils'; +import isElement from '../src/isElement'; + +describe('isElement', () => { + it('should return `true` for elements', () => { + if (document) { + assert.strictEqual(isElement(body), true); + } + }); + + it('should return `true` for non-plain objects', () => { + function Foo() { + this.nodeType = 1; + } + + assert.strictEqual(isElement(new Foo()), true); + }); + + it('should return `false` for non DOM elements', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isElement(value) : isElement(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isElement(args), false); + assert.strictEqual(isElement([1, 2, 3]), false); + assert.strictEqual(isElement(true), false); + assert.strictEqual(isElement(new Date()), false); + assert.strictEqual(isElement(new Error()), false); + assert.strictEqual(isElement(slice), false); + assert.strictEqual(isElement({ a: 1 }), false); + assert.strictEqual(isElement(1), false); + assert.strictEqual(isElement(/x/), false); + assert.strictEqual(isElement('a'), false); + assert.strictEqual(isElement(symbol), false); + }); + + it('should return `false` for plain objects', () => { + assert.strictEqual(isElement({ nodeType: 1 }), false); + assert.strictEqual(isElement({ nodeType: Object(1) }), false); + assert.strictEqual(isElement({ nodeType: true }), false); + assert.strictEqual(isElement({ nodeType: [1] }), false); + assert.strictEqual(isElement({ nodeType: '1' }), false); + assert.strictEqual(isElement({ nodeType: '001' }), false); + }); + + it('should work with a DOM element from another realm', () => { + if (realm.element) { + assert.strictEqual(isElement(realm.element), true); + } + }); +}); diff --git a/test/isElement.test.js b/test/isElement.test.js deleted file mode 100644 index c5e8833d7..000000000 --- a/test/isElement.test.js +++ /dev/null @@ -1,58 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { document, body, falsey, stubFalse, args, slice, symbol, realm } from './utils.js'; -import isElement from '../isElement.js'; - -describe('isElement', function() { - it('should return `true` for elements', function() { - if (document) { - assert.strictEqual(isElement(body), true); - } - }); - - it('should return `true` for non-plain objects', function() { - function Foo() { - this.nodeType = 1; - } - - assert.strictEqual(isElement(new Foo), true); - }); - - it('should return `false` for non DOM elements', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isElement(value) : isElement(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isElement(args), false); - assert.strictEqual(isElement([1, 2, 3]), false); - assert.strictEqual(isElement(true), false); - assert.strictEqual(isElement(new Date), false); - assert.strictEqual(isElement(new Error), false); - assert.strictEqual(isElement(_), false); - assert.strictEqual(isElement(slice), false); - assert.strictEqual(isElement({ 'a': 1 }), false); - assert.strictEqual(isElement(1), false); - assert.strictEqual(isElement(/x/), false); - assert.strictEqual(isElement('a'), false); - assert.strictEqual(isElement(symbol), false); - }); - - it('should return `false` for plain objects', function() { - assert.strictEqual(isElement({ 'nodeType': 1 }), false); - assert.strictEqual(isElement({ 'nodeType': Object(1) }), false); - assert.strictEqual(isElement({ 'nodeType': true }), false); - assert.strictEqual(isElement({ 'nodeType': [1] }), false); - assert.strictEqual(isElement({ 'nodeType': '1' }), false); - assert.strictEqual(isElement({ 'nodeType': '001' }), false); - }); - - it('should work with a DOM element from another realm', function() { - if (realm.element) { - assert.strictEqual(isElement(realm.element), true); - } - }); -}); diff --git a/test/isEmpty.js b/test/isEmpty.js deleted file mode 100644 index 05c8770ab..000000000 --- a/test/isEmpty.js +++ /dev/null @@ -1,119 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - empties, - stubTrue, - slice, - symbol, - args, - push, - arrayProto, - realm, - MAX_SAFE_INTEGER, -} from './utils.js'; - -import isEmpty from '../isEmpty.js'; - -describe('isEmpty', function() { - it('should return `true` for empty values', function() { - var expected = lodashStable.map(empties, stubTrue), - actual = lodashStable.map(empties, isEmpty); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isEmpty(true), true); - assert.strictEqual(isEmpty(slice), true); - assert.strictEqual(isEmpty(1), true); - assert.strictEqual(isEmpty(NaN), true); - assert.strictEqual(isEmpty(/x/), true); - assert.strictEqual(isEmpty(symbol), true); - assert.strictEqual(isEmpty(), true); - - if (Buffer) { - assert.strictEqual(isEmpty(new Buffer(0)), true); - assert.strictEqual(isEmpty(new Buffer(1)), false); - } - }); - - it('should return `false` for non-empty values', function() { - assert.strictEqual(isEmpty([0]), false); - assert.strictEqual(isEmpty({ 'a': 0 }), false); - assert.strictEqual(isEmpty('a'), false); - }); - - it('should work with an object that has a `length` property', function() { - assert.strictEqual(isEmpty({ 'length': 0 }), false); - }); - - it('should work with `arguments` objects', function() { - assert.strictEqual(isEmpty(args), false); - }); - - it('should work with prototype objects', function() { - function Foo() {} - Foo.prototype = { 'constructor': Foo }; - - assert.strictEqual(isEmpty(Foo.prototype), true); - - Foo.prototype.a = 1; - assert.strictEqual(isEmpty(Foo.prototype), false); - }); - - it('should work with jQuery/MooTools DOM query collections', function() { - function Foo(elements) { - push.apply(this, elements); - } - Foo.prototype = { 'length': 0, 'splice': arrayProto.splice }; - - assert.strictEqual(isEmpty(new Foo([])), true); - }); - - it('should work with maps', function() { - if (Map) { - lodashStable.each([new Map, realm.map], function(map) { - assert.strictEqual(isEmpty(map), true); - map.set('a', 1); - assert.strictEqual(isEmpty(map), false); - map.clear(); - }); - } - }); - - it('should work with sets', function() { - if (Set) { - lodashStable.each([new Set, realm.set], function(set) { - assert.strictEqual(isEmpty(set), true); - set.add(1); - assert.strictEqual(isEmpty(set), false); - set.clear(); - }); - } - }); - - it('should not treat objects with negative lengths as array-like', function() { - function Foo() {} - Foo.prototype.length = -1; - - assert.strictEqual(isEmpty(new Foo), true); - }); - - it('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', function() { - function Foo() {} - Foo.prototype.length = MAX_SAFE_INTEGER + 1; - - assert.strictEqual(isEmpty(new Foo), true); - }); - - it('should not treat objects with non-number lengths as array-like', function() { - assert.strictEqual(isEmpty({ 'length': '0' }), false); - }); - - it('should return an unwrapped value when implicitly chaining', function() { - assert.strictEqual(_({}).isEmpty(), true); - }); - - it('should return a wrapped value when explicitly chaining', function() { - assert.ok(_({}).chain().isEmpty() instanceof _); - }); -}); diff --git a/test/isEmpty.spec.ts b/test/isEmpty.spec.ts new file mode 100644 index 000000000..ae7022809 --- /dev/null +++ b/test/isEmpty.spec.ts @@ -0,0 +1,119 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + empties, + stubTrue, + slice, + symbol, + args, + push, + arrayProto, + realm, + MAX_SAFE_INTEGER, +} from './utils'; + +import isEmpty from '../src/isEmpty'; + +describe('isEmpty', () => { + it('should return `true` for empty values', () => { + const expected = lodashStable.map(empties, stubTrue), + actual = lodashStable.map(empties, isEmpty); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isEmpty(true), true); + assert.strictEqual(isEmpty(slice), true); + assert.strictEqual(isEmpty(1), true); + assert.strictEqual(isEmpty(NaN), true); + assert.strictEqual(isEmpty(/x/), true); + assert.strictEqual(isEmpty(symbol), true); + assert.strictEqual(isEmpty(), true); + + if (Buffer) { + assert.strictEqual(isEmpty(new Buffer(0)), true); + assert.strictEqual(isEmpty(new Buffer(1)), false); + } + }); + + it('should return `false` for non-empty values', () => { + assert.strictEqual(isEmpty([0]), false); + assert.strictEqual(isEmpty({ a: 0 }), false); + assert.strictEqual(isEmpty('a'), false); + }); + + it('should work with an object that has a `length` property', () => { + assert.strictEqual(isEmpty({ length: 0 }), false); + }); + + it('should work with `arguments` objects', () => { + assert.strictEqual(isEmpty(args), false); + }); + + it('should work with prototype objects', () => { + function Foo() {} + Foo.prototype = { constructor: Foo }; + + assert.strictEqual(isEmpty(Foo.prototype), true); + + Foo.prototype.a = 1; + assert.strictEqual(isEmpty(Foo.prototype), false); + }); + + it('should work with jQuery/MooTools DOM query collections', () => { + function Foo(elements) { + push.apply(this, elements); + } + Foo.prototype = { length: 0, splice: arrayProto.splice }; + + assert.strictEqual(isEmpty(new Foo([])), true); + }); + + it('should work with maps', () => { + if (Map) { + lodashStable.each([new Map(), realm.map], (map) => { + assert.strictEqual(isEmpty(map), true); + map.set('a', 1); + assert.strictEqual(isEmpty(map), false); + map.clear(); + }); + } + }); + + it('should work with sets', () => { + if (Set) { + lodashStable.each([new Set(), realm.set], (set) => { + assert.strictEqual(isEmpty(set), true); + set.add(1); + assert.strictEqual(isEmpty(set), false); + set.clear(); + }); + } + }); + + it('should not treat objects with negative lengths as array-like', () => { + function Foo() {} + Foo.prototype.length = -1; + + assert.strictEqual(isEmpty(new Foo()), true); + }); + + it('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', () => { + function Foo() {} + Foo.prototype.length = MAX_SAFE_INTEGER + 1; + + assert.strictEqual(isEmpty(new Foo()), true); + }); + + it('should not treat objects with non-number lengths as array-like', () => { + assert.strictEqual(isEmpty({ length: '0' }), false); + }); + + it('should return an unwrapped value when implicitly chaining', () => { + assert.strictEqual(_({}).isEmpty(), true); + }); + + it('should return a wrapped value when explicitly chaining', () => { + assert.ok(_({}).chain().isEmpty() instanceof _); + }); +}); diff --git a/test/isEqual.js b/test/isEqual.js deleted file mode 100644 index 66056d7e5..000000000 --- a/test/isEqual.js +++ /dev/null @@ -1,700 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - noop, - create, - args, - realm, - arrayViews, - map, - promise, - set, - defineProperty, - document, - stubFalse, -} from './utils.js'; - -import isEqual from '../isEqual.js'; - -describe('isEqual', function() { - var symbol1 = Symbol ? Symbol('a') : true, - symbol2 = Symbol ? Symbol('b') : false; - - it('should compare primitives', function() { - var pairs = [ - [1, 1, true], [1, Object(1), true], [1, '1', false], [1, 2, false], - [-0, -0, true], [0, 0, true], [0, Object(0), true], [Object(0), Object(0), true], [-0, 0, true], [0, '0', false], [0, null, false], - [NaN, NaN, true], [NaN, Object(NaN), true], [Object(NaN), Object(NaN), true], [NaN, 'a', false], [NaN, Infinity, false], - ['a', 'a', true], ['a', Object('a'), true], [Object('a'), Object('a'), true], ['a', 'b', false], ['a', ['a'], false], - [true, true, true], [true, Object(true), true], [Object(true), Object(true), true], [true, 1, false], [true, 'a', false], - [false, false, true], [false, Object(false), true], [Object(false), Object(false), true], [false, 0, false], [false, '', false], - [symbol1, symbol1, true], [symbol1, Object(symbol1), true], [Object(symbol1), Object(symbol1), true], [symbol1, symbol2, false], - [null, null, true], [null, undefined, false], [null, {}, false], [null, '', false], - [undefined, undefined, true], [undefined, null, false], [undefined, '', false] - ]; - - var expected = lodashStable.map(pairs, function(pair) { - return pair[2]; - }); - - var actual = lodashStable.map(pairs, function(pair) { - return isEqual(pair[0], pair[1]); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should compare arrays', function() { - var array1 = [true, null, 1, 'a', undefined], - array2 = [true, null, 1, 'a', undefined]; - - assert.strictEqual(isEqual(array1, array2), true); - - array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; - array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; - - assert.strictEqual(isEqual(array1, array2), true); - - array1 = [1]; - array1[2] = 3; - - array2 = [1]; - array2[1] = undefined; - array2[2] = 3; - - assert.strictEqual(isEqual(array1, array2), true); - - array1 = [Object(1), false, Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [Object('c')]], { 'a': 1 }]; - array2 = [1, Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', Object('b'), ['c']], { 'a': 1 }]; - - assert.strictEqual(isEqual(array1, array2), true); - - array1 = [1, 2, 3]; - array2 = [3, 2, 1]; - - assert.strictEqual(isEqual(array1, array2), false); - - array1 = [1, 2]; - array2 = [1, 2, 3]; - - assert.strictEqual(isEqual(array1, array2), false); - }); - - it('should treat arrays with identical values but different non-index properties as equal', function() { - var array1 = [1, 2, 3], - array2 = [1, 2, 3]; - - array1.every = array1.filter = array1.forEach = - array1.indexOf = array1.lastIndexOf = array1.map = - array1.some = array1.reduce = array1.reduceRight = null; - - array2.concat = array2.join = array2.pop = - array2.reverse = array2.shift = array2.slice = - array2.sort = array2.splice = array2.unshift = null; - - assert.strictEqual(isEqual(array1, array2), true); - - array1 = [1, 2, 3]; - array1.a = 1; - - array2 = [1, 2, 3]; - array2.b = 1; - - assert.strictEqual(isEqual(array1, array2), true); - - array1 = /c/.exec('abcde'); - array2 = ['c']; - - assert.strictEqual(isEqual(array1, array2), true); - }); - - it('should compare sparse arrays', function() { - var array = Array(1); - - assert.strictEqual(isEqual(array, Array(1)), true); - assert.strictEqual(isEqual(array, [undefined]), true); - assert.strictEqual(isEqual(array, Array(2)), false); - }); - - it('should compare plain objects', function() { - var object1 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }, - object2 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }; - - assert.strictEqual(isEqual(object1, object2), true); - - object1 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; - object2 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; - - assert.strictEqual(isEqual(object1, object2), true); - - object1 = { 'a': 1, 'b': 2, 'c': 3 }; - object2 = { 'a': 3, 'b': 2, 'c': 1 }; - - assert.strictEqual(isEqual(object1, object2), false); - - object1 = { 'a': 1, 'b': 2, 'c': 3 }; - object2 = { 'd': 1, 'e': 2, 'f': 3 }; - - assert.strictEqual(isEqual(object1, object2), false); - - object1 = { 'a': 1, 'b': 2 }; - object2 = { 'a': 1, 'b': 2, 'c': 3 }; - - assert.strictEqual(isEqual(object1, object2), false); - }); - - it('should compare objects regardless of key order', function() { - var object1 = { 'a': 1, 'b': 2, 'c': 3 }, - object2 = { 'c': 3, 'a': 1, 'b': 2 }; - - assert.strictEqual(isEqual(object1, object2), true); - }); - - it('should compare nested objects', function() { - var object1 = { - 'a': [1, 2, 3], - 'b': true, - 'c': Object(1), - 'd': 'a', - 'e': { - 'f': ['a', Object('b'), 'c'], - 'g': Object(false), - 'h': new Date(2012, 4, 23), - 'i': noop, - 'j': 'a' - } - }; - - var object2 = { - 'a': [1, Object(2), 3], - 'b': Object(true), - 'c': 1, - 'd': Object('a'), - 'e': { - 'f': ['a', 'b', 'c'], - 'g': false, - 'h': new Date(2012, 4, 23), - 'i': noop, - 'j': 'a' - } - }; - - assert.strictEqual(isEqual(object1, object2), true); - }); - - it('should compare object instances', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.a = 1; - - function Bar() { - this.a = 1; - } - Bar.prototype.a = 2; - - assert.strictEqual(isEqual(new Foo, new Foo), true); - assert.strictEqual(isEqual(new Foo, new Bar), false); - assert.strictEqual(isEqual({ 'a': 1 }, new Foo), false); - assert.strictEqual(isEqual({ 'a': 2 }, new Bar), false); - }); - - it('should compare objects with constructor properties', function() { - assert.strictEqual(isEqual({ 'constructor': 1 }, { 'constructor': 1 }), true); - assert.strictEqual(isEqual({ 'constructor': 1 }, { 'constructor': '1' }), false); - assert.strictEqual(isEqual({ 'constructor': [1] }, { 'constructor': [1] }), true); - assert.strictEqual(isEqual({ 'constructor': [1] }, { 'constructor': ['1'] }), false); - assert.strictEqual(isEqual({ 'constructor': Object }, {}), false); - }); - - it('should compare arrays with circular references', function() { - var array1 = [], - array2 = []; - - array1.push(array1); - array2.push(array2); - - assert.strictEqual(isEqual(array1, array2), true); - - array1.push('b'); - array2.push('b'); - - assert.strictEqual(isEqual(array1, array2), true); - - array1.push('c'); - array2.push('d'); - - assert.strictEqual(isEqual(array1, array2), false); - - array1 = ['a', 'b', 'c']; - array1[1] = array1; - array2 = ['a', ['a', 'b', 'c'], 'c']; - - assert.strictEqual(isEqual(array1, array2), false); - }); - - it('should have transitive equivalence for circular references of arrays', function() { - var array1 = [], - array2 = [array1], - array3 = [array2]; - - array1[0] = array1; - - assert.strictEqual(isEqual(array1, array2), true); - assert.strictEqual(isEqual(array2, array3), true); - assert.strictEqual(isEqual(array1, array3), true); - }); - - it('should compare objects with circular references', function() { - var object1 = {}, - object2 = {}; - - object1.a = object1; - object2.a = object2; - - assert.strictEqual(isEqual(object1, object2), true); - - object1.b = 0; - object2.b = Object(0); - - assert.strictEqual(isEqual(object1, object2), true); - - object1.c = Object(1); - object2.c = Object(2); - - assert.strictEqual(isEqual(object1, object2), false); - - object1 = { 'a': 1, 'b': 2, 'c': 3 }; - object1.b = object1; - object2 = { 'a': 1, 'b': { 'a': 1, 'b': 2, 'c': 3 }, 'c': 3 }; - - assert.strictEqual(isEqual(object1, object2), false); - }); - - it('should have transitive equivalence for circular references of objects', function() { - var object1 = {}, - object2 = { 'a': object1 }, - object3 = { 'a': object2 }; - - object1.a = object1; - - assert.strictEqual(isEqual(object1, object2), true); - assert.strictEqual(isEqual(object2, object3), true); - assert.strictEqual(isEqual(object1, object3), true); - }); - - it('should compare objects with multiple circular references', function() { - var array1 = [{}], - array2 = [{}]; - - (array1[0].a = array1).push(array1); - (array2[0].a = array2).push(array2); - - assert.strictEqual(isEqual(array1, array2), true); - - array1[0].b = 0; - array2[0].b = Object(0); - - assert.strictEqual(isEqual(array1, array2), true); - - array1[0].c = Object(1); - array2[0].c = Object(2); - - assert.strictEqual(isEqual(array1, array2), false); - }); - - it('should compare objects with complex circular references', function() { - var object1 = { - 'foo': { 'b': { 'c': { 'd': {} } } }, - 'bar': { 'a': 2 } - }; - - var object2 = { - 'foo': { 'b': { 'c': { 'd': {} } } }, - 'bar': { 'a': 2 } - }; - - object1.foo.b.c.d = object1; - object1.bar.b = object1.foo.b; - - object2.foo.b.c.d = object2; - object2.bar.b = object2.foo.b; - - assert.strictEqual(isEqual(object1, object2), true); - }); - - it('should compare objects with shared property values', function() { - var object1 = { - 'a': [1, 2] - }; - - var object2 = { - 'a': [1, 2], - 'b': [1, 2] - }; - - object1.b = object1.a; - - assert.strictEqual(isEqual(object1, object2), true); - }); - - it('should treat objects created by `Object.create(null)` like plain objects', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.constructor = null; - - var object1 = create(null); - object1.a = 1; - - var object2 = { 'a': 1 }; - - assert.strictEqual(isEqual(object1, object2), true); - assert.strictEqual(isEqual(new Foo, object2), false); - }); - - it('should avoid common type coercions', function() { - assert.strictEqual(isEqual(true, Object(false)), false); - assert.strictEqual(isEqual(Object(false), Object(0)), false); - assert.strictEqual(isEqual(false, Object('')), false); - assert.strictEqual(isEqual(Object(36), Object('36')), false); - assert.strictEqual(isEqual(0, ''), false); - assert.strictEqual(isEqual(1, true), false); - assert.strictEqual(isEqual(1337756400000, new Date(2012, 4, 23)), false); - assert.strictEqual(isEqual('36', 36), false); - assert.strictEqual(isEqual(36, '36'), false); - }); - - it('should compare `arguments` objects', function() { - var args1 = (function() { return arguments; }()), - args2 = (function() { return arguments; }()), - args3 = (function() { return arguments; }(1, 2)); - - assert.strictEqual(isEqual(args1, args2), true); - assert.strictEqual(isEqual(args1, args3), false); - }); - - it('should treat `arguments` objects like `Object` objects', function() { - var object = { '0': 1, '1': 2, '2': 3 }; - - function Foo() {} - Foo.prototype = object; - - assert.strictEqual(isEqual(args, object), true); - assert.strictEqual(isEqual(object, args), true); - assert.strictEqual(isEqual(args, new Foo), false); - assert.strictEqual(isEqual(new Foo, args), false); - }); - - it('should compare array buffers', function() { - if (ArrayBuffer) { - var buffer = new Int8Array([-1]).buffer; - - assert.strictEqual(isEqual(buffer, new Uint8Array([255]).buffer), true); - assert.strictEqual(isEqual(buffer, new ArrayBuffer(1)), false); - } - }); - - it('should compare array views', function() { - lodashStable.times(2, function(index) { - var ns = index ? realm : root; - - var pairs = lodashStable.map(arrayViews, function(type, viewIndex) { - var otherType = arrayViews[(viewIndex + 1) % arrayViews.length], - CtorA = ns[type] || function(n) { this.n = n; }, - CtorB = ns[otherType] || function(n) { this.n = n; }, - bufferA = ns[type] ? new ns.ArrayBuffer(8) : 8, - bufferB = ns[otherType] ? new ns.ArrayBuffer(8) : 8, - bufferC = ns[otherType] ? new ns.ArrayBuffer(16) : 16; - - return [new CtorA(bufferA), new CtorA(bufferA), new CtorB(bufferB), new CtorB(bufferC)]; - }); - - var expected = lodashStable.map(pairs, lodashStable.constant([true, false, false])); - - var actual = lodashStable.map(pairs, function(pair) { - return [isEqual(pair[0], pair[1]), isEqual(pair[0], pair[2]), isEqual(pair[2], pair[3])]; - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should compare buffers', function() { - if (Buffer) { - var buffer = new Buffer([1]); - - assert.strictEqual(isEqual(buffer, new Buffer([1])), true); - assert.strictEqual(isEqual(buffer, new Buffer([2])), false); - assert.strictEqual(isEqual(buffer, new Uint8Array([1])), false); - } - }); - - it('should compare date objects', function() { - var date = new Date(2012, 4, 23); - - assert.strictEqual(isEqual(date, new Date(2012, 4, 23)), true); - assert.strictEqual(isEqual(new Date('a'), new Date('b')), true); - assert.strictEqual(isEqual(date, new Date(2013, 3, 25)), false); - assert.strictEqual(isEqual(date, { 'getTime': lodashStable.constant(+date) }), false); - }); - - it('should compare error objects', function() { - var pairs = lodashStable.map([ - 'Error', - 'EvalError', - 'RangeError', - 'ReferenceError', - 'SyntaxError', - 'TypeError', - 'URIError' - ], function(type, index, errorTypes) { - var otherType = errorTypes[++index % errorTypes.length], - CtorA = root[type], - CtorB = root[otherType]; - - return [new CtorA('a'), new CtorA('a'), new CtorB('a'), new CtorB('b')]; - }); - - var expected = lodashStable.map(pairs, lodashStable.constant([true, false, false])); - - var actual = lodashStable.map(pairs, function(pair) { - return [isEqual(pair[0], pair[1]), isEqual(pair[0], pair[2]), isEqual(pair[2], pair[3])]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should compare functions', function() { - function a() { return 1 + 2; } - function b() { return 1 + 2; } - - assert.strictEqual(isEqual(a, a), true); - assert.strictEqual(isEqual(a, b), false); - }); - - it('should compare maps', function() { - if (Map) { - lodashStable.each([[map, new Map], [map, realm.map]], function(maps) { - var map1 = maps[0], - map2 = maps[1]; - - map1.set('a', 1); - map2.set('b', 2); - assert.strictEqual(isEqual(map1, map2), false); - - map1.set('b', 2); - map2.set('a', 1); - assert.strictEqual(isEqual(map1, map2), true); - - map1.delete('a'); - map1.set('a', 1); - assert.strictEqual(isEqual(map1, map2), true); - - map2.delete('a'); - assert.strictEqual(isEqual(map1, map2), false); - - map1.clear(); - map2.clear(); - }); - } - }); - - it('should compare maps with circular references', function() { - if (Map) { - var map1 = new Map, - map2 = new Map; - - map1.set('a', map1); - map2.set('a', map2); - assert.strictEqual(isEqual(map1, map2), true); - - map1.set('b', 1); - map2.set('b', 2); - assert.strictEqual(isEqual(map1, map2), false); - } - }); - - it('should compare promises by reference', function() { - if (promise) { - lodashStable.each([[promise, Promise.resolve(1)], [promise, realm.promise]], function(promises) { - var promise1 = promises[0], - promise2 = promises[1]; - - assert.strictEqual(isEqual(promise1, promise2), false); - assert.strictEqual(isEqual(promise1, promise1), true); - }); - } - }); - - it('should compare regexes', function() { - assert.strictEqual(isEqual(/x/gim, /x/gim), true); - assert.strictEqual(isEqual(/x/gim, /x/mgi), true); - assert.strictEqual(isEqual(/x/gi, /x/g), false); - assert.strictEqual(isEqual(/x/, /y/), false); - assert.strictEqual(isEqual(/x/g, { 'global': true, 'ignoreCase': false, 'multiline': false, 'source': 'x' }), false); - }); - - it('should compare sets', function() { - if (Set) { - lodashStable.each([[set, new Set], [set, realm.set]], function(sets) { - var set1 = sets[0], - set2 = sets[1]; - - set1.add(1); - set2.add(2); - assert.strictEqual(isEqual(set1, set2), false); - - set1.add(2); - set2.add(1); - assert.strictEqual(isEqual(set1, set2), true); - - set1.delete(1); - set1.add(1); - assert.strictEqual(isEqual(set1, set2), true); - - set2.delete(1); - assert.strictEqual(isEqual(set1, set2), false); - - set1.clear(); - set2.clear(); - }); - } - }); - - it('should compare sets with circular references', function() { - if (Set) { - var set1 = new Set, - set2 = new Set; - - set1.add(set1); - set2.add(set2); - assert.strictEqual(isEqual(set1, set2), true); - - set1.add(1); - set2.add(2); - assert.strictEqual(isEqual(set1, set2), false); - } - }); - - it('should compare symbol properties', function() { - if (Symbol) { - var object1 = { 'a': 1 }, - object2 = { 'a': 1 }; - - object1[symbol1] = { 'a': { 'b': 2 } }; - object2[symbol1] = { 'a': { 'b': 2 } }; - - defineProperty(object2, symbol2, { - 'configurable': true, - 'enumerable': false, - 'writable': true, - 'value': 2 - }); - - assert.strictEqual(isEqual(object1, object2), true); - - object2[symbol1] = { 'a': 1 }; - assert.strictEqual(isEqual(object1, object2), false); - - delete object2[symbol1]; - object2[Symbol('a')] = { 'a': { 'b': 2 } }; - assert.strictEqual(isEqual(object1, object2), false); - } - }); - - it('should compare wrapped values', function() { - var stamp = +new Date; - - var values = [ - [[1, 2], [1, 2], [1, 2, 3]], - [true, true, false], - [new Date(stamp), new Date(stamp), new Date(stamp - 100)], - [{ 'a': 1, 'b': 2 }, { 'a': 1, 'b': 2 }, { 'a': 1, 'b': 1 }], - [1, 1, 2], - [NaN, NaN, Infinity], - [/x/, /x/, /x/i], - ['a', 'a', 'A'] - ]; - - lodashStable.each(values, function(vals) { - var wrapped1 = _(vals[0]), - wrapped2 = _(vals[1]), - actual = wrapped1.isEqual(wrapped2); - - assert.strictEqual(actual, true); - assert.strictEqual(isEqual(_(actual), _(true)), true); - - wrapped1 = _(vals[0]); - wrapped2 = _(vals[2]); - - actual = wrapped1.isEqual(wrapped2); - assert.strictEqual(actual, false); - assert.strictEqual(isEqual(_(actual), _(false)), true); - }); - }); - - it('should compare wrapped and non-wrapped values', function() { - var object1 = _({ 'a': 1, 'b': 2 }), - object2 = { 'a': 1, 'b': 2 }; - - assert.strictEqual(object1.isEqual(object2), true); - assert.strictEqual(isEqual(object1, object2), true); - - object1 = _({ 'a': 1, 'b': 2 }); - object2 = { 'a': 1, 'b': 1 }; - - assert.strictEqual(object1.isEqual(object2), false); - assert.strictEqual(isEqual(object1, object2), false); - }); - - it('should work as an iteratee for `_.every`', function() { - var actual = lodashStable.every([1, 1, 1], lodashStable.partial(isEqual, 1)); - assert.ok(actual); - }); - - it('should not error on DOM elements', function() { - if (document) { - var element1 = document.createElement('div'), - element2 = element1.cloneNode(true); - - try { - assert.strictEqual(isEqual(element1, element2), false); - } catch (e) { - assert.ok(false, e.message); - } - } - }); - - it('should return `true` for like-objects from different documents', function() { - if (realm.object) { - assert.strictEqual(isEqual([1], realm.array), true); - assert.strictEqual(isEqual([2], realm.array), false); - assert.strictEqual(isEqual({ 'a': 1 }, realm.object), true); - assert.strictEqual(isEqual({ 'a': 2 }, realm.object), false); - } - }); - - it('should return `false` for objects with custom `toString` methods', function() { - var primitive, - object = { 'toString': function() { return primitive; } }, - values = [true, null, 1, 'a', undefined], - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value) { - primitive = value; - return isEqual(object, value); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return an unwrapped value when implicitly chaining', function() { - assert.strictEqual(_('a').isEqual('a'), true); - }); - - it('should return a wrapped value when explicitly chaining', function() { - assert.ok(_('a').chain().isEqual('a') instanceof _); - }); -}); diff --git a/test/isEqual.spec.ts b/test/isEqual.spec.ts new file mode 100644 index 000000000..c04e98818 --- /dev/null +++ b/test/isEqual.spec.ts @@ -0,0 +1,822 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + noop, + create, + args, + realm, + arrayViews, + map, + promise, + set, + defineProperty, + document, + stubFalse, +} from './utils'; + +import isEqual from '../src/isEqual'; + +describe('isEqual', () => { + const symbol1 = Symbol ? Symbol('a') : true, + symbol2 = Symbol ? Symbol('b') : false; + + it('should compare primitives', () => { + const pairs = [ + [1, 1, true], + [1, Object(1), true], + [1, '1', false], + [1, 2, false], + [-0, -0, true], + [0, 0, true], + [0, Object(0), true], + [Object(0), Object(0), true], + [-0, 0, true], + [0, '0', false], + [0, null, false], + [NaN, NaN, true], + [NaN, Object(NaN), true], + [Object(NaN), Object(NaN), true], + [NaN, 'a', false], + [NaN, Infinity, false], + ['a', 'a', true], + ['a', Object('a'), true], + [Object('a'), Object('a'), true], + ['a', 'b', false], + ['a', ['a'], false], + [true, true, true], + [true, Object(true), true], + [Object(true), Object(true), true], + [true, 1, false], + [true, 'a', false], + [false, false, true], + [false, Object(false), true], + [Object(false), Object(false), true], + [false, 0, false], + [false, '', false], + [symbol1, symbol1, true], + [symbol1, Object(symbol1), true], + [Object(symbol1), Object(symbol1), true], + [symbol1, symbol2, false], + [null, null, true], + [null, undefined, false], + [null, {}, false], + [null, '', false], + [undefined, undefined, true], + [undefined, null, false], + [undefined, '', false], + ]; + + const expected = lodashStable.map(pairs, (pair) => pair[2]); + + const actual = lodashStable.map(pairs, (pair) => isEqual(pair[0], pair[1])); + + assert.deepStrictEqual(actual, expected); + }); + + it('should compare arrays', () => { + let array1 = [true, null, 1, 'a', undefined], + array2 = [true, null, 1, 'a', undefined]; + + assert.strictEqual(isEqual(array1, array2), true); + + array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { e: 1 }]; + array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { e: 1 }]; + + assert.strictEqual(isEqual(array1, array2), true); + + array1 = [1]; + array1[2] = 3; + + array2 = [1]; + array2[1] = undefined; + array2[2] = 3; + + assert.strictEqual(isEqual(array1, array2), true); + + array1 = [ + Object(1), + false, + Object('a'), + /x/, + new Date(2012, 4, 23), + ['a', 'b', [Object('c')]], + { a: 1 }, + ]; + array2 = [ + 1, + Object(false), + 'a', + /x/, + new Date(2012, 4, 23), + ['a', Object('b'), ['c']], + { a: 1 }, + ]; + + assert.strictEqual(isEqual(array1, array2), true); + + array1 = [1, 2, 3]; + array2 = [3, 2, 1]; + + assert.strictEqual(isEqual(array1, array2), false); + + array1 = [1, 2]; + array2 = [1, 2, 3]; + + assert.strictEqual(isEqual(array1, array2), false); + }); + + it('should treat arrays with identical values but different non-index properties as equal', () => { + let array1 = [1, 2, 3], + array2 = [1, 2, 3]; + + array1.every = + array1.filter = + array1.forEach = + array1.indexOf = + array1.lastIndexOf = + array1.map = + array1.some = + array1.reduce = + array1.reduceRight = + null; + + array2.concat = + array2.join = + array2.pop = + array2.reverse = + array2.shift = + array2.slice = + array2.sort = + array2.splice = + array2.unshift = + null; + + assert.strictEqual(isEqual(array1, array2), true); + + array1 = [1, 2, 3]; + array1.a = 1; + + array2 = [1, 2, 3]; + array2.b = 1; + + assert.strictEqual(isEqual(array1, array2), true); + + array1 = /c/.exec('abcde'); + array2 = ['c']; + + assert.strictEqual(isEqual(array1, array2), true); + }); + + it('should compare sparse arrays', () => { + const array = Array(1); + + assert.strictEqual(isEqual(array, Array(1)), true); + assert.strictEqual(isEqual(array, [undefined]), true); + assert.strictEqual(isEqual(array, Array(2)), false); + }); + + it('should compare plain objects', () => { + let object1 = { a: true, b: null, c: 1, d: 'a', e: undefined }, + object2 = { a: true, b: null, c: 1, d: 'a', e: undefined }; + + assert.strictEqual(isEqual(object1, object2), true); + + object1 = { a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: { e: 1 } }; + object2 = { a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: { e: 1 } }; + + assert.strictEqual(isEqual(object1, object2), true); + + object1 = { a: 1, b: 2, c: 3 }; + object2 = { a: 3, b: 2, c: 1 }; + + assert.strictEqual(isEqual(object1, object2), false); + + object1 = { a: 1, b: 2, c: 3 }; + object2 = { d: 1, e: 2, f: 3 }; + + assert.strictEqual(isEqual(object1, object2), false); + + object1 = { a: 1, b: 2 }; + object2 = { a: 1, b: 2, c: 3 }; + + assert.strictEqual(isEqual(object1, object2), false); + }); + + it('should compare objects regardless of key order', () => { + const object1 = { a: 1, b: 2, c: 3 }, + object2 = { c: 3, a: 1, b: 2 }; + + assert.strictEqual(isEqual(object1, object2), true); + }); + + it('should compare nested objects', () => { + const object1 = { + a: [1, 2, 3], + b: true, + c: Object(1), + d: 'a', + e: { + f: ['a', Object('b'), 'c'], + g: Object(false), + h: new Date(2012, 4, 23), + i: noop, + j: 'a', + }, + }; + + const object2 = { + a: [1, Object(2), 3], + b: Object(true), + c: 1, + d: Object('a'), + e: { + f: ['a', 'b', 'c'], + g: false, + h: new Date(2012, 4, 23), + i: noop, + j: 'a', + }, + }; + + assert.strictEqual(isEqual(object1, object2), true); + }); + + it('should compare object instances', () => { + function Foo() { + this.a = 1; + } + Foo.prototype.a = 1; + + function Bar() { + this.a = 1; + } + Bar.prototype.a = 2; + + assert.strictEqual(isEqual(new Foo(), new Foo()), true); + assert.strictEqual(isEqual(new Foo(), new Bar()), false); + assert.strictEqual(isEqual({ a: 1 }, new Foo()), false); + assert.strictEqual(isEqual({ a: 2 }, new Bar()), false); + }); + + it('should compare objects with constructor properties', () => { + assert.strictEqual(isEqual({ constructor: 1 }, { constructor: 1 }), true); + assert.strictEqual(isEqual({ constructor: 1 }, { constructor: '1' }), false); + assert.strictEqual(isEqual({ constructor: [1] }, { constructor: [1] }), true); + assert.strictEqual(isEqual({ constructor: [1] }, { constructor: ['1'] }), false); + assert.strictEqual(isEqual({ constructor: Object }, {}), false); + }); + + it('should compare arrays with circular references', () => { + let array1 = [], + array2 = []; + + array1.push(array1); + array2.push(array2); + + assert.strictEqual(isEqual(array1, array2), true); + + array1.push('b'); + array2.push('b'); + + assert.strictEqual(isEqual(array1, array2), true); + + array1.push('c'); + array2.push('d'); + + assert.strictEqual(isEqual(array1, array2), false); + + array1 = ['a', 'b', 'c']; + array1[1] = array1; + array2 = ['a', ['a', 'b', 'c'], 'c']; + + assert.strictEqual(isEqual(array1, array2), false); + }); + + it('should have transitive equivalence for circular references of arrays', () => { + const array1 = [], + array2 = [array1], + array3 = [array2]; + + array1[0] = array1; + + assert.strictEqual(isEqual(array1, array2), true); + assert.strictEqual(isEqual(array2, array3), true); + assert.strictEqual(isEqual(array1, array3), true); + }); + + it('should compare objects with circular references', () => { + let object1 = {}, + object2 = {}; + + object1.a = object1; + object2.a = object2; + + assert.strictEqual(isEqual(object1, object2), true); + + object1.b = 0; + object2.b = Object(0); + + assert.strictEqual(isEqual(object1, object2), true); + + object1.c = Object(1); + object2.c = Object(2); + + assert.strictEqual(isEqual(object1, object2), false); + + object1 = { a: 1, b: 2, c: 3 }; + object1.b = object1; + object2 = { a: 1, b: { a: 1, b: 2, c: 3 }, c: 3 }; + + assert.strictEqual(isEqual(object1, object2), false); + }); + + it('should have transitive equivalence for circular references of objects', () => { + const object1 = {}, + object2 = { a: object1 }, + object3 = { a: object2 }; + + object1.a = object1; + + assert.strictEqual(isEqual(object1, object2), true); + assert.strictEqual(isEqual(object2, object3), true); + assert.strictEqual(isEqual(object1, object3), true); + }); + + it('should compare objects with multiple circular references', () => { + const array1 = [{}], + array2 = [{}]; + + (array1[0].a = array1).push(array1); + (array2[0].a = array2).push(array2); + + assert.strictEqual(isEqual(array1, array2), true); + + array1[0].b = 0; + array2[0].b = Object(0); + + assert.strictEqual(isEqual(array1, array2), true); + + array1[0].c = Object(1); + array2[0].c = Object(2); + + assert.strictEqual(isEqual(array1, array2), false); + }); + + it('should compare objects with complex circular references', () => { + const object1 = { + foo: { b: { c: { d: {} } } }, + bar: { a: 2 }, + }; + + const object2 = { + foo: { b: { c: { d: {} } } }, + bar: { a: 2 }, + }; + + object1.foo.b.c.d = object1; + object1.bar.b = object1.foo.b; + + object2.foo.b.c.d = object2; + object2.bar.b = object2.foo.b; + + assert.strictEqual(isEqual(object1, object2), true); + }); + + it('should compare objects with shared property values', () => { + const object1 = { + a: [1, 2], + }; + + const object2 = { + a: [1, 2], + b: [1, 2], + }; + + object1.b = object1.a; + + assert.strictEqual(isEqual(object1, object2), true); + }); + + it('should treat objects created by `Object.create(null)` like plain objects', () => { + function Foo() { + this.a = 1; + } + Foo.prototype.constructor = null; + + const object1 = create(null); + object1.a = 1; + + const object2 = { a: 1 }; + + assert.strictEqual(isEqual(object1, object2), true); + assert.strictEqual(isEqual(new Foo(), object2), false); + }); + + it('should avoid common type coercions', () => { + assert.strictEqual(isEqual(true, Object(false)), false); + assert.strictEqual(isEqual(Object(false), Object(0)), false); + assert.strictEqual(isEqual(false, Object('')), false); + assert.strictEqual(isEqual(Object(36), Object('36')), false); + assert.strictEqual(isEqual(0, ''), false); + assert.strictEqual(isEqual(1, true), false); + assert.strictEqual(isEqual(1337756400000, new Date(2012, 4, 23)), false); + assert.strictEqual(isEqual('36', 36), false); + assert.strictEqual(isEqual(36, '36'), false); + }); + + it('should compare `arguments` objects', () => { + const args1 = (function () { + return arguments; + })(), + args2 = (function () { + return arguments; + })(), + args3 = (function () { + return arguments; + })(1, 2); + + assert.strictEqual(isEqual(args1, args2), true); + assert.strictEqual(isEqual(args1, args3), false); + }); + + it('should treat `arguments` objects like `Object` objects', () => { + const object = { '0': 1, '1': 2, '2': 3 }; + + function Foo() {} + Foo.prototype = object; + + assert.strictEqual(isEqual(args, object), true); + assert.strictEqual(isEqual(object, args), true); + assert.strictEqual(isEqual(args, new Foo()), false); + assert.strictEqual(isEqual(new Foo(), args), false); + }); + + it('should compare array buffers', () => { + if (ArrayBuffer) { + const buffer = new Int8Array([-1]).buffer; + + assert.strictEqual(isEqual(buffer, new Uint8Array([255]).buffer), true); + assert.strictEqual(isEqual(buffer, new ArrayBuffer(1)), false); + } + }); + + it('should compare array views', () => { + lodashStable.times(2, (index) => { + const ns = index ? realm : root; + + const pairs = lodashStable.map(arrayViews, (type, viewIndex) => { + const otherType = arrayViews[(viewIndex + 1) % arrayViews.length], + CtorA = + ns[type] || + function (n) { + this.n = n; + }, + CtorB = + ns[otherType] || + function (n) { + this.n = n; + }, + bufferA = ns[type] ? new ns.ArrayBuffer(8) : 8, + bufferB = ns[otherType] ? new ns.ArrayBuffer(8) : 8, + bufferC = ns[otherType] ? new ns.ArrayBuffer(16) : 16; + + return [ + new CtorA(bufferA), + new CtorA(bufferA), + new CtorB(bufferB), + new CtorB(bufferC), + ]; + }); + + const expected = lodashStable.map(pairs, lodashStable.constant([true, false, false])); + + const actual = lodashStable.map(pairs, (pair) => [ + isEqual(pair[0], pair[1]), + isEqual(pair[0], pair[2]), + isEqual(pair[2], pair[3]), + ]); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should compare buffers', () => { + if (Buffer) { + const buffer = new Buffer([1]); + + assert.strictEqual(isEqual(buffer, new Buffer([1])), true); + assert.strictEqual(isEqual(buffer, new Buffer([2])), false); + assert.strictEqual(isEqual(buffer, new Uint8Array([1])), false); + } + }); + + it('should compare date objects', () => { + const date = new Date(2012, 4, 23); + + assert.strictEqual(isEqual(date, new Date(2012, 4, 23)), true); + assert.strictEqual(isEqual(new Date('a'), new Date('b')), true); + assert.strictEqual(isEqual(date, new Date(2013, 3, 25)), false); + assert.strictEqual(isEqual(date, { getTime: lodashStable.constant(+date) }), false); + }); + + it('should compare error objects', () => { + const pairs = lodashStable.map( + [ + 'Error', + 'EvalError', + 'RangeError', + 'ReferenceError', + 'SyntaxError', + 'TypeError', + 'URIError', + ], + (type, index, errorTypes) => { + const otherType = errorTypes[++index % errorTypes.length], + CtorA = root[type], + CtorB = root[otherType]; + + return [new CtorA('a'), new CtorA('a'), new CtorB('a'), new CtorB('b')]; + }, + ); + + const expected = lodashStable.map(pairs, lodashStable.constant([true, false, false])); + + const actual = lodashStable.map(pairs, (pair) => [ + isEqual(pair[0], pair[1]), + isEqual(pair[0], pair[2]), + isEqual(pair[2], pair[3]), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it('should compare functions', () => { + function a() { + return 1 + 2; + } + function b() { + return 1 + 2; + } + + assert.strictEqual(isEqual(a, a), true); + assert.strictEqual(isEqual(a, b), false); + }); + + it('should compare maps', () => { + if (Map) { + lodashStable.each( + [ + [map, new Map()], + [map, realm.map], + ], + (maps) => { + const map1 = maps[0], + map2 = maps[1]; + + map1.set('a', 1); + map2.set('b', 2); + assert.strictEqual(isEqual(map1, map2), false); + + map1.set('b', 2); + map2.set('a', 1); + assert.strictEqual(isEqual(map1, map2), true); + + map1.delete('a'); + map1.set('a', 1); + assert.strictEqual(isEqual(map1, map2), true); + + map2.delete('a'); + assert.strictEqual(isEqual(map1, map2), false); + + map1.clear(); + map2.clear(); + }, + ); + } + }); + + it('should compare maps with circular references', () => { + if (Map) { + const map1 = new Map(), + map2 = new Map(); + + map1.set('a', map1); + map2.set('a', map2); + assert.strictEqual(isEqual(map1, map2), true); + + map1.set('b', 1); + map2.set('b', 2); + assert.strictEqual(isEqual(map1, map2), false); + } + }); + + it('should compare promises by reference', () => { + if (promise) { + lodashStable.each( + [ + [promise, Promise.resolve(1)], + [promise, realm.promise], + ], + (promises) => { + const promise1 = promises[0], + promise2 = promises[1]; + + assert.strictEqual(isEqual(promise1, promise2), false); + assert.strictEqual(isEqual(promise1, promise1), true); + }, + ); + } + }); + + it('should compare regexes', () => { + assert.strictEqual(isEqual(/x/gim, /x/gim), true); + assert.strictEqual(isEqual(/x/gim, /x/gim), true); + assert.strictEqual(isEqual(/x/gi, /x/g), false); + assert.strictEqual(isEqual(/x/, /y/), false); + assert.strictEqual( + isEqual(/x/g, { global: true, ignoreCase: false, multiline: false, source: 'x' }), + false, + ); + }); + + it('should compare sets', () => { + if (Set) { + lodashStable.each( + [ + [set, new Set()], + [set, realm.set], + ], + (sets) => { + const set1 = sets[0], + set2 = sets[1]; + + set1.add(1); + set2.add(2); + assert.strictEqual(isEqual(set1, set2), false); + + set1.add(2); + set2.add(1); + assert.strictEqual(isEqual(set1, set2), true); + + set1.delete(1); + set1.add(1); + assert.strictEqual(isEqual(set1, set2), true); + + set2.delete(1); + assert.strictEqual(isEqual(set1, set2), false); + + set1.clear(); + set2.clear(); + }, + ); + } + }); + + it('should compare sets with circular references', () => { + if (Set) { + const set1 = new Set(), + set2 = new Set(); + + set1.add(set1); + set2.add(set2); + assert.strictEqual(isEqual(set1, set2), true); + + set1.add(1); + set2.add(2); + assert.strictEqual(isEqual(set1, set2), false); + } + }); + + it('should compare symbol properties', () => { + if (Symbol) { + const object1 = { a: 1 }, + object2 = { a: 1 }; + + object1[symbol1] = { a: { b: 2 } }; + object2[symbol1] = { a: { b: 2 } }; + + defineProperty(object2, symbol2, { + configurable: true, + enumerable: false, + writable: true, + value: 2, + }); + + assert.strictEqual(isEqual(object1, object2), true); + + object2[symbol1] = { a: 1 }; + assert.strictEqual(isEqual(object1, object2), false); + + delete object2[symbol1]; + object2[Symbol('a')] = { a: { b: 2 } }; + assert.strictEqual(isEqual(object1, object2), false); + } + }); + + it('should compare wrapped values', () => { + const stamp = +new Date(); + + const values = [ + [ + [1, 2], + [1, 2], + [1, 2, 3], + ], + [true, true, false], + [new Date(stamp), new Date(stamp), new Date(stamp - 100)], + [ + { a: 1, b: 2 }, + { a: 1, b: 2 }, + { a: 1, b: 1 }, + ], + [1, 1, 2], + [NaN, NaN, Infinity], + [/x/, /x/, /x/i], + ['a', 'a', 'A'], + ]; + + lodashStable.each(values, (vals) => { + let wrapped1 = _(vals[0]), + wrapped2 = _(vals[1]), + actual = wrapped1.isEqual(wrapped2); + + assert.strictEqual(actual, true); + assert.strictEqual(isEqual(_(actual), _(true)), true); + + wrapped1 = _(vals[0]); + wrapped2 = _(vals[2]); + + actual = wrapped1.isEqual(wrapped2); + assert.strictEqual(actual, false); + assert.strictEqual(isEqual(_(actual), _(false)), true); + }); + }); + + it('should compare wrapped and non-wrapped values', () => { + let object1 = _({ a: 1, b: 2 }), + object2 = { a: 1, b: 2 }; + + assert.strictEqual(object1.isEqual(object2), true); + assert.strictEqual(isEqual(object1, object2), true); + + object1 = _({ a: 1, b: 2 }); + object2 = { a: 1, b: 1 }; + + assert.strictEqual(object1.isEqual(object2), false); + assert.strictEqual(isEqual(object1, object2), false); + }); + + it('should work as an iteratee for `_.every`', () => { + const actual = lodashStable.every([1, 1, 1], lodashStable.partial(isEqual, 1)); + assert.ok(actual); + }); + + it('should not error on DOM elements', () => { + if (document) { + const element1 = document.createElement('div'), + element2 = element1.cloneNode(true); + + try { + assert.strictEqual(isEqual(element1, element2), false); + } catch (e) { + assert.ok(false, e.message); + } + } + }); + + it('should return `true` for like-objects from different documents', () => { + if (realm.object) { + assert.strictEqual(isEqual([1], realm.array), true); + assert.strictEqual(isEqual([2], realm.array), false); + assert.strictEqual(isEqual({ a: 1 }, realm.object), true); + assert.strictEqual(isEqual({ a: 2 }, realm.object), false); + } + }); + + it('should return `false` for objects with custom `toString` methods', () => { + let primitive, + object = { + toString: function () { + return primitive; + }, + }, + values = [true, null, 1, 'a', undefined], + expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(values, (value) => { + primitive = value; + return isEqual(object, value); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return an unwrapped value when implicitly chaining', () => { + assert.strictEqual(_('a').isEqual('a'), true); + }); + + it('should return a wrapped value when explicitly chaining', () => { + assert.ok(_('a').chain().isEqual('a') instanceof _); + }); +}); diff --git a/test/isEqualWith.js b/test/isEqualWith.js deleted file mode 100644 index 312e3e485..000000000 --- a/test/isEqualWith.js +++ /dev/null @@ -1,128 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, noop, stubC, falsey, stubFalse } from './utils.js'; -import isEqualWith from '../isEqualWith.js'; -import isString from '../isString.js'; -import without from '../without.js'; -import partial from '../partial.js'; - -describe('isEqualWith', function() { - it('should provide correct `customizer` arguments', function() { - var argsList = [], - object1 = { 'a': [1, 2], 'b': null }, - object2 = { 'a': [1, 2], 'b': null }; - - object1.b = object2; - object2.b = object1; - - var expected = [ - [object1, object2], - [object1.a, object2.a, 'a', object1, object2], - [object1.a[0], object2.a[0], 0, object1.a, object2.a], - [object1.a[1], object2.a[1], 1, object1.a, object2.a], - [object1.b, object2.b, 'b', object1.b, object2.b] - ]; - - isEqualWith(object1, object2, function() { - var length = arguments.length, - args = slice.call(arguments, 0, length - (length > 2 ? 1 : 0)); - - argsList.push(args); - }); - - assert.deepStrictEqual(argsList, expected); - }); - - it('should handle comparisons when `customizer` returns `undefined`', function() { - assert.strictEqual(isEqualWith('a', 'a', noop), true); - assert.strictEqual(isEqualWith(['a'], ['a'], noop), true); - assert.strictEqual(isEqualWith({ '0': 'a' }, { '0': 'a' }, noop), true); - }); - - it('should not handle comparisons when `customizer` returns `true`', function() { - var customizer = function(value) { - return isString(value) || undefined; - }; - - assert.strictEqual(isEqualWith('a', 'b', customizer), true); - assert.strictEqual(isEqualWith(['a'], ['b'], customizer), true); - assert.strictEqual(isEqualWith({ '0': 'a' }, { '0': 'b' }, customizer), true); - }); - - it('should not handle comparisons when `customizer` returns `false`', function() { - var customizer = function(value) { - return isString(value) ? false : undefined; - }; - - assert.strictEqual(isEqualWith('a', 'a', customizer), false); - assert.strictEqual(isEqualWith(['a'], ['a'], customizer), false); - assert.strictEqual(isEqualWith({ '0': 'a' }, { '0': 'a' }, customizer), false); - }); - - it('should return a boolean value even when `customizer` does not', function() { - var actual = isEqualWith('a', 'b', stubC); - assert.strictEqual(actual, true); - - var values = without(falsey, undefined), - expected = lodashStable.map(values, stubFalse); - - actual = []; - lodashStable.each(values, function(value) { - actual.push(isEqualWith('a', 'a', lodashStable.constant(value))); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should ensure `customizer` is a function', function() { - var array = [1, 2, 3], - eq = partial(isEqualWith, array), - actual = lodashStable.map([array, [1, 0, 3]], eq); - - assert.deepStrictEqual(actual, [true, false]); - }); - - it('should call `customizer` for values maps and sets', function() { - var value = { 'a': { 'b': 2 } }; - - if (Map) { - var map1 = new Map; - map1.set('a', value); - - var map2 = new Map; - map2.set('a', value); - } - if (Set) { - var set1 = new Set; - set1.add(value); - - var set2 = new Set; - set2.add(value); - } - lodashStable.each([[map1, map2], [set1, set2]], function(pair, index) { - if (pair[0]) { - var argsList = [], - array = lodashStable.toArray(pair[0]); - - var expected = [ - [pair[0], pair[1]], - [array[0], array[0], 0, array, array], - [array[0][0], array[0][0], 0, array[0], array[0]], - [array[0][1], array[0][1], 1, array[0], array[0]] - ]; - - if (index) { - expected.length = 2; - } - isEqualWith(pair[0], pair[1], function() { - var length = arguments.length, - args = slice.call(arguments, 0, length - (length > 2 ? 1 : 0)); - - argsList.push(args); - }); - - assert.deepStrictEqual(argsList, expected, index ? 'Set' : 'Map'); - } - }); - }); -}); diff --git a/test/isEqualWith.spec.ts b/test/isEqualWith.spec.ts new file mode 100644 index 000000000..10adf7c5a --- /dev/null +++ b/test/isEqualWith.spec.ts @@ -0,0 +1,134 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, noop, stubC, falsey, stubFalse } from './utils'; +import isEqualWith from '../src/isEqualWith'; +import isString from '../src/isString'; +import without from '../src/without'; +import partial from '../src/partial'; + +describe('isEqualWith', () => { + it('should provide correct `customizer` arguments', () => { + const argsList = [], + object1 = { a: [1, 2], b: null }, + object2 = { a: [1, 2], b: null }; + + object1.b = object2; + object2.b = object1; + + const expected = [ + [object1, object2], + [object1.a, object2.a, 'a', object1, object2], + [object1.a[0], object2.a[0], 0, object1.a, object2.a], + [object1.a[1], object2.a[1], 1, object1.a, object2.a], + [object1.b, object2.b, 'b', object1.b, object2.b], + ]; + + isEqualWith(object1, object2, function () { + const length = arguments.length, + args = slice.call(arguments, 0, length - (length > 2 ? 1 : 0)); + + argsList.push(args); + }); + + assert.deepStrictEqual(argsList, expected); + }); + + it('should handle comparisons when `customizer` returns `undefined`', () => { + assert.strictEqual(isEqualWith('a', 'a', noop), true); + assert.strictEqual(isEqualWith(['a'], ['a'], noop), true); + assert.strictEqual(isEqualWith({ '0': 'a' }, { '0': 'a' }, noop), true); + }); + + it('should not handle comparisons when `customizer` returns `true`', () => { + const customizer = function (value) { + return isString(value) || undefined; + }; + + assert.strictEqual(isEqualWith('a', 'b', customizer), true); + assert.strictEqual(isEqualWith(['a'], ['b'], customizer), true); + assert.strictEqual(isEqualWith({ '0': 'a' }, { '0': 'b' }, customizer), true); + }); + + it('should not handle comparisons when `customizer` returns `false`', () => { + const customizer = function (value) { + return isString(value) ? false : undefined; + }; + + assert.strictEqual(isEqualWith('a', 'a', customizer), false); + assert.strictEqual(isEqualWith(['a'], ['a'], customizer), false); + assert.strictEqual(isEqualWith({ '0': 'a' }, { '0': 'a' }, customizer), false); + }); + + it('should return a boolean value even when `customizer` does not', () => { + let actual = isEqualWith('a', 'b', stubC); + assert.strictEqual(actual, true); + + const values = without(falsey, undefined), + expected = lodashStable.map(values, stubFalse); + + actual = []; + lodashStable.each(values, (value) => { + actual.push(isEqualWith('a', 'a', lodashStable.constant(value))); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should ensure `customizer` is a function', () => { + const array = [1, 2, 3], + eq = partial(isEqualWith, array), + actual = lodashStable.map([array, [1, 0, 3]], eq); + + assert.deepStrictEqual(actual, [true, false]); + }); + + it('should call `customizer` for values maps and sets', () => { + const value = { a: { b: 2 } }; + + if (Map) { + var map1 = new Map(); + map1.set('a', value); + + var map2 = new Map(); + map2.set('a', value); + } + if (Set) { + var set1 = new Set(); + set1.add(value); + + var set2 = new Set(); + set2.add(value); + } + lodashStable.each( + [ + [map1, map2], + [set1, set2], + ], + (pair, index) => { + if (pair[0]) { + const argsList = [], + array = lodashStable.toArray(pair[0]); + + const expected = [ + [pair[0], pair[1]], + [array[0], array[0], 0, array, array], + [array[0][0], array[0][0], 0, array[0], array[0]], + [array[0][1], array[0][1], 1, array[0], array[0]], + ]; + + if (index) { + expected.length = 2; + } + isEqualWith(pair[0], pair[1], function () { + const length = arguments.length, + args = slice.call(arguments, 0, length - (length > 2 ? 1 : 0)); + + argsList.push(args); + }); + + assert.deepStrictEqual(argsList, expected, index ? 'Set' : 'Map'); + } + }, + ); + }); +}); diff --git a/test/isError.spec.ts b/test/isError.spec.ts new file mode 100644 index 000000000..e39cfb9ff --- /dev/null +++ b/test/isError.spec.ts @@ -0,0 +1,65 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + errors, + stubTrue, + CustomError, + falsey, + stubFalse, + args, + slice, + symbol, + realm, +} from './utils'; + +import isError from '../src/isError'; + +describe('isError', () => { + it('should return `true` for error objects', () => { + const expected = lodashStable.map(errors, stubTrue); + + const actual = lodashStable.map(errors, (error) => isError(error) === true); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `true` for subclassed values', () => { + assert.strictEqual(isError(new CustomError('x')), true); + }); + + it('should return `false` for non error objects', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isError(value) : isError(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isError(args), false); + assert.strictEqual(isError([1, 2, 3]), false); + assert.strictEqual(isError(true), false); + assert.strictEqual(isError(new Date()), false); + assert.strictEqual(isError(slice), false); + assert.strictEqual(isError({ a: 1 }), false); + assert.strictEqual(isError(1), false); + assert.strictEqual(isError(/x/), false); + assert.strictEqual(isError('a'), false); + assert.strictEqual(isError(symbol), false); + }); + + it('should return `false` for plain objects', () => { + assert.strictEqual(isError({ name: 'Error', message: '' }), false); + }); + + it('should work with an error object from another realm', () => { + if (realm.errors) { + const expected = lodashStable.map(realm.errors, stubTrue); + + const actual = lodashStable.map(realm.errors, (error) => isError(error) === true); + + assert.deepStrictEqual(actual, expected); + } + }); +}); diff --git a/test/isError.test.js b/test/isError.test.js deleted file mode 100644 index 0805b588e..000000000 --- a/test/isError.test.js +++ /dev/null @@ -1,70 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - errors, - stubTrue, - CustomError, - falsey, - stubFalse, - args, - slice, - symbol, - realm, -} from './utils.js'; - -import isError from '../isError.js'; - -describe('isError', function() { - it('should return `true` for error objects', function() { - var expected = lodashStable.map(errors, stubTrue); - - var actual = lodashStable.map(errors, function(error) { - return isError(error) === true; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `true` for subclassed values', function() { - assert.strictEqual(isError(new CustomError('x')), true); - }); - - it('should return `false` for non error objects', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isError(value) : isError(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isError(args), false); - assert.strictEqual(isError([1, 2, 3]), false); - assert.strictEqual(isError(true), false); - assert.strictEqual(isError(new Date), false); - assert.strictEqual(isError(_), false); - assert.strictEqual(isError(slice), false); - assert.strictEqual(isError({ 'a': 1 }), false); - assert.strictEqual(isError(1), false); - assert.strictEqual(isError(/x/), false); - assert.strictEqual(isError('a'), false); - assert.strictEqual(isError(symbol), false); - }); - - it('should return `false` for plain objects', function() { - assert.strictEqual(isError({ 'name': 'Error', 'message': '' }), false); - }); - - it('should work with an error object from another realm', function() { - if (realm.errors) { - var expected = lodashStable.map(realm.errors, stubTrue); - - var actual = lodashStable.map(realm.errors, function(error) { - return isError(error) === true; - }); - - assert.deepStrictEqual(actual, expected); - } - }); -}); diff --git a/test/isFinite.js b/test/isFinite.js deleted file mode 100644 index f5c8ec688..000000000 --- a/test/isFinite.js +++ /dev/null @@ -1,48 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubTrue, stubFalse, args, symbol } from './utils.js'; -import isFinite from '../isFinite.js'; - -describe('isFinite', function() { - it('should return `true` for finite values', function() { - var values = [0, 1, 3.14, -1], - expected = lodashStable.map(values, stubTrue), - actual = lodashStable.map(values, isFinite); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `false` for non-finite values', function() { - var values = [NaN, Infinity, -Infinity, Object(1)], - expected = lodashStable.map(values, stubFalse), - actual = lodashStable.map(values, isFinite); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `false` for non-numeric values', function() { - var values = [undefined, [], true, '', ' ', '2px'], - expected = lodashStable.map(values, stubFalse), - actual = lodashStable.map(values, isFinite); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isFinite(args), false); - assert.strictEqual(isFinite([1, 2, 3]), false); - assert.strictEqual(isFinite(true), false); - assert.strictEqual(isFinite(new Date), false); - assert.strictEqual(isFinite(new Error), false); - assert.strictEqual(isFinite({ 'a': 1 }), false); - assert.strictEqual(isFinite(/x/), false); - assert.strictEqual(isFinite('a'), false); - assert.strictEqual(isFinite(symbol), false); - }); - - it('should return `false` for numeric string values', function() { - var values = ['2', '0', '08'], - expected = lodashStable.map(values, stubFalse), - actual = lodashStable.map(values, isFinite); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/isFinite.spec.ts b/test/isFinite.spec.ts new file mode 100644 index 000000000..0b849c368 --- /dev/null +++ b/test/isFinite.spec.ts @@ -0,0 +1,48 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubTrue, stubFalse, args, symbol } from './utils'; +import isFinite from '../src/isFinite'; + +describe('isFinite', () => { + it('should return `true` for finite values', () => { + const values = [0, 1, 3.14, -1], + expected = lodashStable.map(values, stubTrue), + actual = lodashStable.map(values, isFinite); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `false` for non-finite values', () => { + const values = [NaN, Infinity, -Infinity, Object(1)], + expected = lodashStable.map(values, stubFalse), + actual = lodashStable.map(values, isFinite); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `false` for non-numeric values', () => { + const values = [undefined, [], true, '', ' ', '2px'], + expected = lodashStable.map(values, stubFalse), + actual = lodashStable.map(values, isFinite); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isFinite(args), false); + assert.strictEqual(isFinite([1, 2, 3]), false); + assert.strictEqual(isFinite(true), false); + assert.strictEqual(isFinite(new Date()), false); + assert.strictEqual(isFinite(new Error()), false); + assert.strictEqual(isFinite({ a: 1 }), false); + assert.strictEqual(isFinite(/x/), false); + assert.strictEqual(isFinite('a'), false); + assert.strictEqual(isFinite(symbol), false); + }); + + it('should return `false` for numeric string values', () => { + const values = ['2', '0', '08'], + expected = lodashStable.map(values, stubFalse), + actual = lodashStable.map(values, isFinite); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/isFunction.js b/test/isFunction.js deleted file mode 100644 index be051d63c..000000000 --- a/test/isFunction.js +++ /dev/null @@ -1,83 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - slice, - asyncFunc, - genFunc, - arrayViews, - objToString, - funcTag, - falsey, - stubFalse, - args, - symbol, - document, - realm, -} from './utils.js'; - -import isFunction from '../isFunction.js'; - -describe('isFunction', function() { - it('should return `true` for functions', function() { - assert.strictEqual(isFunction(_), true); - assert.strictEqual(isFunction(slice), true); - }); - - it('should return `true` for async functions', function() { - assert.strictEqual(isFunction(asyncFunc), typeof asyncFunc === 'function'); - }); - - it('should return `true` for generator functions', function() { - assert.strictEqual(isFunction(genFunc), typeof genFunc === 'function'); - }); - - it('should return `true` for the `Proxy` constructor', function() { - if (Proxy) { - assert.strictEqual(isFunction(Proxy), true); - } - }); - - it('should return `true` for array view constructors', function() { - var expected = lodashStable.map(arrayViews, function(type) { - return objToString.call(root[type]) == funcTag; - }); - - var actual = lodashStable.map(arrayViews, function(type) { - return isFunction(root[type]); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `false` for non-functions', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isFunction(value) : isFunction(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isFunction(args), false); - assert.strictEqual(isFunction([1, 2, 3]), false); - assert.strictEqual(isFunction(true), false); - assert.strictEqual(isFunction(new Date), false); - assert.strictEqual(isFunction(new Error), false); - assert.strictEqual(isFunction({ 'a': 1 }), false); - assert.strictEqual(isFunction(1), false); - assert.strictEqual(isFunction(/x/), false); - assert.strictEqual(isFunction('a'), false); - assert.strictEqual(isFunction(symbol), false); - - if (document) { - assert.strictEqual(isFunction(document.getElementsByTagName('body')), false); - } - }); - - it('should work with a function from another realm', function() { - if (realm.function) { - assert.strictEqual(isFunction(realm.function), true); - } - }); -}); diff --git a/test/isFunction.spec.ts b/test/isFunction.spec.ts new file mode 100644 index 000000000..99d7fb49d --- /dev/null +++ b/test/isFunction.spec.ts @@ -0,0 +1,81 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + slice, + asyncFunc, + genFunc, + arrayViews, + objToString, + funcTag, + falsey, + stubFalse, + args, + symbol, + document, + realm, +} from './utils'; + +import isFunction from '../src/isFunction'; + +describe('isFunction', () => { + it('should return `true` for functions', () => { + assert.strictEqual(isFunction(slice), true); + }); + + it('should return `true` for async functions', () => { + assert.strictEqual(isFunction(asyncFunc), typeof asyncFunc === 'function'); + }); + + it('should return `true` for generator functions', () => { + assert.strictEqual(isFunction(genFunc), typeof genFunc === 'function'); + }); + + it('should return `true` for the `Proxy` constructor', () => { + if (Proxy) { + assert.strictEqual(isFunction(Proxy), true); + } + }); + + it('should return `true` for array view constructors', () => { + const expected = lodashStable.map( + arrayViews, + (type) => objToString.call(root[type]) == funcTag, + ); + + const actual = lodashStable.map(arrayViews, (type) => isFunction(root[type])); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `false` for non-functions', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isFunction(value) : isFunction(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isFunction(args), false); + assert.strictEqual(isFunction([1, 2, 3]), false); + assert.strictEqual(isFunction(true), false); + assert.strictEqual(isFunction(new Date()), false); + assert.strictEqual(isFunction(new Error()), false); + assert.strictEqual(isFunction({ a: 1 }), false); + assert.strictEqual(isFunction(1), false); + assert.strictEqual(isFunction(/x/), false); + assert.strictEqual(isFunction('a'), false); + assert.strictEqual(isFunction(symbol), false); + + if (document) { + assert.strictEqual(isFunction(document.getElementsByTagName('body')), false); + } + }); + + it('should work with a function from another realm', () => { + if (realm.function) { + assert.strictEqual(isFunction(realm.function), true); + } + }); +}); diff --git a/test/isIndex.spec.ts b/test/isIndex.spec.ts new file mode 100644 index 000000000..7f61d3df4 --- /dev/null +++ b/test/isIndex.spec.ts @@ -0,0 +1,30 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { MAX_SAFE_INTEGER, stubTrue, stubFalse } from './utils'; +import _isIndex from '../src/.internal/isIndex'; + +describe('isIndex', () => { + const func = _isIndex; + + it('should return `true` for indexes', () => { + if (func) { + const values = [[0], ['0'], ['1'], [3, 4], [MAX_SAFE_INTEGER - 1]], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (args) => func.apply(undefined, args)); + + assert.deepStrictEqual(actual, expected); + } + }); + + it('should return `false` for non-indexes', () => { + if (func) { + const values = [['1abc'], ['07'], ['0001'], [-1], [3, 3], [1.1], [MAX_SAFE_INTEGER]], + expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(values, (args) => func.apply(undefined, args)); + + assert.deepStrictEqual(actual, expected); + } + }); +}); diff --git a/test/isIndex.test.js b/test/isIndex.test.js deleted file mode 100644 index 486eef29e..000000000 --- a/test/isIndex.test.js +++ /dev/null @@ -1,34 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { MAX_SAFE_INTEGER, stubTrue, stubFalse } from './utils.js'; -import _isIndex from '../.internal/isIndex.js'; - -describe('isIndex', function() { - var func = _isIndex; - - it('should return `true` for indexes', function() { - if (func) { - var values = [[0], ['0'], ['1'], [3, 4], [MAX_SAFE_INTEGER - 1]], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(args) { - return func.apply(undefined, args); - }); - - assert.deepStrictEqual(actual, expected); - } - }); - - it('should return `false` for non-indexes', function() { - if (func) { - var values = [['1abc'], ['07'], ['0001'], [-1], [3, 3], [1.1], [MAX_SAFE_INTEGER]], - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(args) { - return func.apply(undefined, args); - }); - - assert.deepStrictEqual(actual, expected); - } - }); -}); diff --git a/test/isInteger-methods.js b/test/isInteger-methods.js deleted file mode 100644 index 9c12c6840..000000000 --- a/test/isInteger-methods.js +++ /dev/null @@ -1,55 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, stubTrue, MAX_INTEGER, stubFalse, falsey, args, symbol } from './utils.js'; - -describe('isInteger methods', function() { - lodashStable.each(['isInteger', 'isSafeInteger'], function(methodName) { - var func = _[methodName], - isSafe = methodName == 'isSafeInteger'; - - it('`_.' + methodName + '` should return `true` for integer values', function() { - var values = [-1, 0, 1], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value) { - return func(value); - }); - - assert.deepStrictEqual(actual, expected); - assert.strictEqual(func(MAX_INTEGER), !isSafe); - }); - - it('should return `false` for non-integer number values', function() { - var values = [NaN, Infinity, -Infinity, Object(1), 3.14], - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value) { - return func(value); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `false` for non-numeric values', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === 0; - }); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? func(value) : func(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(func(args), false); - assert.strictEqual(func([1, 2, 3]), false); - assert.strictEqual(func(true), false); - assert.strictEqual(func(new Date), false); - assert.strictEqual(func(new Error), false); - assert.strictEqual(func({ 'a': 1 }), false); - assert.strictEqual(func(/x/), false); - assert.strictEqual(func('a'), false); - assert.strictEqual(func(symbol), false); - }); - }); -}); diff --git a/test/isInteger-methods.spec.ts b/test/isInteger-methods.spec.ts new file mode 100644 index 000000000..74bd5b705 --- /dev/null +++ b/test/isInteger-methods.spec.ts @@ -0,0 +1,49 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, stubTrue, MAX_INTEGER, stubFalse, falsey, args, symbol } from './utils'; + +describe('isInteger methods', () => { + lodashStable.each(['isInteger', 'isSafeInteger'], (methodName) => { + const func = _[methodName], + isSafe = methodName == 'isSafeInteger'; + + it(`\`_.${methodName}\` should return \`true\` for integer values`, () => { + const values = [-1, 0, 1], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (value) => func(value)); + + assert.deepStrictEqual(actual, expected); + assert.strictEqual(func(MAX_INTEGER), !isSafe); + }); + + it('should return `false` for non-integer number values', () => { + const values = [NaN, Infinity, -Infinity, Object(1), 3.14], + expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(values, (value) => func(value)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `false` for non-numeric values', () => { + const expected = lodashStable.map(falsey, (value) => value === 0); + + const actual = lodashStable.map(falsey, (value, index) => + index ? func(value) : func(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(func(args), false); + assert.strictEqual(func([1, 2, 3]), false); + assert.strictEqual(func(true), false); + assert.strictEqual(func(new Date()), false); + assert.strictEqual(func(new Error()), false); + assert.strictEqual(func({ a: 1 }), false); + assert.strictEqual(func(/x/), false); + assert.strictEqual(func('a'), false); + assert.strictEqual(func(symbol), false); + }); + }); +}); diff --git a/test/isIterateeCall.js b/test/isIterateeCall.js deleted file mode 100644 index 86b4de524..000000000 --- a/test/isIterateeCall.js +++ /dev/null @@ -1,47 +0,0 @@ -import assert from 'assert'; -import { MAX_SAFE_INTEGER } from './utils.js'; -import _isIterateeCall from '../.internal/isIterateeCall.js'; - -describe('isIterateeCall', function() { - var array = [1], - func = _isIterateeCall, - object = { 'a': 1 }; - - it('should return `true` for iteratee calls', function() { - function Foo() {} - Foo.prototype.a = 1; - - if (func) { - assert.strictEqual(func(1, 0, array), true); - assert.strictEqual(func(1, 'a', object), true); - assert.strictEqual(func(1, 'a', new Foo), true); - } - }); - - it('should return `false` for non-iteratee calls', function() { - if (func) { - assert.strictEqual(func(2, 0, array), false); - assert.strictEqual(func(1, 1.1, array), false); - assert.strictEqual(func(1, 0, { 'length': MAX_SAFE_INTEGER + 1 }), false); - assert.strictEqual(func(1, 'b', object), false); - } - }); - - it('should work with `NaN` values', function() { - if (func) { - assert.strictEqual(func(NaN, 0, [NaN]), true); - assert.strictEqual(func(NaN, 'a', { 'a': NaN }), true); - } - }); - - it('should not error when `index` is an object without a `toString` method', function() { - if (func) { - try { - var actual = func(1, { 'toString': null }, [1]); - } catch (e) { - var message = e.message; - } - assert.strictEqual(actual, false, message || ''); - } - }); -}); diff --git a/test/isIterateeCall.spec.ts b/test/isIterateeCall.spec.ts new file mode 100644 index 000000000..8331b9035 --- /dev/null +++ b/test/isIterateeCall.spec.ts @@ -0,0 +1,47 @@ +import assert from 'node:assert'; +import { MAX_SAFE_INTEGER } from './utils'; +import _isIterateeCall from '../.internal/isIterateeCall'; + +describe('isIterateeCall', () => { + const array = [1], + func = _isIterateeCall, + object = { a: 1 }; + + it('should return `true` for iteratee calls', () => { + function Foo() {} + Foo.prototype.a = 1; + + if (func) { + assert.strictEqual(func(1, 0, array), true); + assert.strictEqual(func(1, 'a', object), true); + assert.strictEqual(func(1, 'a', new Foo()), true); + } + }); + + it('should return `false` for non-iteratee calls', () => { + if (func) { + assert.strictEqual(func(2, 0, array), false); + assert.strictEqual(func(1, 1.1, array), false); + assert.strictEqual(func(1, 0, { length: MAX_SAFE_INTEGER + 1 }), false); + assert.strictEqual(func(1, 'b', object), false); + } + }); + + it('should work with `NaN` values', () => { + if (func) { + assert.strictEqual(func(NaN, 0, [NaN]), true); + assert.strictEqual(func(NaN, 'a', { a: NaN }), true); + } + }); + + it('should not error when `index` is an object without a `toString` method', () => { + if (func) { + try { + var actual = func(1, { toString: null }, [1]); + } catch (e) { + var message = e.message; + } + assert.strictEqual(actual, false, message || ''); + } + }); +}); diff --git a/test/isLength.spec.ts b/test/isLength.spec.ts new file mode 100644 index 000000000..c65019334 --- /dev/null +++ b/test/isLength.spec.ts @@ -0,0 +1,22 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { MAX_SAFE_INTEGER, stubTrue, stubFalse } from './utils'; +import isLength from '../src/isLength'; + +describe('isLength', () => { + it('should return `true` for lengths', () => { + const values = [0, 3, MAX_SAFE_INTEGER], + expected = lodashStable.map(values, stubTrue), + actual = lodashStable.map(values, isLength); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `false` for non-lengths', () => { + const values = [-1, '1', 1.1, MAX_SAFE_INTEGER + 1], + expected = lodashStable.map(values, stubFalse), + actual = lodashStable.map(values, isLength); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/isLength.test.js b/test/isLength.test.js deleted file mode 100644 index 3978c0cb5..000000000 --- a/test/isLength.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { MAX_SAFE_INTEGER, stubTrue, stubFalse } from './utils.js'; -import isLength from '../isLength.js'; - -describe('isLength', function() { - it('should return `true` for lengths', function() { - var values = [0, 3, MAX_SAFE_INTEGER], - expected = lodashStable.map(values, stubTrue), - actual = lodashStable.map(values, isLength); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `false` for non-lengths', function() { - var values = [-1, '1', 1.1, MAX_SAFE_INTEGER + 1], - expected = lodashStable.map(values, stubFalse), - actual = lodashStable.map(values, isLength); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/isMap.spec.ts b/test/isMap.spec.ts new file mode 100644 index 000000000..1d21102b3 --- /dev/null +++ b/test/isMap.spec.ts @@ -0,0 +1,48 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { map, falsey, stubFalse, args, slice, symbol, weakMap, realm } from './utils'; +import isMap from '../src/isMap'; + +describe('isMap', () => { + it('should return `true` for maps', () => { + if (Map) { + assert.strictEqual(isMap(map), true); + } + }); + + it('should return `false` for non-maps', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => (index ? isMap(value) : isMap())); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isMap(args), false); + assert.strictEqual(isMap([1, 2, 3]), false); + assert.strictEqual(isMap(true), false); + assert.strictEqual(isMap(new Date()), false); + assert.strictEqual(isMap(new Error()), false); + assert.strictEqual(isMap(slice), false); + assert.strictEqual(isMap({ a: 1 }), false); + assert.strictEqual(isMap(1), false); + assert.strictEqual(isMap(/x/), false); + assert.strictEqual(isMap('a'), false); + assert.strictEqual(isMap(symbol), false); + assert.strictEqual(isMap(weakMap), false); + }); + + it('should work for objects with a non-function `constructor` (test in IE 11)', () => { + const values = [false, true], + expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(values, (value) => isMap({ constructor: value })); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with maps from another realm', () => { + if (realm.map) { + assert.strictEqual(isMap(realm.map), true); + } + }); +}); diff --git a/test/isMap.test.js b/test/isMap.test.js deleted file mode 100644 index 32fb80fff..000000000 --- a/test/isMap.test.js +++ /dev/null @@ -1,53 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { map, falsey, stubFalse, args, slice, symbol, weakMap, realm } from './utils.js'; -import isMap from '../isMap.js'; - -describe('isMap', function() { - it('should return `true` for maps', function() { - if (Map) { - assert.strictEqual(isMap(map), true); - } - }); - - it('should return `false` for non-maps', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isMap(value) : isMap(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isMap(args), false); - assert.strictEqual(isMap([1, 2, 3]), false); - assert.strictEqual(isMap(true), false); - assert.strictEqual(isMap(new Date), false); - assert.strictEqual(isMap(new Error), false); - assert.strictEqual(isMap(_), false); - assert.strictEqual(isMap(slice), false); - assert.strictEqual(isMap({ 'a': 1 }), false); - assert.strictEqual(isMap(1), false); - assert.strictEqual(isMap(/x/), false); - assert.strictEqual(isMap('a'), false); - assert.strictEqual(isMap(symbol), false); - assert.strictEqual(isMap(weakMap), false); - }); - - it('should work for objects with a non-function `constructor` (test in IE 11)', function() { - var values = [false, true], - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value) { - return isMap({ 'constructor': value }); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with maps from another realm', function() { - if (realm.map) { - assert.strictEqual(isMap(realm.map), true); - } - }); -}); diff --git a/test/isMatchWith.js b/test/isMatchWith.js deleted file mode 100644 index a7941d658..000000000 --- a/test/isMatchWith.js +++ /dev/null @@ -1,137 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, noop, stubA, falsey, stubFalse, isNpm, mapCaches } from './utils.js'; -import isMatchWith from '../isMatchWith.js'; -import isString from '../isString.js'; -import last from '../last.js'; -import partial from '../partial.js'; - -describe('isMatchWith', function() { - it('should provide correct `customizer` arguments', function() { - var argsList = [], - object1 = { 'a': [1, 2], 'b': null }, - object2 = { 'a': [1, 2], 'b': null }; - - object1.b = object2; - object2.b = object1; - - var expected = [ - [object1.a, object2.a, 'a', object1, object2], - [object1.a[0], object2.a[0], 0, object1.a, object2.a], - [object1.a[1], object2.a[1], 1, object1.a, object2.a], - [object1.b, object2.b, 'b', object1, object2], - [object1.b.a, object2.b.a, 'a', object1.b, object2.b], - [object1.b.a[0], object2.b.a[0], 0, object1.b.a, object2.b.a], - [object1.b.a[1], object2.b.a[1], 1, object1.b.a, object2.b.a], - [object1.b.b, object2.b.b, 'b', object1.b, object2.b] - ]; - - isMatchWith(object1, object2, function() { - argsList.push(slice.call(arguments, 0, -1)); - }); - - assert.deepStrictEqual(argsList, expected); - }); - - it('should handle comparisons when `customizer` returns `undefined`', function() { - assert.strictEqual(isMatchWith({ 'a': 1 }, { 'a': 1 }, noop), true); - }); - - it('should not handle comparisons when `customizer` returns `true`', function() { - var customizer = function(value) { - return isString(value) || undefined; - }; - - assert.strictEqual(isMatchWith(['a'], ['b'], customizer), true); - assert.strictEqual(isMatchWith({ '0': 'a' }, { '0': 'b' }, customizer), true); - }); - - it('should not handle comparisons when `customizer` returns `false`', function() { - var customizer = function(value) { - return isString(value) ? false : undefined; - }; - - assert.strictEqual(isMatchWith(['a'], ['a'], customizer), false); - assert.strictEqual(isMatchWith({ '0': 'a' }, { '0': 'a' }, customizer), false); - }); - - it('should return a boolean value even when `customizer` does not', function() { - var object = { 'a': 1 }, - actual = isMatchWith(object, { 'a': 1 }, stubA); - - assert.strictEqual(actual, true); - - var expected = lodashStable.map(falsey, stubFalse); - - actual = []; - lodashStable.each(falsey, function(value) { - actual.push(isMatchWith(object, { 'a': 2 }, lodashStable.constant(value))); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should provide `stack` to `customizer`', function() { - var actual; - - isMatchWith({ 'a': 1 }, { 'a': 1 }, function() { - actual = last(arguments); - }); - - assert.ok(isNpm - ? actual.constructor.name == 'Stack' - : actual instanceof mapCaches.Stack - ); - }); - - it('should ensure `customizer` is a function', function() { - var object = { 'a': 1 }, - matches = partial(isMatchWith, object), - actual = lodashStable.map([object, { 'a': 2 }], matches); - - assert.deepStrictEqual(actual, [true, false]); - }); - - it('should call `customizer` for values maps and sets', function() { - var value = { 'a': { 'b': 2 } }; - - if (Map) { - var map1 = new Map; - map1.set('a', value); - - var map2 = new Map; - map2.set('a', value); - } - if (Set) { - var set1 = new Set; - set1.add(value); - - var set2 = new Set; - set2.add(value); - } - lodashStable.each([[map1, map2], [set1, set2]], function(pair, index) { - if (pair[0]) { - var argsList = [], - array = lodashStable.toArray(pair[0]), - object1 = { 'a': pair[0] }, - object2 = { 'a': pair[1] }; - - var expected = [ - [pair[0], pair[1], 'a', object1, object2], - [array[0], array[0], 0, array, array], - [array[0][0], array[0][0], 0, array[0], array[0]], - [array[0][1], array[0][1], 1, array[0], array[0]] - ]; - - if (index) { - expected.length = 2; - } - isMatchWith({ 'a': pair[0] }, { 'a': pair[1] }, function() { - argsList.push(slice.call(arguments, 0, -1)); - }); - - assert.deepStrictEqual(argsList, expected, index ? 'Set' : 'Map'); - } - }); - }); -}); diff --git a/test/isMatchWith.spec.ts b/test/isMatchWith.spec.ts new file mode 100644 index 000000000..f3ab705f7 --- /dev/null +++ b/test/isMatchWith.spec.ts @@ -0,0 +1,140 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, noop, stubA, falsey, stubFalse, isNpm, mapCaches } from './utils'; +import isMatchWith from '../src/isMatchWith'; +import isString from '../src/isString'; +import last from '../src/last'; +import partial from '../src/partial'; + +describe('isMatchWith', () => { + it('should provide correct `customizer` arguments', () => { + const argsList = [], + object1 = { a: [1, 2], b: null }, + object2 = { a: [1, 2], b: null }; + + object1.b = object2; + object2.b = object1; + + const expected = [ + [object1.a, object2.a, 'a', object1, object2], + [object1.a[0], object2.a[0], 0, object1.a, object2.a], + [object1.a[1], object2.a[1], 1, object1.a, object2.a], + [object1.b, object2.b, 'b', object1, object2], + [object1.b.a, object2.b.a, 'a', object1.b, object2.b], + [object1.b.a[0], object2.b.a[0], 0, object1.b.a, object2.b.a], + [object1.b.a[1], object2.b.a[1], 1, object1.b.a, object2.b.a], + [object1.b.b, object2.b.b, 'b', object1.b, object2.b], + ]; + + isMatchWith(object1, object2, function () { + argsList.push(slice.call(arguments, 0, -1)); + }); + + assert.deepStrictEqual(argsList, expected); + }); + + it('should handle comparisons when `customizer` returns `undefined`', () => { + assert.strictEqual(isMatchWith({ a: 1 }, { a: 1 }, noop), true); + }); + + it('should not handle comparisons when `customizer` returns `true`', () => { + const customizer = function (value) { + return isString(value) || undefined; + }; + + assert.strictEqual(isMatchWith(['a'], ['b'], customizer), true); + assert.strictEqual(isMatchWith({ '0': 'a' }, { '0': 'b' }, customizer), true); + }); + + it('should not handle comparisons when `customizer` returns `false`', () => { + const customizer = function (value) { + return isString(value) ? false : undefined; + }; + + assert.strictEqual(isMatchWith(['a'], ['a'], customizer), false); + assert.strictEqual(isMatchWith({ '0': 'a' }, { '0': 'a' }, customizer), false); + }); + + it('should return a boolean value even when `customizer` does not', () => { + let object = { a: 1 }, + actual = isMatchWith(object, { a: 1 }, stubA); + + assert.strictEqual(actual, true); + + const expected = lodashStable.map(falsey, stubFalse); + + actual = []; + lodashStable.each(falsey, (value) => { + actual.push(isMatchWith(object, { a: 2 }, lodashStable.constant(value))); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should provide `stack` to `customizer`', () => { + let actual; + + isMatchWith({ a: 1 }, { a: 1 }, function () { + actual = last(arguments); + }); + + assert.ok(isNpm ? actual.constructor.name == 'Stack' : actual instanceof mapCaches.Stack); + }); + + it('should ensure `customizer` is a function', () => { + const object = { a: 1 }, + matches = partial(isMatchWith, object), + actual = lodashStable.map([object, { a: 2 }], matches); + + assert.deepStrictEqual(actual, [true, false]); + }); + + it('should call `customizer` for values maps and sets', () => { + const value = { a: { b: 2 } }; + + if (Map) { + var map1 = new Map(); + map1.set('a', value); + + var map2 = new Map(); + map2.set('a', value); + } + if (Set) { + var set1 = new Set(); + set1.add(value); + + var set2 = new Set(); + set2.add(value); + } + lodashStable.each( + [ + [map1, map2], + [set1, set2], + ], + (pair, index) => { + if (pair[0]) { + const argsList = [], + array = lodashStable.toArray(pair[0]), + object1 = { a: pair[0] }, + object2 = { a: pair[1] }; + + const expected = [ + [pair[0], pair[1], 'a', object1, object2], + [array[0], array[0], 0, array, array], + [array[0][0], array[0][0], 0, array[0], array[0]], + [array[0][1], array[0][1], 1, array[0], array[0]], + ]; + + if (index) { + expected.length = 2; + } + isMatchWith({ a: pair[0] }, { a: pair[1] }, function () { + argsList.push(slice.call(arguments, 0, -1)); + }); + + assert.deepStrictEqual(argsList, expected, index ? 'Set' : 'Map'); + } + }, + ); + }); +}); diff --git a/test/isNaN.js b/test/isNaN.js deleted file mode 100644 index 27529eac3..000000000 --- a/test/isNaN.js +++ /dev/null @@ -1,43 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, args, slice, symbol, realm } from './utils.js'; -import isNaN from '../isNaN.js'; - -describe('isNaN', function() { - it('should return `true` for NaNs', function() { - assert.strictEqual(isNaN(NaN), true); - assert.strictEqual(isNaN(Object(NaN)), true); - }); - - it('should return `false` for non-NaNs', function() { - var expected = lodashStable.map(falsey, function(value) { - return value !== value; - }); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isNaN(value) : isNaN(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isNaN(args), false); - assert.strictEqual(isNaN([1, 2, 3]), false); - assert.strictEqual(isNaN(true), false); - assert.strictEqual(isNaN(new Date), false); - assert.strictEqual(isNaN(new Error), false); - assert.strictEqual(isNaN(_), false); - assert.strictEqual(isNaN(slice), false); - assert.strictEqual(isNaN({ 'a': 1 }), false); - assert.strictEqual(isNaN(1), false); - assert.strictEqual(isNaN(Object(1)), false); - assert.strictEqual(isNaN(/x/), false); - assert.strictEqual(isNaN('a'), false); - assert.strictEqual(isNaN(symbol), false); - }); - - it('should work with `NaN` from another realm', function() { - if (realm.object) { - assert.strictEqual(isNaN(realm.nan), true); - } - }); -}); diff --git a/test/isNaN.spec.ts b/test/isNaN.spec.ts new file mode 100644 index 000000000..612e0e7b9 --- /dev/null +++ b/test/isNaN.spec.ts @@ -0,0 +1,38 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, args, slice, symbol, realm } from './utils'; +import isNaN from '../src/isNaN'; + +describe('isNaN', () => { + it('should return `true` for NaNs', () => { + assert.strictEqual(isNaN(NaN), true); + assert.strictEqual(isNaN(Object(NaN)), true); + }); + + it('should return `false` for non-NaNs', () => { + const expected = lodashStable.map(falsey, (value) => value !== value); + + const actual = lodashStable.map(falsey, (value, index) => (index ? isNaN(value) : isNaN())); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isNaN(args), false); + assert.strictEqual(isNaN([1, 2, 3]), false); + assert.strictEqual(isNaN(true), false); + assert.strictEqual(isNaN(new Date()), false); + assert.strictEqual(isNaN(new Error()), false); + assert.strictEqual(isNaN(slice), false); + assert.strictEqual(isNaN({ a: 1 }), false); + assert.strictEqual(isNaN(1), false); + assert.strictEqual(isNaN(Object(1)), false); + assert.strictEqual(isNaN(/x/), false); + assert.strictEqual(isNaN('a'), false); + assert.strictEqual(isNaN(symbol), false); + }); + + it('should work with `NaN` from another realm', () => { + if (realm.object) { + assert.strictEqual(isNaN(realm.nan), true); + } + }); +}); diff --git a/test/isNative.js b/test/isNative.js deleted file mode 100644 index c5f999485..000000000 --- a/test/isNative.js +++ /dev/null @@ -1,92 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - body, - create, - slice, - falsey, - stubFalse, - args, - symbol, - realm, - amd, - filePath, - emptyObject, - interopRequire, -} from './utils.js'; - -import isNative from '../isNative.js'; -import runInContext from '../runInContext.js'; -import _baseEach from '../.internal/baseEach.js'; - -describe('isNative', function() { - it('should return `true` for native methods', function() { - var values = [Array, body && body.cloneNode, create, root.encodeURI, Promise, slice, Uint8Array], - expected = lodashStable.map(values, Boolean), - actual = lodashStable.map(values, isNative); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `false` for non-native methods', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isNative(value) : isNative(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isNative(args), false); - assert.strictEqual(isNative([1, 2, 3]), false); - assert.strictEqual(isNative(true), false); - assert.strictEqual(isNative(new Date), false); - assert.strictEqual(isNative(new Error), false); - assert.strictEqual(isNative(_), false); - assert.strictEqual(isNative({ 'a': 1 }), false); - assert.strictEqual(isNative(1), false); - assert.strictEqual(isNative(/x/), false); - assert.strictEqual(isNative('a'), false); - assert.strictEqual(isNative(symbol), false); - }); - - it('should work with native functions from another realm', function() { - if (realm.element) { - assert.strictEqual(isNative(realm.element.cloneNode), true); - } - if (realm.object) { - assert.strictEqual(isNative(realm.object.valueOf), true); - } - }); - - it('should throw an error if core-js is detected', function() { - var lodash = runInContext({ - '__core-js_shared__': {} - }); - - assert.raises(function() { lodash.isNative(noop); }); - }); - - it('should detect methods masquerading as native (test in Node.js)', function() { - if (!amd && _baseEach) { - var path = require('path'), - basePath = path.dirname(filePath), - uid = 'e0gvgyrad1jor', - coreKey = '__core-js_shared__', - fakeSrcKey = 'Symbol(src)_1.' + uid; - - root[coreKey] = { 'keys': { 'IE_PROTO': 'Symbol(IE_PROTO)_3.' + uid } }; - emptyObject(require.cache); - - var baseIsNative = interopRequire(path.join(basePath, '_baseIsNative')); - assert.strictEqual(baseIsNative(slice), true); - - slice[fakeSrcKey] = slice + ''; - assert.strictEqual(baseIsNative(slice), false); - - delete slice[fakeSrcKey]; - delete root[coreKey]; - } - }); -}); diff --git a/test/isNative.spec.ts b/test/isNative.spec.ts new file mode 100644 index 000000000..de4d033e7 --- /dev/null +++ b/test/isNative.spec.ts @@ -0,0 +1,101 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + body, + create, + slice, + falsey, + stubFalse, + args, + symbol, + realm, + amd, + filePath, + emptyObject, + interopRequire, +} from './utils'; + +import isNative from '../src/isNative'; +import runInContext from '../src/runInContext'; +import _baseEach from '../.internal/baseEach'; + +describe('isNative', () => { + it('should return `true` for native methods', () => { + const values = [ + Array, + body && body.cloneNode, + create, + root.encodeURI, + Promise, + slice, + Uint8Array, + ], + expected = lodashStable.map(values, Boolean), + actual = lodashStable.map(values, isNative); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `false` for non-native methods', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isNative(value) : isNative(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isNative(args), false); + assert.strictEqual(isNative([1, 2, 3]), false); + assert.strictEqual(isNative(true), false); + assert.strictEqual(isNative(new Date()), false); + assert.strictEqual(isNative(new Error()), false); + assert.strictEqual(isNative({ a: 1 }), false); + assert.strictEqual(isNative(1), false); + assert.strictEqual(isNative(/x/), false); + assert.strictEqual(isNative('a'), false); + assert.strictEqual(isNative(symbol), false); + }); + + it('should work with native functions from another realm', () => { + if (realm.element) { + assert.strictEqual(isNative(realm.element.cloneNode), true); + } + if (realm.object) { + assert.strictEqual(isNative(realm.object.valueOf), true); + } + }); + + it('should throw an error if core-js is detected', () => { + const lodash = runInContext({ + '__core-js_shared__': {}, + }); + + assert.raises(() => { + lodash.isNative(noop); + }); + }); + + it('should detect methods masquerading as native (test in Node.js)', () => { + if (!amd && _baseEach) { + const path = require('path'), + basePath = path.dirname(filePath), + uid = 'e0gvgyrad1jor', + coreKey = '__core-js_shared__', + fakeSrcKey = `Symbol(src)_1.${uid}`; + + root[coreKey] = { keys: { IE_PROTO: `Symbol(IE_PROTO)_3.${uid}` } }; + emptyObject(require.cache); + + const baseIsNative = interopRequire(path.join(basePath, '_baseIsNative')); + assert.strictEqual(baseIsNative(slice), true); + + slice[fakeSrcKey] = `${slice}`; + assert.strictEqual(baseIsNative(slice), false); + + delete slice[fakeSrcKey]; + delete root[coreKey]; + } + }); +}); diff --git a/test/isNil.spec.ts b/test/isNil.spec.ts new file mode 100644 index 000000000..f6d39cdab --- /dev/null +++ b/test/isNil.spec.ts @@ -0,0 +1,42 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, args, slice, symbol, realm } from './utils'; +import isNil from '../src/isNil'; + +describe('isNil', () => { + it('should return `true` for nullish values', () => { + assert.strictEqual(isNil(null), true); + assert.strictEqual(isNil(), true); + assert.strictEqual(isNil(undefined), true); + }); + + it('should return `false` for non-nullish values', () => { + const expected = lodashStable.map(falsey, (value) => value == null); + + const actual = lodashStable.map(falsey, (value, index) => (index ? isNil(value) : isNil())); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isNil(args), false); + assert.strictEqual(isNil([1, 2, 3]), false); + assert.strictEqual(isNil(true), false); + assert.strictEqual(isNil(new Date()), false); + assert.strictEqual(isNil(new Error()), false); + assert.strictEqual(isNil(slice), false); + assert.strictEqual(isNil({ a: 1 }), false); + assert.strictEqual(isNil(1), false); + assert.strictEqual(isNil(/x/), false); + assert.strictEqual(isNil('a'), false); + + if (Symbol) { + assert.strictEqual(isNil(symbol), false); + } + }); + + it('should work with nils from another realm', () => { + if (realm.object) { + assert.strictEqual(isNil(realm.null), true); + assert.strictEqual(isNil(realm.undefined), true); + } + }); +}); diff --git a/test/isNil.test.js b/test/isNil.test.js deleted file mode 100644 index 3bd067be2..000000000 --- a/test/isNil.test.js +++ /dev/null @@ -1,47 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, args, slice, symbol, realm } from './utils.js'; -import isNil from '../isNil.js'; - -describe('isNil', function() { - it('should return `true` for nullish values', function() { - assert.strictEqual(isNil(null), true); - assert.strictEqual(isNil(), true); - assert.strictEqual(isNil(undefined), true); - }); - - it('should return `false` for non-nullish values', function() { - var expected = lodashStable.map(falsey, function(value) { - return value == null; - }); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isNil(value) : isNil(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isNil(args), false); - assert.strictEqual(isNil([1, 2, 3]), false); - assert.strictEqual(isNil(true), false); - assert.strictEqual(isNil(new Date), false); - assert.strictEqual(isNil(new Error), false); - assert.strictEqual(isNil(_), false); - assert.strictEqual(isNil(slice), false); - assert.strictEqual(isNil({ 'a': 1 }), false); - assert.strictEqual(isNil(1), false); - assert.strictEqual(isNil(/x/), false); - assert.strictEqual(isNil('a'), false); - - if (Symbol) { - assert.strictEqual(isNil(symbol), false); - } - }); - - it('should work with nils from another realm', function() { - if (realm.object) { - assert.strictEqual(isNil(realm.null), true); - assert.strictEqual(isNil(realm.undefined), true); - } - }); -}); diff --git a/test/isNull.spec.ts b/test/isNull.spec.ts new file mode 100644 index 000000000..9966f208e --- /dev/null +++ b/test/isNull.spec.ts @@ -0,0 +1,38 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, args, slice, symbol, realm } from './utils'; +import isNull from '../src/isNull'; + +describe('isNull', () => { + it('should return `true` for `null` values', () => { + assert.strictEqual(isNull(null), true); + }); + + it('should return `false` for non `null` values', () => { + const expected = lodashStable.map(falsey, (value) => value === null); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isNull(value) : isNull(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isNull(args), false); + assert.strictEqual(isNull([1, 2, 3]), false); + assert.strictEqual(isNull(true), false); + assert.strictEqual(isNull(new Date()), false); + assert.strictEqual(isNull(new Error()), false); + assert.strictEqual(isNull(slice), false); + assert.strictEqual(isNull({ a: 1 }), false); + assert.strictEqual(isNull(1), false); + assert.strictEqual(isNull(/x/), false); + assert.strictEqual(isNull('a'), false); + assert.strictEqual(isNull(symbol), false); + }); + + it('should work with nulls from another realm', () => { + if (realm.object) { + assert.strictEqual(isNull(realm.null), true); + } + }); +}); diff --git a/test/isNull.test.js b/test/isNull.test.js deleted file mode 100644 index 239e4c826..000000000 --- a/test/isNull.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, args, slice, symbol, realm } from './utils.js'; -import isNull from '../isNull.js'; - -describe('isNull', function() { - it('should return `true` for `null` values', function() { - assert.strictEqual(isNull(null), true); - }); - - it('should return `false` for non `null` values', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === null; - }); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isNull(value) : isNull(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isNull(args), false); - assert.strictEqual(isNull([1, 2, 3]), false); - assert.strictEqual(isNull(true), false); - assert.strictEqual(isNull(new Date), false); - assert.strictEqual(isNull(new Error), false); - assert.strictEqual(isNull(_), false); - assert.strictEqual(isNull(slice), false); - assert.strictEqual(isNull({ 'a': 1 }), false); - assert.strictEqual(isNull(1), false); - assert.strictEqual(isNull(/x/), false); - assert.strictEqual(isNull('a'), false); - assert.strictEqual(isNull(symbol), false); - }); - - it('should work with nulls from another realm', function() { - if (realm.object) { - assert.strictEqual(isNull(realm.null), true); - } - }); -}); diff --git a/test/isNumber.spec.ts b/test/isNumber.spec.ts new file mode 100644 index 000000000..a7974c73e --- /dev/null +++ b/test/isNumber.spec.ts @@ -0,0 +1,39 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, args, slice, symbol, realm } from './utils'; +import isNumber from '../src/isNumber'; + +describe('isNumber', () => { + it('should return `true` for numbers', () => { + assert.strictEqual(isNumber(0), true); + assert.strictEqual(isNumber(Object(0)), true); + assert.strictEqual(isNumber(NaN), true); + }); + + it('should return `false` for non-numbers', () => { + const expected = lodashStable.map(falsey, (value) => typeof value === 'number'); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isNumber(value) : isNumber(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isNumber(args), false); + assert.strictEqual(isNumber([1, 2, 3]), false); + assert.strictEqual(isNumber(true), false); + assert.strictEqual(isNumber(new Date()), false); + assert.strictEqual(isNumber(new Error()), false); + assert.strictEqual(isNumber(slice), false); + assert.strictEqual(isNumber({ a: 1 }), false); + assert.strictEqual(isNumber(/x/), false); + assert.strictEqual(isNumber('a'), false); + assert.strictEqual(isNumber(symbol), false); + }); + + it('should work with numbers from another realm', () => { + if (realm.number) { + assert.strictEqual(isNumber(realm.number), true); + } + }); +}); diff --git a/test/isNumber.test.js b/test/isNumber.test.js deleted file mode 100644 index fd9ff6bb3..000000000 --- a/test/isNumber.test.js +++ /dev/null @@ -1,42 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, args, slice, symbol, realm } from './utils.js'; -import isNumber from '../isNumber.js'; - -describe('isNumber', function() { - it('should return `true` for numbers', function() { - assert.strictEqual(isNumber(0), true); - assert.strictEqual(isNumber(Object(0)), true); - assert.strictEqual(isNumber(NaN), true); - }); - - it('should return `false` for non-numbers', function() { - var expected = lodashStable.map(falsey, function(value) { - return typeof value === 'number'; - }); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isNumber(value) : isNumber(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isNumber(args), false); - assert.strictEqual(isNumber([1, 2, 3]), false); - assert.strictEqual(isNumber(true), false); - assert.strictEqual(isNumber(new Date), false); - assert.strictEqual(isNumber(new Error), false); - assert.strictEqual(isNumber(_), false); - assert.strictEqual(isNumber(slice), false); - assert.strictEqual(isNumber({ 'a': 1 }), false); - assert.strictEqual(isNumber(/x/), false); - assert.strictEqual(isNumber('a'), false); - assert.strictEqual(isNumber(symbol), false); - }); - - it('should work with numbers from another realm', function() { - if (realm.number) { - assert.strictEqual(isNumber(realm.number), true); - } - }); -}); diff --git a/test/isObject.spec.ts b/test/isObject.spec.ts new file mode 100644 index 000000000..493b95b83 --- /dev/null +++ b/test/isObject.spec.ts @@ -0,0 +1,52 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, slice, document, body, symbol, falsey, stubFalse, realm } from './utils'; +import isObject from '../src/isObject'; + +describe('isObject', () => { + it('should return `true` for objects', () => { + assert.strictEqual(isObject(args), true); + assert.strictEqual(isObject([1, 2, 3]), true); + assert.strictEqual(isObject(Object(false)), true); + assert.strictEqual(isObject(new Date()), true); + assert.strictEqual(isObject(new Error()), true); + assert.strictEqual(isObject(slice), true); + assert.strictEqual(isObject({ a: 1 }), true); + assert.strictEqual(isObject(Object(0)), true); + assert.strictEqual(isObject(/x/), true); + assert.strictEqual(isObject(Object('a')), true); + + if (document) { + assert.strictEqual(isObject(body), true); + } + if (Symbol) { + assert.strictEqual(isObject(Object(symbol)), true); + } + }); + + it('should return `false` for non-objects', () => { + const values = falsey.concat(true, 1, 'a', symbol), + expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(values, (value, index) => + index ? isObject(value) : isObject(), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with objects from another realm', () => { + if (realm.element) { + assert.strictEqual(isObject(realm.element), true); + } + if (realm.object) { + assert.strictEqual(isObject(realm.boolean), true); + assert.strictEqual(isObject(realm.date), true); + assert.strictEqual(isObject(realm.function), true); + assert.strictEqual(isObject(realm.number), true); + assert.strictEqual(isObject(realm.object), true); + assert.strictEqual(isObject(realm.regexp), true); + assert.strictEqual(isObject(realm.string), true); + } + }); +}); diff --git a/test/isObject.test.js b/test/isObject.test.js deleted file mode 100644 index 8e24f532a..000000000 --- a/test/isObject.test.js +++ /dev/null @@ -1,53 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, slice, document, body, symbol, falsey, stubFalse, realm } from './utils.js'; -import isObject from '../isObject.js'; - -describe('isObject', function() { - it('should return `true` for objects', function() { - assert.strictEqual(isObject(args), true); - assert.strictEqual(isObject([1, 2, 3]), true); - assert.strictEqual(isObject(Object(false)), true); - assert.strictEqual(isObject(new Date), true); - assert.strictEqual(isObject(new Error), true); - assert.strictEqual(isObject(_), true); - assert.strictEqual(isObject(slice), true); - assert.strictEqual(isObject({ 'a': 1 }), true); - assert.strictEqual(isObject(Object(0)), true); - assert.strictEqual(isObject(/x/), true); - assert.strictEqual(isObject(Object('a')), true); - - if (document) { - assert.strictEqual(isObject(body), true); - } - if (Symbol) { - assert.strictEqual(isObject(Object(symbol)), true); - } - }); - - it('should return `false` for non-objects', function() { - var values = falsey.concat(true, 1, 'a', symbol), - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value, index) { - return index ? isObject(value) : isObject(); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with objects from another realm', function() { - if (realm.element) { - assert.strictEqual(isObject(realm.element), true); - } - if (realm.object) { - assert.strictEqual(isObject(realm.boolean), true); - assert.strictEqual(isObject(realm.date), true); - assert.strictEqual(isObject(realm.function), true); - assert.strictEqual(isObject(realm.number), true); - assert.strictEqual(isObject(realm.object), true); - assert.strictEqual(isObject(realm.regexp), true); - assert.strictEqual(isObject(realm.string), true); - } - }); -}); diff --git a/test/isObjectLike.spec.ts b/test/isObjectLike.spec.ts new file mode 100644 index 000000000..47b826a24 --- /dev/null +++ b/test/isObjectLike.spec.ts @@ -0,0 +1,40 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, falsey, slice, symbol, stubFalse, realm } from './utils'; +import isObjectLike from '../src/isObjectLike'; + +describe('isObjectLike', () => { + it('should return `true` for objects', () => { + assert.strictEqual(isObjectLike(args), true); + assert.strictEqual(isObjectLike([1, 2, 3]), true); + assert.strictEqual(isObjectLike(Object(false)), true); + assert.strictEqual(isObjectLike(new Date()), true); + assert.strictEqual(isObjectLike(new Error()), true); + assert.strictEqual(isObjectLike({ a: 1 }), true); + assert.strictEqual(isObjectLike(Object(0)), true); + assert.strictEqual(isObjectLike(/x/), true); + assert.strictEqual(isObjectLike(Object('a')), true); + }); + + it('should return `false` for non-objects', () => { + const values = falsey.concat(true, _, slice, 1, 'a', symbol), + expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(values, (value, index) => + index ? isObjectLike(value) : isObjectLike(), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with objects from another realm', () => { + if (realm.object) { + assert.strictEqual(isObjectLike(realm.boolean), true); + assert.strictEqual(isObjectLike(realm.date), true); + assert.strictEqual(isObjectLike(realm.number), true); + assert.strictEqual(isObjectLike(realm.object), true); + assert.strictEqual(isObjectLike(realm.regexp), true); + assert.strictEqual(isObjectLike(realm.string), true); + } + }); +}); diff --git a/test/isObjectLike.test.js b/test/isObjectLike.test.js deleted file mode 100644 index 516d87b23..000000000 --- a/test/isObjectLike.test.js +++ /dev/null @@ -1,40 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, falsey, slice, symbol, stubFalse, realm } from './utils.js'; -import isObjectLike from '../isObjectLike.js'; - -describe('isObjectLike', function() { - it('should return `true` for objects', function() { - assert.strictEqual(isObjectLike(args), true); - assert.strictEqual(isObjectLike([1, 2, 3]), true); - assert.strictEqual(isObjectLike(Object(false)), true); - assert.strictEqual(isObjectLike(new Date), true); - assert.strictEqual(isObjectLike(new Error), true); - assert.strictEqual(isObjectLike({ 'a': 1 }), true); - assert.strictEqual(isObjectLike(Object(0)), true); - assert.strictEqual(isObjectLike(/x/), true); - assert.strictEqual(isObjectLike(Object('a')), true); - }); - - it('should return `false` for non-objects', function() { - var values = falsey.concat(true, _, slice, 1, 'a', symbol), - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value, index) { - return index ? isObjectLike(value) : isObjectLike(); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with objects from another realm', function() { - if (realm.object) { - assert.strictEqual(isObjectLike(realm.boolean), true); - assert.strictEqual(isObjectLike(realm.date), true); - assert.strictEqual(isObjectLike(realm.number), true); - assert.strictEqual(isObjectLike(realm.object), true); - assert.strictEqual(isObjectLike(realm.regexp), true); - assert.strictEqual(isObjectLike(realm.string), true); - } - }); -}); diff --git a/test/isPlainObject.js b/test/isPlainObject.js deleted file mode 100644 index a50ba7b98..000000000 --- a/test/isPlainObject.js +++ /dev/null @@ -1,114 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - document, - create, - objectProto, - falsey, - stubFalse, - symbol, - defineProperty, - realm, -} from './utils.js'; - -import isPlainObject from '../isPlainObject.js'; - -describe('isPlainObject', function() { - var element = document && document.createElement('div'); - - it('should detect plain objects', function() { - function Foo(a) { - this.a = 1; - } - - assert.strictEqual(isPlainObject({}), true); - assert.strictEqual(isPlainObject({ 'a': 1 }), true); - assert.strictEqual(isPlainObject({ 'constructor': Foo }), true); - assert.strictEqual(isPlainObject([1, 2, 3]), false); - assert.strictEqual(isPlainObject(new Foo(1)), false); - }); - - it('should return `true` for objects with a `[[Prototype]]` of `null`', function() { - var object = create(null); - assert.strictEqual(isPlainObject(object), true); - - object.constructor = objectProto.constructor; - assert.strictEqual(isPlainObject(object), true); - }); - - it('should return `true` for objects with a `valueOf` property', function() { - assert.strictEqual(isPlainObject({ 'valueOf': 0 }), true); - }); - - it('should return `true` for objects with a writable `Symbol.toStringTag` property', function() { - if (Symbol && Symbol.toStringTag) { - var object = {}; - object[Symbol.toStringTag] = 'X'; - - assert.deepStrictEqual(isPlainObject(object), true); - } - }); - - it('should return `false` for objects with a custom `[[Prototype]]`', function() { - var object = create({ 'a': 1 }); - assert.strictEqual(isPlainObject(object), false); - }); - - it('should return `false` for DOM elements', function() { - if (element) { - assert.strictEqual(isPlainObject(element), false); - } - }); - - it('should return `false` for non-Object objects', function() { - assert.strictEqual(isPlainObject(arguments), false); - assert.strictEqual(isPlainObject(Error), false); - assert.strictEqual(isPlainObject(Math), false); - }); - - it('should return `false` for non-objects', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isPlainObject(value) : isPlainObject(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isPlainObject(true), false); - assert.strictEqual(isPlainObject('a'), false); - assert.strictEqual(isPlainObject(symbol), false); - }); - - it('should return `false` for objects with a read-only `Symbol.toStringTag` property', function() { - if (Symbol && Symbol.toStringTag) { - var object = {}; - defineProperty(object, Symbol.toStringTag, { - 'configurable': true, - 'enumerable': false, - 'writable': false, - 'value': 'X' - }); - - assert.deepStrictEqual(isPlainObject(object), false); - } - }); - - it('should not mutate `value`', function() { - if (Symbol && Symbol.toStringTag) { - var proto = {}; - proto[Symbol.toStringTag] = undefined; - var object = create(proto); - - assert.strictEqual(isPlainObject(object), false); - assert.ok(!lodashStable.has(object, Symbol.toStringTag)); - } - }); - - it('should work with objects from another realm', function() { - if (realm.object) { - assert.strictEqual(isPlainObject(realm.object), true); - } - }); -}); diff --git a/test/isPlainObject.spec.ts b/test/isPlainObject.spec.ts new file mode 100644 index 000000000..1b3edc36c --- /dev/null +++ b/test/isPlainObject.spec.ts @@ -0,0 +1,114 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + document, + create, + objectProto, + falsey, + stubFalse, + symbol, + defineProperty, + realm, +} from './utils'; + +import isPlainObject from '../src/isPlainObject'; + +describe('isPlainObject', () => { + const element = document && document.createElement('div'); + + it('should detect plain objects', () => { + function Foo(a) { + this.a = 1; + } + + assert.strictEqual(isPlainObject({}), true); + assert.strictEqual(isPlainObject({ a: 1 }), true); + assert.strictEqual(isPlainObject({ constructor: Foo }), true); + assert.strictEqual(isPlainObject([1, 2, 3]), false); + assert.strictEqual(isPlainObject(new Foo(1)), false); + }); + + it('should return `true` for objects with a `[[Prototype]]` of `null`', () => { + const object = create(null); + assert.strictEqual(isPlainObject(object), true); + + object.constructor = objectProto.constructor; + assert.strictEqual(isPlainObject(object), true); + }); + + it('should return `true` for objects with a `valueOf` property', () => { + assert.strictEqual(isPlainObject({ valueOf: 0 }), true); + }); + + it('should return `true` for objects with a writable `Symbol.toStringTag` property', () => { + if (Symbol && Symbol.toStringTag) { + const object = {}; + object[Symbol.toStringTag] = 'X'; + + assert.deepStrictEqual(isPlainObject(object), true); + } + }); + + it('should return `false` for objects with a custom `[[Prototype]]`', () => { + const object = create({ a: 1 }); + assert.strictEqual(isPlainObject(object), false); + }); + + it('should return `false` for DOM elements', () => { + if (element) { + assert.strictEqual(isPlainObject(element), false); + } + }); + + it('should return `false` for non-Object objects', function () { + assert.strictEqual(isPlainObject(arguments), false); + assert.strictEqual(isPlainObject(Error), false); + assert.strictEqual(isPlainObject(Math), false); + }); + + it('should return `false` for non-objects', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isPlainObject(value) : isPlainObject(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isPlainObject(true), false); + assert.strictEqual(isPlainObject('a'), false); + assert.strictEqual(isPlainObject(symbol), false); + }); + + it('should return `false` for objects with a read-only `Symbol.toStringTag` property', () => { + if (Symbol && Symbol.toStringTag) { + const object = {}; + defineProperty(object, Symbol.toStringTag, { + configurable: true, + enumerable: false, + writable: false, + value: 'X', + }); + + assert.deepStrictEqual(isPlainObject(object), false); + } + }); + + it('should not mutate `value`', () => { + if (Symbol && Symbol.toStringTag) { + const proto = {}; + proto[Symbol.toStringTag] = undefined; + const object = create(proto); + + assert.strictEqual(isPlainObject(object), false); + assert.ok(!lodashStable.has(object, Symbol.toStringTag)); + } + }); + + it('should work with objects from another realm', () => { + if (realm.object) { + assert.strictEqual(isPlainObject(realm.object), true); + } + }); +}); diff --git a/test/isRegExp.spec.ts b/test/isRegExp.spec.ts new file mode 100644 index 000000000..16fa8ea6a --- /dev/null +++ b/test/isRegExp.spec.ts @@ -0,0 +1,38 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubFalse, args, slice, symbol, realm } from './utils'; +import isRegExp from '../src/isRegExp'; + +describe('isRegExp', () => { + it('should return `true` for regexes', () => { + assert.strictEqual(isRegExp(/x/), true); + assert.strictEqual(isRegExp(RegExp('x')), true); + }); + + it('should return `false` for non-regexes', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isRegExp(value) : isRegExp(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isRegExp(args), false); + assert.strictEqual(isRegExp([1, 2, 3]), false); + assert.strictEqual(isRegExp(true), false); + assert.strictEqual(isRegExp(new Date()), false); + assert.strictEqual(isRegExp(new Error()), false); + assert.strictEqual(isRegExp(slice), false); + assert.strictEqual(isRegExp({ a: 1 }), false); + assert.strictEqual(isRegExp(1), false); + assert.strictEqual(isRegExp('a'), false); + assert.strictEqual(isRegExp(symbol), false); + }); + + it('should work with regexes from another realm', () => { + if (realm.regexp) { + assert.strictEqual(isRegExp(realm.regexp), true); + } + }); +}); diff --git a/test/isRegExp.test.js b/test/isRegExp.test.js deleted file mode 100644 index 507cdd474..000000000 --- a/test/isRegExp.test.js +++ /dev/null @@ -1,39 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubFalse, args, slice, symbol, realm } from './utils.js'; -import isRegExp from '../isRegExp.js'; - -describe('isRegExp', function() { - it('should return `true` for regexes', function() { - assert.strictEqual(isRegExp(/x/), true); - assert.strictEqual(isRegExp(RegExp('x')), true); - }); - - it('should return `false` for non-regexes', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isRegExp(value) : isRegExp(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isRegExp(args), false); - assert.strictEqual(isRegExp([1, 2, 3]), false); - assert.strictEqual(isRegExp(true), false); - assert.strictEqual(isRegExp(new Date), false); - assert.strictEqual(isRegExp(new Error), false); - assert.strictEqual(isRegExp(_), false); - assert.strictEqual(isRegExp(slice), false); - assert.strictEqual(isRegExp({ 'a': 1 }), false); - assert.strictEqual(isRegExp(1), false); - assert.strictEqual(isRegExp('a'), false); - assert.strictEqual(isRegExp(symbol), false); - }); - - it('should work with regexes from another realm', function() { - if (realm.regexp) { - assert.strictEqual(isRegExp(realm.regexp), true); - } - }); -}); diff --git a/test/isSet.spec.ts b/test/isSet.spec.ts new file mode 100644 index 000000000..4b86e029b --- /dev/null +++ b/test/isSet.spec.ts @@ -0,0 +1,48 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { set, falsey, stubFalse, args, slice, symbol, weakSet, realm } from './utils'; +import isSet from '../src/isSet'; + +describe('isSet', () => { + it('should return `true` for sets', () => { + if (Set) { + assert.strictEqual(isSet(set), true); + } + }); + + it('should return `false` for non-sets', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => (index ? isSet(value) : isSet())); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isSet(args), false); + assert.strictEqual(isSet([1, 2, 3]), false); + assert.strictEqual(isSet(true), false); + assert.strictEqual(isSet(new Date()), false); + assert.strictEqual(isSet(new Error()), false); + assert.strictEqual(isSet(slice), false); + assert.strictEqual(isSet({ a: 1 }), false); + assert.strictEqual(isSet(1), false); + assert.strictEqual(isSet(/x/), false); + assert.strictEqual(isSet('a'), false); + assert.strictEqual(isSet(symbol), false); + assert.strictEqual(isSet(weakSet), false); + }); + + it('should work for objects with a non-function `constructor` (test in IE 11)', () => { + const values = [false, true], + expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(values, (value) => isSet({ constructor: value })); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with weak sets from another realm', () => { + if (realm.set) { + assert.strictEqual(isSet(realm.set), true); + } + }); +}); diff --git a/test/isSet.test.js b/test/isSet.test.js deleted file mode 100644 index 49d9d9065..000000000 --- a/test/isSet.test.js +++ /dev/null @@ -1,53 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { set, falsey, stubFalse, args, slice, symbol, weakSet, realm } from './utils.js'; -import isSet from '../isSet.js'; - -describe('isSet', function() { - it('should return `true` for sets', function() { - if (Set) { - assert.strictEqual(isSet(set), true); - } - }); - - it('should return `false` for non-sets', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isSet(value) : isSet(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isSet(args), false); - assert.strictEqual(isSet([1, 2, 3]), false); - assert.strictEqual(isSet(true), false); - assert.strictEqual(isSet(new Date), false); - assert.strictEqual(isSet(new Error), false); - assert.strictEqual(isSet(_), false); - assert.strictEqual(isSet(slice), false); - assert.strictEqual(isSet({ 'a': 1 }), false); - assert.strictEqual(isSet(1), false); - assert.strictEqual(isSet(/x/), false); - assert.strictEqual(isSet('a'), false); - assert.strictEqual(isSet(symbol), false); - assert.strictEqual(isSet(weakSet), false); - }); - - it('should work for objects with a non-function `constructor` (test in IE 11)', function() { - var values = [false, true], - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value) { - return isSet({ 'constructor': value }); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with weak sets from another realm', function() { - if (realm.set) { - assert.strictEqual(isSet(realm.set), true); - } - }); -}); diff --git a/test/isString.spec.ts b/test/isString.spec.ts new file mode 100644 index 000000000..54bddfcba --- /dev/null +++ b/test/isString.spec.ts @@ -0,0 +1,38 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, args, slice, symbol, realm } from './utils'; +import isString from '../src/isString'; + +describe('isString', () => { + it('should return `true` for strings', () => { + assert.strictEqual(isString('a'), true); + assert.strictEqual(isString(Object('a')), true); + }); + + it('should return `false` for non-strings', () => { + const expected = lodashStable.map(falsey, (value) => value === ''); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isString(value) : isString(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isString(args), false); + assert.strictEqual(isString([1, 2, 3]), false); + assert.strictEqual(isString(true), false); + assert.strictEqual(isString(new Date()), false); + assert.strictEqual(isString(new Error()), false); + assert.strictEqual(isString(slice), false); + assert.strictEqual(isString({ '0': 1, length: 1 }), false); + assert.strictEqual(isString(1), false); + assert.strictEqual(isString(/x/), false); + assert.strictEqual(isString(symbol), false); + }); + + it('should work with strings from another realm', () => { + if (realm.string) { + assert.strictEqual(isString(realm.string), true); + } + }); +}); diff --git a/test/isString.test.js b/test/isString.test.js deleted file mode 100644 index e046d507f..000000000 --- a/test/isString.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, args, slice, symbol, realm } from './utils.js'; -import isString from '../isString.js'; - -describe('isString', function() { - it('should return `true` for strings', function() { - assert.strictEqual(isString('a'), true); - assert.strictEqual(isString(Object('a')), true); - }); - - it('should return `false` for non-strings', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === ''; - }); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isString(value) : isString(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isString(args), false); - assert.strictEqual(isString([1, 2, 3]), false); - assert.strictEqual(isString(true), false); - assert.strictEqual(isString(new Date), false); - assert.strictEqual(isString(new Error), false); - assert.strictEqual(isString(_), false); - assert.strictEqual(isString(slice), false); - assert.strictEqual(isString({ '0': 1, 'length': 1 }), false); - assert.strictEqual(isString(1), false); - assert.strictEqual(isString(/x/), false); - assert.strictEqual(isString(symbol), false); - }); - - it('should work with strings from another realm', function() { - if (realm.string) { - assert.strictEqual(isString(realm.string), true); - } - }); -}); diff --git a/test/isSymbol.spec.ts b/test/isSymbol.spec.ts new file mode 100644 index 000000000..9949297ec --- /dev/null +++ b/test/isSymbol.spec.ts @@ -0,0 +1,40 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { symbol, falsey, stubFalse, args, slice, realm } from './utils'; +import isSymbol from '../src/isSymbol'; + +describe('isSymbol', () => { + it('should return `true` for symbols', () => { + if (Symbol) { + assert.strictEqual(isSymbol(symbol), true); + assert.strictEqual(isSymbol(Object(symbol)), true); + } + }); + + it('should return `false` for non-symbols', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isSymbol(value) : isSymbol(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isSymbol(args), false); + assert.strictEqual(isSymbol([1, 2, 3]), false); + assert.strictEqual(isSymbol(true), false); + assert.strictEqual(isSymbol(new Date()), false); + assert.strictEqual(isSymbol(new Error()), false); + assert.strictEqual(isSymbol(slice), false); + assert.strictEqual(isSymbol({ '0': 1, length: 1 }), false); + assert.strictEqual(isSymbol(1), false); + assert.strictEqual(isSymbol(/x/), false); + assert.strictEqual(isSymbol('a'), false); + }); + + it('should work with symbols from another realm', () => { + if (Symbol && realm.symbol) { + assert.strictEqual(isSymbol(realm.symbol), true); + } + }); +}); diff --git a/test/isSymbol.test.js b/test/isSymbol.test.js deleted file mode 100644 index bf546c649..000000000 --- a/test/isSymbol.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { symbol, falsey, stubFalse, args, slice, realm } from './utils.js'; -import isSymbol from '../isSymbol.js'; - -describe('isSymbol', function() { - it('should return `true` for symbols', function() { - if (Symbol) { - assert.strictEqual(isSymbol(symbol), true); - assert.strictEqual(isSymbol(Object(symbol)), true); - } - }); - - it('should return `false` for non-symbols', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isSymbol(value) : isSymbol(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isSymbol(args), false); - assert.strictEqual(isSymbol([1, 2, 3]), false); - assert.strictEqual(isSymbol(true), false); - assert.strictEqual(isSymbol(new Date), false); - assert.strictEqual(isSymbol(new Error), false); - assert.strictEqual(isSymbol(_), false); - assert.strictEqual(isSymbol(slice), false); - assert.strictEqual(isSymbol({ '0': 1, 'length': 1 }), false); - assert.strictEqual(isSymbol(1), false); - assert.strictEqual(isSymbol(/x/), false); - assert.strictEqual(isSymbol('a'), false); - }); - - it('should work with symbols from another realm', function() { - if (Symbol && realm.symbol) { - assert.strictEqual(isSymbol(realm.symbol), true); - } - }); -}); diff --git a/test/isType-checks.js b/test/isType-checks.js deleted file mode 100644 index 909669721..000000000 --- a/test/isType-checks.js +++ /dev/null @@ -1,39 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { objToString, objectTag, _, xml } from './utils.js'; - -describe('isType checks', function() { - it('should return `false` for subclassed values', function() { - var funcs = [ - 'isArray', 'isBoolean', 'isDate', 'isFunction', - 'isNumber', 'isRegExp', 'isString' - ]; - - lodashStable.each(funcs, function(methodName) { - function Foo() {} - Foo.prototype = root[methodName.slice(2)].prototype; - - var object = new Foo; - if (objToString.call(object) == objectTag) { - assert.strictEqual(_[methodName](object), false, '`_.' + methodName + '` returns `false`'); - } - }); - }); - - it('should not error on host objects (test in IE)', function() { - var funcs = [ - 'isArguments', 'isArray', 'isArrayBuffer', 'isArrayLike', 'isBoolean', - 'isBuffer', 'isDate', 'isElement', 'isError', 'isFinite', 'isFunction', - 'isInteger', 'isMap', 'isNaN', 'isNil', 'isNull', 'isNumber', 'isObject', - 'isObjectLike', 'isRegExp', 'isSet', 'isSafeInteger', 'isString', - 'isUndefined', 'isWeakMap', 'isWeakSet' - ]; - - lodashStable.each(funcs, function(methodName) { - if (xml) { - _[methodName](xml); - assert.ok(true, '`_.' + methodName + '` should not error'); - } - }); - }); -}); diff --git a/test/isType-checks.spec.ts b/test/isType-checks.spec.ts new file mode 100644 index 000000000..2e985d80d --- /dev/null +++ b/test/isType-checks.spec.ts @@ -0,0 +1,69 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { objToString, objectTag, _, xml } from './utils'; + +describe('isType checks', () => { + it('should return `false` for subclassed values', () => { + const funcs = [ + 'isArray', + 'isBoolean', + 'isDate', + 'isFunction', + 'isNumber', + 'isRegExp', + 'isString', + ]; + + lodashStable.each(funcs, (methodName) => { + function Foo() {} + Foo.prototype = root[methodName.slice(2)].prototype; + + const object = new Foo(); + if (objToString.call(object) == objectTag) { + assert.strictEqual( + _[methodName](object), + false, + `\`_.${methodName}\` returns \`false\``, + ); + } + }); + }); + + it('should not error on host objects (test in IE)', () => { + const funcs = [ + 'isArguments', + 'isArray', + 'isArrayBuffer', + 'isArrayLike', + 'isBoolean', + 'isBuffer', + 'isDate', + 'isElement', + 'isError', + 'isFinite', + 'isFunction', + 'isInteger', + 'isMap', + 'isNaN', + 'isNil', + 'isNull', + 'isNumber', + 'isObject', + 'isObjectLike', + 'isRegExp', + 'isSet', + 'isSafeInteger', + 'isString', + 'isUndefined', + 'isWeakMap', + 'isWeakSet', + ]; + + lodashStable.each(funcs, (methodName) => { + if (xml) { + _[methodName](xml); + assert.ok(true, `\`_.${methodName}\` should not error`); + } + }); + }); +}); diff --git a/test/isTypedArray.js b/test/isTypedArray.js deleted file mode 100644 index 3c0d8be2e..000000000 --- a/test/isTypedArray.js +++ /dev/null @@ -1,59 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { typedArrays, falsey, stubFalse, args, slice, symbol, realm } from './utils.js'; -import isTypedArray from '../isTypedArray.js'; - -describe('isTypedArray', function() { - it('should return `true` for typed arrays', function() { - var expected = lodashStable.map(typedArrays, function(type) { - return type in root; - }); - - var actual = lodashStable.map(typedArrays, function(type) { - var Ctor = root[type]; - return Ctor ? isTypedArray(new Ctor(new ArrayBuffer(8))) : false; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `false` for non typed arrays', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isTypedArray(value) : isTypedArray(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isTypedArray(args), false); - assert.strictEqual(isTypedArray([1, 2, 3]), false); - assert.strictEqual(isTypedArray(true), false); - assert.strictEqual(isTypedArray(new Date), false); - assert.strictEqual(isTypedArray(new Error), false); - assert.strictEqual(isTypedArray(_), false); - assert.strictEqual(isTypedArray(slice), false); - assert.strictEqual(isTypedArray({ 'a': 1 }), false); - assert.strictEqual(isTypedArray(1), false); - assert.strictEqual(isTypedArray(/x/), false); - assert.strictEqual(isTypedArray('a'), false); - assert.strictEqual(isTypedArray(symbol), false); - }); - - it('should work with typed arrays from another realm', function() { - if (realm.object) { - var props = lodashStable.invokeMap(typedArrays, 'toLowerCase'); - - var expected = lodashStable.map(props, function(key) { - return realm[key] !== undefined; - }); - - var actual = lodashStable.map(props, function(key) { - var value = realm[key]; - return value ? isTypedArray(value) : false; - }); - - assert.deepStrictEqual(actual, expected); - } - }); -}); diff --git a/test/isTypedArray.spec.ts b/test/isTypedArray.spec.ts new file mode 100644 index 000000000..b051d02cb --- /dev/null +++ b/test/isTypedArray.spec.ts @@ -0,0 +1,54 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { typedArrays, falsey, stubFalse, args, slice, symbol, realm } from './utils'; +import isTypedArray from '../src/isTypedArray'; + +describe('isTypedArray', () => { + it('should return `true` for typed arrays', () => { + const expected = lodashStable.map(typedArrays, (type) => type in root); + + const actual = lodashStable.map(typedArrays, (type) => { + const Ctor = root[type]; + return Ctor ? isTypedArray(new Ctor(new ArrayBuffer(8))) : false; + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `false` for non typed arrays', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isTypedArray(value) : isTypedArray(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isTypedArray(args), false); + assert.strictEqual(isTypedArray([1, 2, 3]), false); + assert.strictEqual(isTypedArray(true), false); + assert.strictEqual(isTypedArray(new Date()), false); + assert.strictEqual(isTypedArray(new Error()), false); + assert.strictEqual(isTypedArray(slice), false); + assert.strictEqual(isTypedArray({ a: 1 }), false); + assert.strictEqual(isTypedArray(1), false); + assert.strictEqual(isTypedArray(/x/), false); + assert.strictEqual(isTypedArray('a'), false); + assert.strictEqual(isTypedArray(symbol), false); + }); + + it('should work with typed arrays from another realm', () => { + if (realm.object) { + const props = lodashStable.invokeMap(typedArrays, 'toLowerCase'); + + const expected = lodashStable.map(props, (key) => realm[key] !== undefined); + + const actual = lodashStable.map(props, (key) => { + const value = realm[key]; + return value ? isTypedArray(value) : false; + }); + + assert.deepStrictEqual(actual, expected); + } + }); +}); diff --git a/test/isUndefined.spec.ts b/test/isUndefined.spec.ts new file mode 100644 index 000000000..085be4640 --- /dev/null +++ b/test/isUndefined.spec.ts @@ -0,0 +1,42 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, args, slice, symbol, realm } from './utils'; +import isUndefined from '../src/isUndefined'; + +describe('isUndefined', () => { + it('should return `true` for `undefined` values', () => { + assert.strictEqual(isUndefined(), true); + assert.strictEqual(isUndefined(undefined), true); + }); + + it('should return `false` for non `undefined` values', () => { + const expected = lodashStable.map(falsey, (value) => value === undefined); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isUndefined(value) : isUndefined(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isUndefined(args), false); + assert.strictEqual(isUndefined([1, 2, 3]), false); + assert.strictEqual(isUndefined(true), false); + assert.strictEqual(isUndefined(new Date()), false); + assert.strictEqual(isUndefined(new Error()), false); + assert.strictEqual(isUndefined(slice), false); + assert.strictEqual(isUndefined({ a: 1 }), false); + assert.strictEqual(isUndefined(1), false); + assert.strictEqual(isUndefined(/x/), false); + assert.strictEqual(isUndefined('a'), false); + + if (Symbol) { + assert.strictEqual(isUndefined(symbol), false); + } + }); + + it('should work with `undefined` from another realm', () => { + if (realm.object) { + assert.strictEqual(isUndefined(realm.undefined), true); + } + }); +}); diff --git a/test/isUndefined.test.js b/test/isUndefined.test.js deleted file mode 100644 index 4f8c1fceb..000000000 --- a/test/isUndefined.test.js +++ /dev/null @@ -1,45 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, args, slice, symbol, realm } from './utils.js'; -import isUndefined from '../isUndefined.js'; - -describe('isUndefined', function() { - it('should return `true` for `undefined` values', function() { - assert.strictEqual(isUndefined(), true); - assert.strictEqual(isUndefined(undefined), true); - }); - - it('should return `false` for non `undefined` values', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined; - }); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isUndefined(value) : isUndefined(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isUndefined(args), false); - assert.strictEqual(isUndefined([1, 2, 3]), false); - assert.strictEqual(isUndefined(true), false); - assert.strictEqual(isUndefined(new Date), false); - assert.strictEqual(isUndefined(new Error), false); - assert.strictEqual(isUndefined(_), false); - assert.strictEqual(isUndefined(slice), false); - assert.strictEqual(isUndefined({ 'a': 1 }), false); - assert.strictEqual(isUndefined(1), false); - assert.strictEqual(isUndefined(/x/), false); - assert.strictEqual(isUndefined('a'), false); - - if (Symbol) { - assert.strictEqual(isUndefined(symbol), false); - } - }); - - it('should work with `undefined` from another realm', function() { - if (realm.object) { - assert.strictEqual(isUndefined(realm.undefined), true); - } - }); -}); diff --git a/test/isWeakMap.spec.ts b/test/isWeakMap.spec.ts new file mode 100644 index 000000000..006c94de5 --- /dev/null +++ b/test/isWeakMap.spec.ts @@ -0,0 +1,50 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { weakMap, falsey, stubFalse, args, slice, map, symbol, realm } from './utils'; +import isWeakMap from '../src/isWeakMap'; + +describe('isWeakMap', () => { + it('should return `true` for weak maps', () => { + if (WeakMap) { + assert.strictEqual(isWeakMap(weakMap), true); + } + }); + + it('should return `false` for non weak maps', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isWeakMap(value) : isWeakMap(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isWeakMap(args), false); + assert.strictEqual(isWeakMap([1, 2, 3]), false); + assert.strictEqual(isWeakMap(true), false); + assert.strictEqual(isWeakMap(new Date()), false); + assert.strictEqual(isWeakMap(new Error()), false); + assert.strictEqual(isWeakMap(slice), false); + assert.strictEqual(isWeakMap({ a: 1 }), false); + assert.strictEqual(isWeakMap(map), false); + assert.strictEqual(isWeakMap(1), false); + assert.strictEqual(isWeakMap(/x/), false); + assert.strictEqual(isWeakMap('a'), false); + assert.strictEqual(isWeakMap(symbol), false); + }); + + it('should work for objects with a non-function `constructor` (test in IE 11)', () => { + const values = [false, true], + expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(values, (value) => isWeakMap({ constructor: value })); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with weak maps from another realm', () => { + if (realm.weakMap) { + assert.strictEqual(isWeakMap(realm.weakMap), true); + } + }); +}); diff --git a/test/isWeakMap.test.js b/test/isWeakMap.test.js deleted file mode 100644 index f0c153207..000000000 --- a/test/isWeakMap.test.js +++ /dev/null @@ -1,53 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { weakMap, falsey, stubFalse, args, slice, map, symbol, realm } from './utils.js'; -import isWeakMap from '../isWeakMap.js'; - -describe('isWeakMap', function() { - it('should return `true` for weak maps', function() { - if (WeakMap) { - assert.strictEqual(isWeakMap(weakMap), true); - } - }); - - it('should return `false` for non weak maps', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isWeakMap(value) : isWeakMap(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isWeakMap(args), false); - assert.strictEqual(isWeakMap([1, 2, 3]), false); - assert.strictEqual(isWeakMap(true), false); - assert.strictEqual(isWeakMap(new Date), false); - assert.strictEqual(isWeakMap(new Error), false); - assert.strictEqual(isWeakMap(_), false); - assert.strictEqual(isWeakMap(slice), false); - assert.strictEqual(isWeakMap({ 'a': 1 }), false); - assert.strictEqual(isWeakMap(map), false); - assert.strictEqual(isWeakMap(1), false); - assert.strictEqual(isWeakMap(/x/), false); - assert.strictEqual(isWeakMap('a'), false); - assert.strictEqual(isWeakMap(symbol), false); - }); - - it('should work for objects with a non-function `constructor` (test in IE 11)', function() { - var values = [false, true], - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value) { - return isWeakMap({ 'constructor': value }); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with weak maps from another realm', function() { - if (realm.weakMap) { - assert.strictEqual(isWeakMap(realm.weakMap), true); - } - }); -}); diff --git a/test/isWeakSet.spec.ts b/test/isWeakSet.spec.ts new file mode 100644 index 000000000..503fb5665 --- /dev/null +++ b/test/isWeakSet.spec.ts @@ -0,0 +1,41 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { weakSet, falsey, stubFalse, args, slice, set, symbol, realm } from './utils'; +import isWeakSet from '../src/isWeakSet'; + +describe('isWeakSet', () => { + it('should return `true` for weak sets', () => { + if (WeakSet) { + assert.strictEqual(isWeakSet(weakSet), true); + } + }); + + it('should return `false` for non weak sets', () => { + const expected = lodashStable.map(falsey, stubFalse); + + const actual = lodashStable.map(falsey, (value, index) => + index ? isWeakSet(value) : isWeakSet(), + ); + + assert.deepStrictEqual(actual, expected); + + assert.strictEqual(isWeakSet(args), false); + assert.strictEqual(isWeakSet([1, 2, 3]), false); + assert.strictEqual(isWeakSet(true), false); + assert.strictEqual(isWeakSet(new Date()), false); + assert.strictEqual(isWeakSet(new Error()), false); + assert.strictEqual(isWeakSet(slice), false); + assert.strictEqual(isWeakSet({ a: 1 }), false); + assert.strictEqual(isWeakSet(1), false); + assert.strictEqual(isWeakSet(/x/), false); + assert.strictEqual(isWeakSet('a'), false); + assert.strictEqual(isWeakSet(set), false); + assert.strictEqual(isWeakSet(symbol), false); + }); + + it('should work with weak sets from another realm', () => { + if (realm.weakSet) { + assert.strictEqual(isWeakSet(realm.weakSet), true); + } + }); +}); diff --git a/test/isWeakSet.test.js b/test/isWeakSet.test.js deleted file mode 100644 index a974bf1f5..000000000 --- a/test/isWeakSet.test.js +++ /dev/null @@ -1,42 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { weakSet, falsey, stubFalse, args, slice, set, symbol, realm } from './utils.js'; -import isWeakSet from '../isWeakSet.js'; - -describe('isWeakSet', function() { - it('should return `true` for weak sets', function() { - if (WeakSet) { - assert.strictEqual(isWeakSet(weakSet), true); - } - }); - - it('should return `false` for non weak sets', function() { - var expected = lodashStable.map(falsey, stubFalse); - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? isWeakSet(value) : isWeakSet(); - }); - - assert.deepStrictEqual(actual, expected); - - assert.strictEqual(isWeakSet(args), false); - assert.strictEqual(isWeakSet([1, 2, 3]), false); - assert.strictEqual(isWeakSet(true), false); - assert.strictEqual(isWeakSet(new Date), false); - assert.strictEqual(isWeakSet(new Error), false); - assert.strictEqual(isWeakSet(_), false); - assert.strictEqual(isWeakSet(slice), false); - assert.strictEqual(isWeakSet({ 'a': 1 }), false); - assert.strictEqual(isWeakSet(1), false); - assert.strictEqual(isWeakSet(/x/), false); - assert.strictEqual(isWeakSet('a'), false); - assert.strictEqual(isWeakSet(set), false); - assert.strictEqual(isWeakSet(symbol), false); - }); - - it('should work with weak sets from another realm', function() { - if (realm.weakSet) { - assert.strictEqual(isWeakSet(realm.weakSet), true); - } - }); -}); diff --git a/test/iteratee.js b/test/iteratee.js deleted file mode 100644 index fd653dd2e..000000000 --- a/test/iteratee.js +++ /dev/null @@ -1,164 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, _, isNpm, push, stubFalse } from './utils.js'; -import partial from '../partial.js'; -import partialRight from '../partialRight.js'; -import map from '../map.js'; - -describe('iteratee', function() { - it('should provide arguments to `func`', function() { - var fn = function() { return slice.call(arguments); }, - iteratee = _.iteratee(fn), - actual = iteratee('a', 'b', 'c', 'd', 'e', 'f'); - - assert.deepStrictEqual(actual, ['a', 'b', 'c', 'd', 'e', 'f']); - }); - - it('should return `_.identity` when `func` is nullish', function() { - var object = {}, - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant([!isNpm && _.identity, object])); - - var actual = lodashStable.map(values, function(value, index) { - var identity = index ? _.iteratee(value) : _.iteratee(); - return [!isNpm && identity, identity(object)]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return an iteratee created by `_.matches` when `func` is an object', function() { - var matches = _.iteratee({ 'a': 1, 'b': 2 }); - assert.strictEqual(matches({ 'a': 1, 'b': 2, 'c': 3 }), true); - assert.strictEqual(matches({ 'b': 2 }), false); - }); - - it('should not change `_.matches` behavior if `source` is modified', function() { - var sources = [ - { 'a': { 'b': 2, 'c': 3 } }, - { 'a': 1, 'b': 2 }, - { 'a': 1 } - ]; - - lodashStable.each(sources, function(source, index) { - var object = lodashStable.cloneDeep(source), - matches = _.iteratee(source); - - assert.strictEqual(matches(object), true); - - if (index) { - source.a = 2; - source.b = 1; - source.c = 3; - } else { - source.a.b = 1; - source.a.c = 2; - source.a.d = 3; - } - assert.strictEqual(matches(object), true); - assert.strictEqual(matches(source), false); - }); - }); - - it('should return an iteratee created by `_.matchesProperty` when `func` is an array', function() { - var array = ['a', undefined], - matches = _.iteratee([0, 'a']); - - assert.strictEqual(matches(array), true); - - matches = _.iteratee(['0', 'a']); - assert.strictEqual(matches(array), true); - - matches = _.iteratee([1, undefined]); - assert.strictEqual(matches(array), true); - }); - - it('should support deep paths for `_.matchesProperty` shorthands', function() { - var object = { 'a': { 'b': { 'c': 1, 'd': 2 } } }, - matches = _.iteratee(['a.b', { 'c': 1 }]); - - assert.strictEqual(matches(object), true); - }); - - it('should not change `_.matchesProperty` behavior if `source` is modified', function() { - var sources = [ - { 'a': { 'b': 2, 'c': 3 } }, - { 'a': 1, 'b': 2 }, - { 'a': 1 } - ]; - - lodashStable.each(sources, function(source, index) { - var object = { 'a': lodashStable.cloneDeep(source) }, - matches = _.iteratee(['a', source]); - - assert.strictEqual(matches(object), true); - - if (index) { - source.a = 2; - source.b = 1; - source.c = 3; - } else { - source.a.b = 1; - source.a.c = 2; - source.a.d = 3; - } - assert.strictEqual(matches(object), true); - assert.strictEqual(matches({ 'a': source }), false); - }); - }); - - it('should return an iteratee created by `_.property` when `func` is a number or string', function() { - var array = ['a'], - prop = _.iteratee(0); - - assert.strictEqual(prop(array), 'a'); - - prop = _.iteratee('0'); - assert.strictEqual(prop(array), 'a'); - }); - - it('should support deep paths for `_.property` shorthands', function() { - var object = { 'a': { 'b': 2 } }, - prop = _.iteratee('a.b'); - - assert.strictEqual(prop(object), 2); - }); - - it('should work with functions created by `_.partial` and `_.partialRight`', function() { - var fn = function() { - var result = [this.a]; - push.apply(result, arguments); - return result; - }; - - var expected = [1, 2, 3], - object = { 'a': 1 , 'iteratee': _.iteratee(partial(fn, 2)) }; - - assert.deepStrictEqual(object.iteratee(3), expected); - - object.iteratee = _.iteratee(partialRight(fn, 3)); - assert.deepStrictEqual(object.iteratee(2), expected); - }); - - it('should use internal `iteratee` if external is unavailable', function() { - var iteratee = _.iteratee; - delete _.iteratee; - - assert.deepStrictEqual(map([{ 'a': 1 }], 'a'), [1]); - - _.iteratee = iteratee; - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var fn = function() { return this instanceof Number; }, - array = [fn, fn, fn], - iteratees = lodashStable.map(array, _.iteratee), - expected = lodashStable.map(array, stubFalse); - - var actual = lodashStable.map(iteratees, function(iteratee) { - return iteratee(); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/iteratee.spec.ts b/test/iteratee.spec.ts new file mode 100644 index 000000000..acf72203e --- /dev/null +++ b/test/iteratee.spec.ts @@ -0,0 +1,161 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, _, isNpm, push, stubFalse } from './utils'; +import partial from '../src/partial'; +import partialRight from '../src/partialRight'; +import map from '../src/map'; + +describe('iteratee', () => { + it('should provide arguments to `func`', () => { + const fn = function () { + return slice.call(arguments); + }, + iteratee = _.iteratee(fn), + actual = iteratee('a', 'b', 'c', 'd', 'e', 'f'); + + assert.deepStrictEqual(actual, ['a', 'b', 'c', 'd', 'e', 'f']); + }); + + it('should return `_.identity` when `func` is nullish', () => { + const object = {}, + values = [, null, undefined], + expected = lodashStable.map( + values, + lodashStable.constant([!isNpm && _.identity, object]), + ); + + const actual = lodashStable.map(values, (value, index) => { + const identity = index ? _.iteratee(value) : _.iteratee(); + return [!isNpm && identity, identity(object)]; + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return an iteratee created by `_.matches` when `func` is an object', () => { + const matches = _.iteratee({ a: 1, b: 2 }); + assert.strictEqual(matches({ a: 1, b: 2, c: 3 }), true); + assert.strictEqual(matches({ b: 2 }), false); + }); + + it('should not change `_.matches` behavior if `source` is modified', () => { + const sources = [{ a: { b: 2, c: 3 } }, { a: 1, b: 2 }, { a: 1 }]; + + lodashStable.each(sources, (source, index) => { + const object = lodashStable.cloneDeep(source), + matches = _.iteratee(source); + + assert.strictEqual(matches(object), true); + + if (index) { + source.a = 2; + source.b = 1; + source.c = 3; + } else { + source.a.b = 1; + source.a.c = 2; + source.a.d = 3; + } + assert.strictEqual(matches(object), true); + assert.strictEqual(matches(source), false); + }); + }); + + it('should return an iteratee created by `_.matchesProperty` when `func` is an array', () => { + let array = ['a', undefined], + matches = _.iteratee([0, 'a']); + + assert.strictEqual(matches(array), true); + + matches = _.iteratee(['0', 'a']); + assert.strictEqual(matches(array), true); + + matches = _.iteratee([1, undefined]); + assert.strictEqual(matches(array), true); + }); + + it('should support deep paths for `_.matchesProperty` shorthands', () => { + const object = { a: { b: { c: 1, d: 2 } } }, + matches = _.iteratee(['a.b', { c: 1 }]); + + assert.strictEqual(matches(object), true); + }); + + it('should not change `_.matchesProperty` behavior if `source` is modified', () => { + const sources = [{ a: { b: 2, c: 3 } }, { a: 1, b: 2 }, { a: 1 }]; + + lodashStable.each(sources, (source, index) => { + const object = { a: lodashStable.cloneDeep(source) }, + matches = _.iteratee(['a', source]); + + assert.strictEqual(matches(object), true); + + if (index) { + source.a = 2; + source.b = 1; + source.c = 3; + } else { + source.a.b = 1; + source.a.c = 2; + source.a.d = 3; + } + assert.strictEqual(matches(object), true); + assert.strictEqual(matches({ a: source }), false); + }); + }); + + it('should return an iteratee created by `_.property` when `func` is a number or string', () => { + let array = ['a'], + prop = _.iteratee(0); + + assert.strictEqual(prop(array), 'a'); + + prop = _.iteratee('0'); + assert.strictEqual(prop(array), 'a'); + }); + + it('should support deep paths for `_.property` shorthands', () => { + const object = { a: { b: 2 } }, + prop = _.iteratee('a.b'); + + assert.strictEqual(prop(object), 2); + }); + + it('should work with functions created by `_.partial` and `_.partialRight`', () => { + const fn = function () { + const result = [this.a]; + push.apply(result, arguments); + return result; + }; + + const expected = [1, 2, 3], + object = { a: 1, iteratee: _.iteratee(partial(fn, 2)) }; + + assert.deepStrictEqual(object.iteratee(3), expected); + + object.iteratee = _.iteratee(partialRight(fn, 3)); + assert.deepStrictEqual(object.iteratee(2), expected); + }); + + it('should use internal `iteratee` if external is unavailable', () => { + const iteratee = _.iteratee; + delete _.iteratee; + + assert.deepStrictEqual(map([{ a: 1 }], 'a'), [1]); + + _.iteratee = iteratee; + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const fn = function () { + return this instanceof Number; + }, + array = [fn, fn, fn], + iteratees = lodashStable.map(array, _.iteratee), + expected = lodashStable.map(array, stubFalse); + + const actual = lodashStable.map(iteratees, (iteratee) => iteratee()); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/iteration-methods.js b/test/iteration-methods.js deleted file mode 100644 index 67c73e821..000000000 --- a/test/iteration-methods.js +++ /dev/null @@ -1,340 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, slice, isNpm, noop, MAX_SAFE_INTEGER, stubTrue } from './utils.js'; - -describe('iteration methods', function() { - var methods = [ - '_baseEach', - 'countBy', - 'every', - 'filter', - 'find', - 'findIndex', - 'findKey', - 'findLast', - 'findLastIndex', - 'findLastKey', - 'forEach', - 'forEachRight', - 'forIn', - 'forInRight', - 'forOwn', - 'forOwnRight', - 'groupBy', - 'keyBy', - 'map', - 'mapKeys', - 'mapValues', - 'maxBy', - 'minBy', - 'omitBy', - 'partition', - 'pickBy', - 'reject', - 'some' - ]; - - var arrayMethods = [ - 'findIndex', - 'findLastIndex', - 'maxBy', - 'minBy' - ]; - - var collectionMethods = [ - '_baseEach', - 'countBy', - 'every', - 'filter', - 'find', - 'findLast', - 'forEach', - 'forEachRight', - 'groupBy', - 'keyBy', - 'map', - 'partition', - 'reduce', - 'reduceRight', - 'reject', - 'some' - ]; - - var forInMethods = [ - 'forIn', - 'forInRight', - 'omitBy', - 'pickBy' - ]; - - var iterationMethods = [ - '_baseEach', - 'forEach', - 'forEachRight', - 'forIn', - 'forInRight', - 'forOwn', - 'forOwnRight' - ]; - - var objectMethods = [ - 'findKey', - 'findLastKey', - 'forIn', - 'forInRight', - 'forOwn', - 'forOwnRight', - 'mapKeys', - 'mapValues', - 'omitBy', - 'pickBy' - ]; - - var rightMethods = [ - 'findLast', - 'findLastIndex', - 'findLastKey', - 'forEachRight', - 'forInRight', - 'forOwnRight' - ]; - - var unwrappedMethods = [ - 'each', - 'eachRight', - 'every', - 'find', - 'findIndex', - 'findKey', - 'findLast', - 'findLastIndex', - 'findLastKey', - 'forEach', - 'forEachRight', - 'forIn', - 'forInRight', - 'forOwn', - 'forOwnRight', - 'max', - 'maxBy', - 'min', - 'minBy', - 'some' - ]; - - lodashStable.each(methods, function(methodName) { - var array = [1, 2, 3], - func = _[methodName], - isBy = /(^partition|By)$/.test(methodName), - isFind = /^find/.test(methodName), - isOmitPick = /^(?:omit|pick)By$/.test(methodName), - isSome = methodName == 'some'; - - it('`_.' + methodName + '` should provide correct iteratee arguments', function() { - if (func) { - var args, - expected = [1, 0, array]; - - func(array, function() { - args || (args = slice.call(arguments)); - }); - - if (lodashStable.includes(rightMethods, methodName)) { - expected[0] = 3; - expected[1] = 2; - } - if (lodashStable.includes(objectMethods, methodName)) { - expected[1] += ''; - } - if (isBy) { - expected.length = isOmitPick ? 2 : 1; - } - assert.deepStrictEqual(args, expected); - } - }); - - it('`_.' + methodName + '` should treat sparse arrays as dense', function() { - if (func) { - var array = [1]; - array[2] = 3; - - var expected = lodashStable.includes(objectMethods, methodName) - ? [[1, '0', array], [undefined, '1', array], [3, '2', array]] - : [[1, 0, array], [undefined, 1, array], [3, 2, array]]; - - if (isBy) { - expected = lodashStable.map(expected, function(args) { - return args.slice(0, isOmitPick ? 2 : 1); - }); - } - else if (lodashStable.includes(objectMethods, methodName)) { - expected = lodashStable.map(expected, function(args) { - args[1] += ''; - return args; - }); - } - if (lodashStable.includes(rightMethods, methodName)) { - expected.reverse(); - } - var argsList = []; - func(array, function() { - argsList.push(slice.call(arguments)); - return !(isFind || isSome); - }); - - assert.deepStrictEqual(argsList, expected); - } - }); - }); - - lodashStable.each(lodashStable.difference(methods, objectMethods), function(methodName) { - var array = [1, 2, 3], - func = _[methodName], - isEvery = methodName == 'every'; - - array.a = 1; - - it('`_.' + methodName + '` should not iterate custom properties on arrays', function() { - if (func) { - var keys = []; - func(array, function(value, key) { - keys.push(key); - return isEvery; - }); - - assert.ok(!lodashStable.includes(keys, 'a')); - } - }); - }); - - lodashStable.each(lodashStable.difference(methods, unwrappedMethods), function(methodName) { - var array = [1, 2, 3], - isBaseEach = methodName == '_baseEach'; - - it('`_.' + methodName + '` should return a wrapped value when implicitly chaining', function() { - if (!(isBaseEach || isNpm)) { - var wrapped = _(array)[methodName](noop); - assert.ok(wrapped instanceof _); - } - }); - }); - - lodashStable.each(unwrappedMethods, function(methodName) { - var array = [1, 2, 3]; - - it('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function() { - var actual = _(array)[methodName](noop); - assert.notOk(actual instanceof _); - }); - - it('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function() { - var wrapped = _(array).chain(), - actual = wrapped[methodName](noop); - - assert.ok(actual instanceof _); - assert.notStrictEqual(actual, wrapped); - }); - }); - - lodashStable.each(lodashStable.difference(methods, arrayMethods, forInMethods), function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` iterates over own string keyed properties of objects', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - if (func) { - var values = []; - func(new Foo, function(value) { values.push(value); }); - assert.deepStrictEqual(values, [1]); - } - }); - }); - - lodashStable.each(iterationMethods, function(methodName) { - var array = [1, 2, 3], - func = _[methodName]; - - it('`_.' + methodName + '` should return the collection', function() { - if (func) { - assert.strictEqual(func(array, Boolean), array); - } - }); - }); - - lodashStable.each(collectionMethods, function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should use `isArrayLike` to determine whether a value is array-like', function() { - if (func) { - var isIteratedAsObject = function(object) { - var result = false; - func(object, function() { result = true; }, 0); - return result; - }; - - var values = [-1, '1', 1.1, Object(1), MAX_SAFE_INTEGER + 1], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(length) { - return isIteratedAsObject({ 'length': length }); - }); - - var Foo = function(a) {}; - Foo.a = 1; - - assert.deepStrictEqual(actual, expected); - assert.ok(isIteratedAsObject(Foo)); - assert.ok(!isIteratedAsObject({ 'length': 0 })); - } - }); - }); - - lodashStable.each(methods, function(methodName) { - var func = _[methodName], - isFind = /^find/.test(methodName), - isSome = methodName == 'some', - isReduce = /^reduce/.test(methodName); - - it('`_.' + methodName + '` should ignore changes to `length`', function() { - if (func) { - var count = 0, - array = [1]; - - func(array, function() { - if (++count == 1) { - array.push(2); - } - return !(isFind || isSome); - }, isReduce ? array : null); - - assert.strictEqual(count, 1); - } - }); - }); - - lodashStable.each(lodashStable.difference(lodashStable.union(methods, collectionMethods), arrayMethods), function(methodName) { - var func = _[methodName], - isFind = /^find/.test(methodName), - isSome = methodName == 'some', - isReduce = /^reduce/.test(methodName); - - it('`_.' + methodName + '` should ignore added `object` properties', function() { - if (func) { - var count = 0, - object = { 'a': 1 }; - - func(object, function() { - if (++count == 1) { - object.b = 2; - } - return !(isFind || isSome); - }, isReduce ? object : null); - - assert.strictEqual(count, 1); - } - }); - }); -}); diff --git a/test/iteration-methods.spec.ts b/test/iteration-methods.spec.ts new file mode 100644 index 000000000..15fdf3a58 --- /dev/null +++ b/test/iteration-methods.spec.ts @@ -0,0 +1,359 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, slice, isNpm, noop, MAX_SAFE_INTEGER, stubTrue } from './utils'; + +describe('iteration methods', () => { + const methods = [ + '_baseEach', + 'countBy', + 'every', + 'filter', + 'find', + 'findIndex', + 'findKey', + 'findLast', + 'findLastIndex', + 'findLastKey', + 'forEach', + 'forEachRight', + 'forIn', + 'forInRight', + 'forOwn', + 'forOwnRight', + 'groupBy', + 'keyBy', + 'map', + 'mapKeys', + 'mapValues', + 'maxBy', + 'minBy', + 'omitBy', + 'partition', + 'pickBy', + 'reject', + 'some', + ]; + + const arrayMethods = ['findIndex', 'findLastIndex', 'maxBy', 'minBy']; + + const collectionMethods = [ + '_baseEach', + 'countBy', + 'every', + 'filter', + 'find', + 'findLast', + 'forEach', + 'forEachRight', + 'groupBy', + 'keyBy', + 'map', + 'partition', + 'reduce', + 'reduceRight', + 'reject', + 'some', + ]; + + const forInMethods = ['forIn', 'forInRight', 'omitBy', 'pickBy']; + + const iterationMethods = [ + '_baseEach', + 'forEach', + 'forEachRight', + 'forIn', + 'forInRight', + 'forOwn', + 'forOwnRight', + ]; + + const objectMethods = [ + 'findKey', + 'findLastKey', + 'forIn', + 'forInRight', + 'forOwn', + 'forOwnRight', + 'mapKeys', + 'mapValues', + 'omitBy', + 'pickBy', + ]; + + const rightMethods = [ + 'findLast', + 'findLastIndex', + 'findLastKey', + 'forEachRight', + 'forInRight', + 'forOwnRight', + ]; + + const unwrappedMethods = [ + 'each', + 'eachRight', + 'every', + 'find', + 'findIndex', + 'findKey', + 'findLast', + 'findLastIndex', + 'findLastKey', + 'forEach', + 'forEachRight', + 'forIn', + 'forInRight', + 'forOwn', + 'forOwnRight', + 'max', + 'maxBy', + 'min', + 'minBy', + 'some', + ]; + + lodashStable.each(methods, (methodName) => { + const array = [1, 2, 3], + func = _[methodName], + isBy = /(^partition|By)$/.test(methodName), + isFind = /^find/.test(methodName), + isOmitPick = /^(?:omit|pick)By$/.test(methodName), + isSome = methodName == 'some'; + + it(`\`_.${methodName}\` should provide correct iteratee arguments`, () => { + if (func) { + let args, + expected = [1, 0, array]; + + func(array, function () { + args || (args = slice.call(arguments)); + }); + + if (lodashStable.includes(rightMethods, methodName)) { + expected[0] = 3; + expected[1] = 2; + } + if (lodashStable.includes(objectMethods, methodName)) { + expected[1] += ''; + } + if (isBy) { + expected.length = isOmitPick ? 2 : 1; + } + assert.deepStrictEqual(args, expected); + } + }); + + it(`\`_.${methodName}\` should treat sparse arrays as dense`, () => { + if (func) { + const array = [1]; + array[2] = 3; + + let expected = lodashStable.includes(objectMethods, methodName) + ? [ + [1, '0', array], + [undefined, '1', array], + [3, '2', array], + ] + : [ + [1, 0, array], + [undefined, 1, array], + [3, 2, array], + ]; + + if (isBy) { + expected = lodashStable.map(expected, (args) => + args.slice(0, isOmitPick ? 2 : 1), + ); + } else if (lodashStable.includes(objectMethods, methodName)) { + expected = lodashStable.map(expected, (args) => { + args[1] += ''; + return args; + }); + } + if (lodashStable.includes(rightMethods, methodName)) { + expected.reverse(); + } + const argsList = []; + func(array, function () { + argsList.push(slice.call(arguments)); + return !(isFind || isSome); + }); + + assert.deepStrictEqual(argsList, expected); + } + }); + }); + + lodashStable.each(lodashStable.difference(methods, objectMethods), (methodName) => { + const array = [1, 2, 3], + func = _[methodName], + isEvery = methodName == 'every'; + + array.a = 1; + + it(`\`_.${methodName}\` should not iterate custom properties on arrays`, () => { + if (func) { + const keys = []; + func(array, (value, key) => { + keys.push(key); + return isEvery; + }); + + assert.ok(!lodashStable.includes(keys, 'a')); + } + }); + }); + + lodashStable.each(lodashStable.difference(methods, unwrappedMethods), (methodName) => { + const array = [1, 2, 3], + isBaseEach = methodName == '_baseEach'; + + it(`\`_.${methodName}\` should return a wrapped value when implicitly chaining`, () => { + if (!(isBaseEach || isNpm)) { + const wrapped = _(array)[methodName](noop); + assert.ok(wrapped instanceof _); + } + }); + }); + + lodashStable.each(unwrappedMethods, (methodName) => { + const array = [1, 2, 3]; + + it(`\`_.${methodName}\` should return an unwrapped value when implicitly chaining`, () => { + const actual = _(array)[methodName](noop); + assert.notOk(actual instanceof _); + }); + + it(`\`_.${methodName}\` should return a wrapped value when explicitly chaining`, () => { + const wrapped = _(array).chain(), + actual = wrapped[methodName](noop); + + assert.ok(actual instanceof _); + assert.notStrictEqual(actual, wrapped); + }); + }); + + lodashStable.each( + lodashStable.difference(methods, arrayMethods, forInMethods), + (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` iterates over own string keyed properties of objects`, () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + if (func) { + const values = []; + func(new Foo(), (value) => { + values.push(value); + }); + assert.deepStrictEqual(values, [1]); + } + }); + }, + ); + + lodashStable.each(iterationMethods, (methodName) => { + const array = [1, 2, 3], + func = _[methodName]; + + it(`\`_.${methodName}\` should return the collection`, () => { + if (func) { + assert.strictEqual(func(array, Boolean), array); + } + }); + }); + + lodashStable.each(collectionMethods, (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should use \`isArrayLike\` to determine whether a value is array-like`, () => { + if (func) { + const isIteratedAsObject = function (object) { + let result = false; + func( + object, + () => { + result = true; + }, + 0, + ); + return result; + }; + + const values = [-1, '1', 1.1, Object(1), MAX_SAFE_INTEGER + 1], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (length) => + isIteratedAsObject({ length: length }), + ); + + const Foo = function (a) {}; + Foo.a = 1; + + assert.deepStrictEqual(actual, expected); + assert.ok(isIteratedAsObject(Foo)); + assert.ok(!isIteratedAsObject({ length: 0 })); + } + }); + }); + + lodashStable.each(methods, (methodName) => { + const func = _[methodName], + isFind = /^find/.test(methodName), + isSome = methodName == 'some', + isReduce = /^reduce/.test(methodName); + + it(`\`_.${methodName}\` should ignore changes to \`length\``, () => { + if (func) { + let count = 0, + array = [1]; + + func( + array, + () => { + if (++count == 1) { + array.push(2); + } + return !(isFind || isSome); + }, + isReduce ? array : null, + ); + + assert.strictEqual(count, 1); + } + }); + }); + + lodashStable.each( + lodashStable.difference(lodashStable.union(methods, collectionMethods), arrayMethods), + (methodName) => { + const func = _[methodName], + isFind = /^find/.test(methodName), + isSome = methodName == 'some', + isReduce = /^reduce/.test(methodName); + + it(`\`_.${methodName}\` should ignore added \`object\` properties`, () => { + if (func) { + let count = 0, + object = { a: 1 }; + + func( + object, + () => { + if (++count == 1) { + object.b = 2; + } + return !(isFind || isSome); + }, + isReduce ? object : null, + ); + + assert.strictEqual(count, 1); + } + }); + }, + ); +}); diff --git a/test/join.js b/test/join.js deleted file mode 100644 index a8f672f8b..000000000 --- a/test/join.js +++ /dev/null @@ -1,20 +0,0 @@ -import assert from 'assert'; -import join from '../join.js'; - -describe('join', function() { - var array = ['a', 'b', 'c']; - - it('should return join all array elements into a string', function() { - assert.strictEqual(join(array, '~'), 'a~b~c'); - }); - - it('should return an unwrapped value when implicitly chaining', function() { - var wrapped = _(array); - assert.strictEqual(wrapped.join('~'), 'a~b~c'); - assert.strictEqual(wrapped.value(), array); - }); - - it('should return a wrapped value when explicitly chaining', function() { - assert.ok(_(array).chain().join('~') instanceof _); - }); -}); diff --git a/test/join.spec.ts b/test/join.spec.ts new file mode 100644 index 000000000..3cd69bd15 --- /dev/null +++ b/test/join.spec.ts @@ -0,0 +1,20 @@ +import assert from 'node:assert'; +import join from '../src/join'; + +describe('join', () => { + const array = ['a', 'b', 'c']; + + it('should return join all array elements into a string', () => { + assert.strictEqual(join(array, '~'), 'a~b~c'); + }); + + it('should return an unwrapped value when implicitly chaining', () => { + const wrapped = _(array); + assert.strictEqual(wrapped.join('~'), 'a~b~c'); + assert.strictEqual(wrapped.value(), array); + }); + + it('should return a wrapped value when explicitly chaining', () => { + assert.ok(_(array).chain().join('~') instanceof _); + }); +}); diff --git a/test/keyBy.js b/test/keyBy.js deleted file mode 100644 index 997c1015b..000000000 --- a/test/keyBy.js +++ /dev/null @@ -1,76 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE } from './utils.js'; -import keyBy from '../keyBy.js'; - -describe('keyBy', function() { - var array = [ - { 'dir': 'left', 'code': 97 }, - { 'dir': 'right', 'code': 100 } - ]; - - it('should transform keys by `iteratee`', function() { - var expected = { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }; - - var actual = keyBy(array, function(object) { - return String.fromCharCode(object.code); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var array = [4, 6, 6], - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant({ '4': 4, '6': 6 })); - - var actual = lodashStable.map(values, function(value, index) { - return index ? keyBy(array, value) : keyBy(array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `_.property` shorthands', function() { - var expected = { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }, - actual = keyBy(array, 'dir'); - - assert.deepStrictEqual(actual, expected); - }); - - it('should only add values to own, not inherited, properties', function() { - var actual = keyBy([6.1, 4.2, 6.3], function(n) { - return Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor'; - }); - - assert.deepStrictEqual(actual.constructor, 4.2); - assert.deepStrictEqual(actual.hasOwnProperty, 6.3); - }); - - it('should work with a number for `iteratee`', function() { - var array = [ - [1, 'a'], - [2, 'a'], - [2, 'b'] - ]; - - assert.deepStrictEqual(keyBy(array, 0), { '1': [1, 'a'], '2': [2, 'b'] }); - assert.deepStrictEqual(keyBy(array, 1), { 'a': [2, 'a'], 'b': [2, 'b'] }); - }); - - it('should work with an object for `collection`', function() { - var actual = keyBy({ 'a': 6.1, 'b': 4.2, 'c': 6.3 }, Math.floor); - assert.deepStrictEqual(actual, { '4': 4.2, '6': 6.3 }); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE).concat( - lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), - lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE) - ); - - var actual = _(array).keyBy().map(square).filter(isEven).take().value(); - - assert.deepEqual(actual, _.take(_.filter(_.map(keyBy(array), square), isEven))); - }); -}); diff --git a/test/keyBy.spec.ts b/test/keyBy.spec.ts new file mode 100644 index 000000000..1fc0f78ef --- /dev/null +++ b/test/keyBy.spec.ts @@ -0,0 +1,76 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE } from './utils'; +import keyBy from '../src/keyBy'; + +describe('keyBy', () => { + const array = [ + { dir: 'left', code: 97 }, + { dir: 'right', code: 100 }, + ]; + + it('should transform keys by `iteratee`', () => { + const expected = { a: { dir: 'left', code: 97 }, d: { dir: 'right', code: 100 } }; + + const actual = keyBy(array, (object) => String.fromCharCode(object.code)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const array = [4, 6, 6], + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant({ '4': 4, '6': 6 })); + + const actual = lodashStable.map(values, (value, index) => + index ? keyBy(array, value) : keyBy(array), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `_.property` shorthands', () => { + const expected = { left: { dir: 'left', code: 97 }, right: { dir: 'right', code: 100 } }, + actual = keyBy(array, 'dir'); + + assert.deepStrictEqual(actual, expected); + }); + + it('should only add values to own, not inherited, properties', () => { + const actual = keyBy([6.1, 4.2, 6.3], (n) => + Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor', + ); + + assert.deepStrictEqual(actual.constructor, 4.2); + assert.deepStrictEqual(actual.hasOwnProperty, 6.3); + }); + + it('should work with a number for `iteratee`', () => { + const array = [ + [1, 'a'], + [2, 'a'], + [2, 'b'], + ]; + + assert.deepStrictEqual(keyBy(array, 0), { '1': [1, 'a'], '2': [2, 'b'] }); + assert.deepStrictEqual(keyBy(array, 1), { a: [2, 'a'], b: [2, 'b'] }); + }); + + it('should work with an object for `collection`', () => { + const actual = keyBy({ a: 6.1, b: 4.2, c: 6.3 }, Math.floor); + assert.deepStrictEqual(actual, { '4': 4.2, '6': 6.3 }); + }); + + it('should work in a lazy sequence', () => { + const array = lodashStable + .range(LARGE_ARRAY_SIZE) + .concat( + lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), + lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE), + ); + + const actual = _(array).keyBy().map(square).filter(isEven).take().value(); + + assert.deepEqual(actual, _.take(_.filter(_.map(keyBy(array), square), isEven))); + }); +}); diff --git a/test/keys-methods.js b/test/keys-methods.js deleted file mode 100644 index e45e9b320..000000000 --- a/test/keys-methods.js +++ /dev/null @@ -1,183 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - _, - arrayProto, - args, - strictArgs, - objectProto, - stringProto, - primitives, - numberProto, - stubArray, -} from './utils.js'; - -describe('keys methods', function() { - lodashStable.each(['keys', 'keysIn'], function(methodName) { - var func = _[methodName], - isKeys = methodName == 'keys'; - - it('`_.' + methodName + '` should return the string keyed property names of `object`', function() { - var actual = func({ 'a': 1, 'b': 1 }).sort(); - - assert.deepStrictEqual(actual, ['a', 'b']); - }); - - it('`_.' + methodName + '` should ' + (isKeys ? 'not ' : '') + 'include inherited string keyed properties', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var expected = isKeys ? ['a'] : ['a', 'b'], - actual = func(new Foo).sort(); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should treat sparse arrays as dense', function() { - var array = [1]; - array[2] = 3; - - var actual = func(array).sort(); - - assert.deepStrictEqual(actual, ['0', '1', '2']); - }); - - it('`_.' + methodName + '` should return keys for custom properties on arrays', function() { - var array = [1]; - array.a = 1; - - var actual = func(array).sort(); - - assert.deepStrictEqual(actual, ['0', 'a']); - }); - - it('`_.' + methodName + '` should ' + (isKeys ? 'not ' : '') + 'include inherited string keyed properties of arrays', function() { - arrayProto.a = 1; - - var expected = isKeys ? ['0'] : ['0', 'a'], - actual = func([1]).sort(); - - assert.deepStrictEqual(actual, expected); - - delete arrayProto.a; - }); - - it('`_.' + methodName + '` should work with `arguments` objects', function() { - var values = [args, strictArgs], - expected = lodashStable.map(values, lodashStable.constant(['0', '1', '2'])); - - var actual = lodashStable.map(values, function(value) { - return func(value).sort(); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return keys for custom properties on `arguments` objects', function() { - var values = [args, strictArgs], - expected = lodashStable.map(values, lodashStable.constant(['0', '1', '2', 'a'])); - - var actual = lodashStable.map(values, function(value) { - value.a = 1; - var result = func(value).sort(); - delete value.a; - return result; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should ' + (isKeys ? 'not ' : '') + 'include inherited string keyed properties of `arguments` objects', function() { - var values = [args, strictArgs], - expected = lodashStable.map(values, lodashStable.constant(isKeys ? ['0', '1', '2'] : ['0', '1', '2', 'a'])); - - var actual = lodashStable.map(values, function(value) { - objectProto.a = 1; - var result = func(value).sort(); - delete objectProto.a; - return result; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with string objects', function() { - var actual = func(Object('abc')).sort(); - - assert.deepStrictEqual(actual, ['0', '1', '2']); - }); - - it('`_.' + methodName + '` should return keys for custom properties on string objects', function() { - var object = Object('a'); - object.a = 1; - - var actual = func(object).sort(); - - assert.deepStrictEqual(actual, ['0', 'a']); - }); - - it('`_.' + methodName + '` should ' + (isKeys ? 'not ' : '') + 'include inherited string keyed properties of string objects', function() { - stringProto.a = 1; - - var expected = isKeys ? ['0'] : ['0', 'a'], - actual = func(Object('a')).sort(); - - assert.deepStrictEqual(actual, expected); - - delete stringProto.a; - }); - - it('`_.' + methodName + '` should work with array-like objects', function() { - var object = { '0': 'a', 'length': 1 }, - actual = func(object).sort(); - - assert.deepStrictEqual(actual, ['0', 'length']); - }); - - it('`_.' + methodName + '` should coerce primitives to objects (test in IE 9)', function() { - var expected = lodashStable.map(primitives, function(value) { - return typeof value === 'string' ? ['0'] : []; - }); - - var actual = lodashStable.map(primitives, func); - assert.deepStrictEqual(actual, expected); - - // IE 9 doesn't box numbers in for-in loops. - numberProto.a = 1; - assert.deepStrictEqual(func(0), isKeys ? [] : ['a']); - delete numberProto.a; - }); - - it('`_.' + methodName + '` skips the `constructor` property on prototype objects', function() { - function Foo() {} - Foo.prototype.a = 1; - - var expected = ['a']; - assert.deepStrictEqual(func(Foo.prototype), expected); - - Foo.prototype = { 'constructor': Foo, 'a': 1 }; - assert.deepStrictEqual(func(Foo.prototype), expected); - - var Fake = { 'prototype': {} }; - Fake.prototype.constructor = Fake; - assert.deepStrictEqual(func(Fake.prototype), ['constructor']); - }); - - it('`_.' + methodName + '` should return an empty array when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubArray); - - var actual = lodashStable.map(values, function(value, index) { - objectProto.a = 1; - var result = index ? func(value) : func(); - delete objectProto.a; - return result; - }); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/keys-methods.spec.ts b/test/keys-methods.spec.ts new file mode 100644 index 000000000..d025882c6 --- /dev/null +++ b/test/keys-methods.spec.ts @@ -0,0 +1,192 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + _, + arrayProto, + args, + strictArgs, + objectProto, + stringProto, + primitives, + numberProto, + stubArray, +} from './utils'; + +describe('keys methods', () => { + lodashStable.each(['keys', 'keysIn'], (methodName) => { + const func = _[methodName], + isKeys = methodName == 'keys'; + + it(`\`_.${methodName}\` should return the string keyed property names of \`object\``, () => { + const actual = func({ a: 1, b: 1 }).sort(); + + assert.deepStrictEqual(actual, ['a', 'b']); + }); + + it(`\`_.${methodName}\` should ${ + isKeys ? 'not ' : '' + }include inherited string keyed properties`, () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const expected = isKeys ? ['a'] : ['a', 'b'], + actual = func(new Foo()).sort(); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should treat sparse arrays as dense`, () => { + const array = [1]; + array[2] = 3; + + const actual = func(array).sort(); + + assert.deepStrictEqual(actual, ['0', '1', '2']); + }); + + it(`\`_.${methodName}\` should return keys for custom properties on arrays`, () => { + const array = [1]; + array.a = 1; + + const actual = func(array).sort(); + + assert.deepStrictEqual(actual, ['0', 'a']); + }); + + it(`\`_.${methodName}\` should ${ + isKeys ? 'not ' : '' + }include inherited string keyed properties of arrays`, () => { + arrayProto.a = 1; + + const expected = isKeys ? ['0'] : ['0', 'a'], + actual = func([1]).sort(); + + assert.deepStrictEqual(actual, expected); + + delete arrayProto.a; + }); + + it(`\`_.${methodName}\` should work with \`arguments\` objects`, () => { + const values = [args, strictArgs], + expected = lodashStable.map(values, lodashStable.constant(['0', '1', '2'])); + + const actual = lodashStable.map(values, (value) => func(value).sort()); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return keys for custom properties on \`arguments\` objects`, () => { + const values = [args, strictArgs], + expected = lodashStable.map(values, lodashStable.constant(['0', '1', '2', 'a'])); + + const actual = lodashStable.map(values, (value) => { + value.a = 1; + const result = func(value).sort(); + delete value.a; + return result; + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should ${ + isKeys ? 'not ' : '' + }include inherited string keyed properties of \`arguments\` objects`, () => { + const values = [args, strictArgs], + expected = lodashStable.map( + values, + lodashStable.constant(isKeys ? ['0', '1', '2'] : ['0', '1', '2', 'a']), + ); + + const actual = lodashStable.map(values, (value) => { + objectProto.a = 1; + const result = func(value).sort(); + delete objectProto.a; + return result; + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with string objects`, () => { + const actual = func(Object('abc')).sort(); + + assert.deepStrictEqual(actual, ['0', '1', '2']); + }); + + it(`\`_.${methodName}\` should return keys for custom properties on string objects`, () => { + const object = Object('a'); + object.a = 1; + + const actual = func(object).sort(); + + assert.deepStrictEqual(actual, ['0', 'a']); + }); + + it(`\`_.${methodName}\` should ${ + isKeys ? 'not ' : '' + }include inherited string keyed properties of string objects`, () => { + stringProto.a = 1; + + const expected = isKeys ? ['0'] : ['0', 'a'], + actual = func(Object('a')).sort(); + + assert.deepStrictEqual(actual, expected); + + delete stringProto.a; + }); + + it(`\`_.${methodName}\` should work with array-like objects`, () => { + const object = { '0': 'a', length: 1 }, + actual = func(object).sort(); + + assert.deepStrictEqual(actual, ['0', 'length']); + }); + + it(`\`_.${methodName}\` should coerce primitives to objects (test in IE 9)`, () => { + const expected = lodashStable.map(primitives, (value) => + typeof value === 'string' ? ['0'] : [], + ); + + const actual = lodashStable.map(primitives, func); + assert.deepStrictEqual(actual, expected); + + // IE 9 doesn't box numbers in for-in loops. + numberProto.a = 1; + assert.deepStrictEqual(func(0), isKeys ? [] : ['a']); + delete numberProto.a; + }); + + it(`\`_.${methodName}\` skips the \`constructor\` property on prototype objects`, () => { + function Foo() {} + Foo.prototype.a = 1; + + const expected = ['a']; + assert.deepStrictEqual(func(Foo.prototype), expected); + + Foo.prototype = { constructor: Foo, a: 1 }; + assert.deepStrictEqual(func(Foo.prototype), expected); + + const Fake = { prototype: {} }; + Fake.prototype.constructor = Fake; + assert.deepStrictEqual(func(Fake.prototype), ['constructor']); + }); + + it(`\`_.${methodName}\` should return an empty array when \`object\` is nullish`, () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubArray); + + const actual = lodashStable.map(values, (value, index) => { + objectProto.a = 1; + const result = index ? func(value) : func(); + delete objectProto.a; + return result; + }); + + assert.deepStrictEqual(actual, expected); + }); + }); +}); diff --git a/test/last.js b/test/last.js deleted file mode 100644 index fef570ec9..000000000 --- a/test/last.js +++ /dev/null @@ -1,51 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE } from './utils.js'; -import last from '../last.js'; - -describe('last', function() { - var array = [1, 2, 3, 4]; - - it('should return the last element', function() { - assert.strictEqual(last(array), 4); - }); - - it('should return `undefined` when querying empty arrays', function() { - var array = []; - array['-1'] = 1; - - assert.strictEqual(last([]), undefined); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = lodashStable.map(array, last); - - assert.deepStrictEqual(actual, [3, 6, 9]); - }); - - it('should return an unwrapped value when implicitly chaining', function() { - assert.strictEqual(_(array).last(), 4); - }); - - it('should return a wrapped value when explicitly chaining', function() { - assert.ok(_(array).chain().last() instanceof _); - }); - - it('should not execute immediately when explicitly chaining', function() { - var wrapped = _(array).chain().last(); - assert.strictEqual(wrapped.__wrapped__, array); - }); - - it('should work in a lazy sequence', function() { - var largeArray = lodashStable.range(LARGE_ARRAY_SIZE), - smallArray = array; - - lodashStable.times(2, function(index) { - var array = index ? largeArray : smallArray, - wrapped = _(array).filter(isEven); - - assert.strictEqual(wrapped.last(), last(_.filter(array, isEven))); - }); - }); -}); diff --git a/test/last.spec.ts b/test/last.spec.ts new file mode 100644 index 000000000..b99bf6452 --- /dev/null +++ b/test/last.spec.ts @@ -0,0 +1,55 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE } from './utils'; +import last from '../src/last'; + +describe('last', () => { + const array = [1, 2, 3, 4]; + + it('should return the last element', () => { + assert.strictEqual(last(array), 4); + }); + + it('should return `undefined` when querying empty arrays', () => { + const array = []; + array['-1'] = 1; + + assert.strictEqual(last([]), undefined); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + actual = lodashStable.map(array, last); + + assert.deepStrictEqual(actual, [3, 6, 9]); + }); + + it('should return an unwrapped value when implicitly chaining', () => { + assert.strictEqual(_(array).last(), 4); + }); + + it('should return a wrapped value when explicitly chaining', () => { + assert.ok(_(array).chain().last() instanceof _); + }); + + it('should not execute immediately when explicitly chaining', () => { + const wrapped = _(array).chain().last(); + assert.strictEqual(wrapped.__wrapped__, array); + }); + + it('should work in a lazy sequence', () => { + const largeArray = lodashStable.range(LARGE_ARRAY_SIZE), + smallArray = array; + + lodashStable.times(2, (index) => { + const array = index ? largeArray : smallArray, + wrapped = _(array).filter(isEven); + + assert.strictEqual(wrapped.last(), last(_.filter(array, isEven))); + }); + }); +}); diff --git a/test/lodash(...)-methods-that-return-new-wrapped-values.js b/test/lodash(...)-methods-that-return-new-wrapped-values.js deleted file mode 100644 index b66c54c60..000000000 --- a/test/lodash(...)-methods-that-return-new-wrapped-values.js +++ /dev/null @@ -1,45 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -describe('lodash(...) methods that return new wrapped values', function() { - var funcs = [ - 'castArray', - 'concat', - 'difference', - 'differenceBy', - 'differenceWith', - 'intersection', - 'intersectionBy', - 'intersectionWith', - 'pull', - 'pullAll', - 'pullAt', - 'sampleSize', - 'shuffle', - 'slice', - 'splice', - 'split', - 'toArray', - 'union', - 'unionBy', - 'unionWith', - 'uniq', - 'uniqBy', - 'uniqWith', - 'words', - 'xor', - 'xorBy', - 'xorWith' - ]; - - lodashStable.each(funcs, function(methodName) { - it('`_(...).' + methodName + '` should return a new wrapped value', function() { - var value = methodName == 'split' ? 'abc' : [1, 2, 3], - wrapped = _(value), - actual = wrapped[methodName](); - - assert.ok(actual instanceof _); - assert.notStrictEqual(actual, wrapped); - }); - }); -}); diff --git a/test/lodash(...)-methods-that-return-new-wrapped-values.spec.ts b/test/lodash(...)-methods-that-return-new-wrapped-values.spec.ts new file mode 100644 index 000000000..af782e6ba --- /dev/null +++ b/test/lodash(...)-methods-that-return-new-wrapped-values.spec.ts @@ -0,0 +1,45 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +describe('lodash(...) methods that return new wrapped values', () => { + const funcs = [ + 'castArray', + 'concat', + 'difference', + 'differenceBy', + 'differenceWith', + 'intersection', + 'intersectionBy', + 'intersectionWith', + 'pull', + 'pullAll', + 'pullAt', + 'sampleSize', + 'shuffle', + 'slice', + 'splice', + 'split', + 'toArray', + 'union', + 'unionBy', + 'unionWith', + 'uniq', + 'uniqBy', + 'uniqWith', + 'words', + 'xor', + 'xorBy', + 'xorWith', + ]; + + lodashStable.each(funcs, (methodName) => { + it(`\`_(...).${methodName}\` should return a new wrapped value`, () => { + const value = methodName == 'split' ? 'abc' : [1, 2, 3], + wrapped = _(value), + actual = wrapped[methodName](); + + assert.ok(actual instanceof _); + assert.notStrictEqual(actual, wrapped); + }); + }); +}); diff --git a/test/lodash(...)-methods-that-return-the-wrapped-modified-array.js b/test/lodash(...)-methods-that-return-the-wrapped-modified-array.js deleted file mode 100644 index d58eeff84..000000000 --- a/test/lodash(...)-methods-that-return-the-wrapped-modified-array.js +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -describe('lodash(...) methods that return the wrapped modified array', function() { - var funcs = [ - 'push', - 'reverse', - 'sort', - 'unshift' - ]; - - lodashStable.each(funcs, function(methodName) { - it('`_(...).' + methodName + '` should return a new wrapper', function() { - var array = [1, 2, 3], - wrapped = _(array), - actual = wrapped[methodName](); - - assert.ok(actual instanceof _); - assert.notStrictEqual(actual, wrapped); - }); - }); -}); diff --git a/test/lodash(...)-methods-that-return-the-wrapped-modified-array.spec.ts b/test/lodash(...)-methods-that-return-the-wrapped-modified-array.spec.ts new file mode 100644 index 000000000..f59bf8092 --- /dev/null +++ b/test/lodash(...)-methods-that-return-the-wrapped-modified-array.spec.ts @@ -0,0 +1,17 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +describe('lodash(...) methods that return the wrapped modified array', () => { + const funcs = ['push', 'reverse', 'sort', 'unshift']; + + lodashStable.each(funcs, (methodName) => { + it(`\`_(...).${methodName}\` should return a new wrapper`, () => { + const array = [1, 2, 3], + wrapped = _(array), + actual = wrapped[methodName](); + + assert.ok(actual instanceof _); + assert.notStrictEqual(actual, wrapped); + }); + }); +}); diff --git a/test/lodash(...)-methods-that-return-unwrapped-values.js b/test/lodash(...)-methods-that-return-unwrapped-values.js deleted file mode 100644 index 7b906e1ed..000000000 --- a/test/lodash(...)-methods-that-return-unwrapped-values.js +++ /dev/null @@ -1,112 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -describe('lodash(...) methods that return unwrapped values', function() { - var funcs = [ - 'add', - 'camelCase', - 'capitalize', - 'ceil', - 'clone', - 'deburr', - 'defaultTo', - 'divide', - 'endsWith', - 'escape', - 'escapeRegExp', - 'every', - 'find', - 'floor', - 'has', - 'hasIn', - 'head', - 'includes', - 'isArguments', - 'isArray', - 'isArrayBuffer', - 'isArrayLike', - 'isBoolean', - 'isBuffer', - 'isDate', - 'isElement', - 'isEmpty', - 'isEqual', - 'isError', - 'isFinite', - 'isFunction', - 'isInteger', - 'isMap', - 'isNaN', - 'isNative', - 'isNil', - 'isNull', - 'isNumber', - 'isObject', - 'isObjectLike', - 'isPlainObject', - 'isRegExp', - 'isSafeInteger', - 'isSet', - 'isString', - 'isUndefined', - 'isWeakMap', - 'isWeakSet', - 'join', - 'kebabCase', - 'last', - 'lowerCase', - 'lowerFirst', - 'max', - 'maxBy', - 'min', - 'minBy', - 'multiply', - 'nth', - 'pad', - 'padEnd', - 'padStart', - 'parseInt', - 'pop', - 'random', - 'reduce', - 'reduceRight', - 'repeat', - 'replace', - 'round', - 'sample', - 'shift', - 'size', - 'snakeCase', - 'some', - 'startCase', - 'startsWith', - 'subtract', - 'sum', - 'toFinite', - 'toInteger', - 'toLower', - 'toNumber', - 'toSafeInteger', - 'toString', - 'toUpper', - 'trim', - 'trimEnd', - 'trimStart', - 'truncate', - 'unescape', - 'upperCase', - 'upperFirst' - ]; - - lodashStable.each(funcs, function(methodName) { - it('`_(...).' + methodName + '` should return an unwrapped value when implicitly chaining', function() { - var actual = _()[methodName](); - assert.notOk(actual instanceof _); - }); - - it('`_(...).' + methodName + '` should return a wrapped value when explicitly chaining', function() { - var actual = _().chain()[methodName](); - assert.ok(actual instanceof _); - }); - }); -}); diff --git a/test/lodash(...)-methods-that-return-unwrapped-values.spec.ts b/test/lodash(...)-methods-that-return-unwrapped-values.spec.ts new file mode 100644 index 000000000..1136a72ec --- /dev/null +++ b/test/lodash(...)-methods-that-return-unwrapped-values.spec.ts @@ -0,0 +1,112 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +describe('lodash(...) methods that return unwrapped values', () => { + const funcs = [ + 'add', + 'camelCase', + 'capitalize', + 'ceil', + 'clone', + 'deburr', + 'defaultTo', + 'divide', + 'endsWith', + 'escape', + 'escapeRegExp', + 'every', + 'find', + 'floor', + 'has', + 'hasIn', + 'head', + 'includes', + 'isArguments', + 'isArray', + 'isArrayBuffer', + 'isArrayLike', + 'isBoolean', + 'isBuffer', + 'isDate', + 'isElement', + 'isEmpty', + 'isEqual', + 'isError', + 'isFinite', + 'isFunction', + 'isInteger', + 'isMap', + 'isNaN', + 'isNative', + 'isNil', + 'isNull', + 'isNumber', + 'isObject', + 'isObjectLike', + 'isPlainObject', + 'isRegExp', + 'isSafeInteger', + 'isSet', + 'isString', + 'isUndefined', + 'isWeakMap', + 'isWeakSet', + 'join', + 'kebabCase', + 'last', + 'lowerCase', + 'lowerFirst', + 'max', + 'maxBy', + 'min', + 'minBy', + 'multiply', + 'nth', + 'pad', + 'padEnd', + 'padStart', + 'parseInt', + 'pop', + 'random', + 'reduce', + 'reduceRight', + 'repeat', + 'replace', + 'round', + 'sample', + 'shift', + 'size', + 'snakeCase', + 'some', + 'startCase', + 'startsWith', + 'subtract', + 'sum', + 'toFinite', + 'toInteger', + 'toLower', + 'toNumber', + 'toSafeInteger', + 'toString', + 'toUpper', + 'trim', + 'trimEnd', + 'trimStart', + 'truncate', + 'unescape', + 'upperCase', + 'upperFirst', + ]; + + lodashStable.each(funcs, (methodName) => { + it(`\`_(...).${methodName}\` should return an unwrapped value when implicitly chaining`, () => { + const actual = _()[methodName](); + assert.notOk(actual instanceof _); + }); + + it(`\`_(...).${methodName}\` should return a wrapped value when explicitly chaining`, () => { + const actual = _().chain()[methodName](); + assert.ok(actual instanceof _); + }); + }); +}); diff --git a/test/lodash(...).commit.js b/test/lodash(...).commit.js deleted file mode 100644 index 94a7acb08..000000000 --- a/test/lodash(...).commit.js +++ /dev/null @@ -1,21 +0,0 @@ -import assert from 'assert'; - -describe('lodash(...).commit', function() { - it('should execute the chained sequence and returns the wrapped result', function() { - var array = [1], - wrapped = _(array).push(2).push(3); - - assert.deepEqual(array, [1]); - - var otherWrapper = wrapped.commit(); - assert.ok(otherWrapper instanceof _); - assert.deepEqual(otherWrapper.value(), [1, 2, 3]); - assert.deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); - }); - - it('should track the `__chain__` value of a wrapper', function() { - var wrapped = _([1]).chain().commit().head(); - assert.ok(wrapped instanceof _); - assert.strictEqual(wrapped.value(), 1); - }); -}); diff --git a/test/lodash(...).commit.spec.ts b/test/lodash(...).commit.spec.ts new file mode 100644 index 000000000..9f8f524d3 --- /dev/null +++ b/test/lodash(...).commit.spec.ts @@ -0,0 +1,21 @@ +import assert from 'node:assert'; + +describe('lodash(...).commit', () => { + it('should execute the chained sequence and returns the wrapped result', () => { + const array = [1], + wrapped = _(array).push(2).push(3); + + assert.deepEqual(array, [1]); + + const otherWrapper = wrapped.commit(); + assert.ok(otherWrapper instanceof _); + assert.deepEqual(otherWrapper.value(), [1, 2, 3]); + assert.deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); + }); + + it('should track the `__chain__` value of a wrapper', () => { + const wrapped = _([1]).chain().commit().head(); + assert.ok(wrapped instanceof _); + assert.strictEqual(wrapped.value(), 1); + }); +}); diff --git a/test/lodash(...).next.js b/test/lodash(...).next.js deleted file mode 100644 index e3019ba35..000000000 --- a/test/lodash(...).next.js +++ /dev/null @@ -1,74 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, isNpm, LARGE_ARRAY_SIZE, isEven } from './utils.js'; -import toArray from '../toArray.js'; -import filter from '../filter.js'; - -describe('lodash(...).next', function() { - lodashStable.each([false, true], function(implicit) { - function chain(value) { - return implicit ? _(value) : _.chain(value); - } - - var chainType = 'in an ' + (implicit ? 'implicit' : 'explict') + ' chain'; - - it('should follow the iterator protocol ' + chainType, function() { - var wrapped = chain([1, 2]); - - assert.deepEqual(wrapped.next(), { 'done': false, 'value': 1 }); - assert.deepEqual(wrapped.next(), { 'done': false, 'value': 2 }); - assert.deepEqual(wrapped.next(), { 'done': true, 'value': undefined }); - }); - - it('should act as an iterable ' + chainType, function() { - if (!isNpm && Symbol && Symbol.iterator) { - var array = [1, 2], - wrapped = chain(array); - - assert.strictEqual(wrapped[Symbol.iterator](), wrapped); - assert.deepStrictEqual(lodashStable.toArray(wrapped), array); - } - }); - - it('should use `_.toArray` to generate the iterable result ' + chainType, function() { - if (!isNpm && Array.from) { - var hearts = '\ud83d\udc95', - values = [[1], { 'a': 1 }, hearts]; - - lodashStable.each(values, function(value) { - var wrapped = chain(value); - assert.deepStrictEqual(Array.from(wrapped), toArray(value)); - }); - } - }); - - it('should reset the iterator correctly ' + chainType, function() { - if (!isNpm && Symbol && Symbol.iterator) { - var array = [1, 2], - wrapped = chain(array); - - assert.deepStrictEqual(lodashStable.toArray(wrapped), array); - assert.deepStrictEqual(lodashStable.toArray(wrapped), [], 'produces an empty array for exhausted iterator'); - - var other = wrapped.filter(); - assert.deepStrictEqual(lodashStable.toArray(other), array, 'reset for new chain segments'); - assert.deepStrictEqual(lodashStable.toArray(wrapped), [], 'iterator is still exhausted'); - } - }); - - it('should work in a lazy sequence ' + chainType, function() { - if (!isNpm && Symbol && Symbol.iterator) { - var array = lodashStable.range(LARGE_ARRAY_SIZE), - predicate = function(value) { values.push(value); return isEven(value); }, - values = [], - wrapped = chain(array); - - assert.deepStrictEqual(lodashStable.toArray(wrapped), array); - - wrapped = wrapped.filter(predicate); - assert.deepStrictEqual(lodashStable.toArray(wrapped), filter(array, isEven), 'reset for new lazy chain segments'); - assert.deepStrictEqual(values, array, 'memoizes iterator values'); - } - }); - }); -}); diff --git a/test/lodash(...).next.spec.ts b/test/lodash(...).next.spec.ts new file mode 100644 index 000000000..74d8a3246 --- /dev/null +++ b/test/lodash(...).next.spec.ts @@ -0,0 +1,93 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, isNpm, LARGE_ARRAY_SIZE, isEven } from './utils'; +import toArray from '../src/toArray'; +import filter from '../src/filter'; + +describe('lodash(...).next', () => { + lodashStable.each([false, true], (implicit) => { + function chain(value) { + return implicit ? _(value) : _.chain(value); + } + + const chainType = `in an ${implicit ? 'implicit' : 'explict'} chain`; + + it(`should follow the iterator protocol ${chainType}`, () => { + const wrapped = chain([1, 2]); + + assert.deepEqual(wrapped.next(), { done: false, value: 1 }); + assert.deepEqual(wrapped.next(), { done: false, value: 2 }); + assert.deepEqual(wrapped.next(), { done: true, value: undefined }); + }); + + it(`should act as an iterable ${chainType}`, () => { + if (!isNpm && Symbol && Symbol.iterator) { + const array = [1, 2], + wrapped = chain(array); + + assert.strictEqual(wrapped[Symbol.iterator](), wrapped); + assert.deepStrictEqual(lodashStable.toArray(wrapped), array); + } + }); + + it(`should use \`_.toArray\` to generate the iterable result ${chainType}`, () => { + if (!isNpm && Array.from) { + const hearts = '\ud83d\udc95', + values = [[1], { a: 1 }, hearts]; + + lodashStable.each(values, (value) => { + const wrapped = chain(value); + assert.deepStrictEqual(Array.from(wrapped), toArray(value)); + }); + } + }); + + it(`should reset the iterator correctly ${chainType}`, () => { + if (!isNpm && Symbol && Symbol.iterator) { + const array = [1, 2], + wrapped = chain(array); + + assert.deepStrictEqual(lodashStable.toArray(wrapped), array); + assert.deepStrictEqual( + lodashStable.toArray(wrapped), + [], + 'produces an empty array for exhausted iterator', + ); + + const other = wrapped.filter(); + assert.deepStrictEqual( + lodashStable.toArray(other), + array, + 'reset for new chain segments', + ); + assert.deepStrictEqual( + lodashStable.toArray(wrapped), + [], + 'iterator is still exhausted', + ); + } + }); + + it(`should work in a lazy sequence ${chainType}`, () => { + if (!isNpm && Symbol && Symbol.iterator) { + var array = lodashStable.range(LARGE_ARRAY_SIZE), + predicate = function (value) { + values.push(value); + return isEven(value); + }, + values = [], + wrapped = chain(array); + + assert.deepStrictEqual(lodashStable.toArray(wrapped), array); + + wrapped = wrapped.filter(predicate); + assert.deepStrictEqual( + lodashStable.toArray(wrapped), + filter(array, isEven), + 'reset for new lazy chain segments', + ); + assert.deepStrictEqual(values, array, 'memoizes iterator values'); + } + }); + }); +}); diff --git a/test/lodash(...).plant.js b/test/lodash(...).plant.js deleted file mode 100644 index 191eecaa3..000000000 --- a/test/lodash(...).plant.js +++ /dev/null @@ -1,39 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { square, isNpm } from './utils.js'; -import compact from '../compact.js'; - -describe('lodash(...).plant', function() { - it('should clone the chained sequence planting `value` as the wrapped value', function() { - var array1 = [5, null, 3, null, 1], - array2 = [10, null, 8, null, 6], - wrapped1 = _(array1).thru(compact).map(square).takeRight(2).sort(), - wrapped2 = wrapped1.plant(array2); - - assert.deepEqual(wrapped2.value(), [36, 64]); - assert.deepEqual(wrapped1.value(), [1, 9]); - }); - - it('should clone `chainAll` settings', function() { - var array1 = [2, 4], - array2 = [6, 8], - wrapped1 = _(array1).chain().map(square), - wrapped2 = wrapped1.plant(array2); - - assert.deepEqual(wrapped2.head().value(), 36); - }); - - it('should reset iterator data on cloned sequences', function() { - if (!isNpm && Symbol && Symbol.iterator) { - var array1 = [2, 4], - array2 = [6, 8], - wrapped1 = _(array1).map(square); - - assert.deepStrictEqual(lodashStable.toArray(wrapped1), [4, 16]); - assert.deepStrictEqual(lodashStable.toArray(wrapped1), []); - - var wrapped2 = wrapped1.plant(array2); - assert.deepStrictEqual(lodashStable.toArray(wrapped2), [36, 64]); - } - }); -}); diff --git a/test/lodash(...).plant.spec.ts b/test/lodash(...).plant.spec.ts new file mode 100644 index 000000000..279ae3d44 --- /dev/null +++ b/test/lodash(...).plant.spec.ts @@ -0,0 +1,39 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { square, isNpm } from './utils'; +import compact from '../src/compact'; + +describe('lodash(...).plant', () => { + it('should clone the chained sequence planting `value` as the wrapped value', () => { + const array1 = [5, null, 3, null, 1], + array2 = [10, null, 8, null, 6], + wrapped1 = _(array1).thru(compact).map(square).takeRight(2).sort(), + wrapped2 = wrapped1.plant(array2); + + assert.deepEqual(wrapped2.value(), [36, 64]); + assert.deepEqual(wrapped1.value(), [1, 9]); + }); + + it('should clone `chainAll` settings', () => { + const array1 = [2, 4], + array2 = [6, 8], + wrapped1 = _(array1).chain().map(square), + wrapped2 = wrapped1.plant(array2); + + assert.deepEqual(wrapped2.head().value(), 36); + }); + + it('should reset iterator data on cloned sequences', () => { + if (!isNpm && Symbol && Symbol.iterator) { + const array1 = [2, 4], + array2 = [6, 8], + wrapped1 = _(array1).map(square); + + assert.deepStrictEqual(lodashStable.toArray(wrapped1), [4, 16]); + assert.deepStrictEqual(lodashStable.toArray(wrapped1), []); + + const wrapped2 = wrapped1.plant(array2); + assert.deepStrictEqual(lodashStable.toArray(wrapped2), [36, 64]); + } + }); +}); diff --git a/test/lodash(...).pop.js b/test/lodash(...).pop.js deleted file mode 100644 index a06c0cb27..000000000 --- a/test/lodash(...).pop.js +++ /dev/null @@ -1,31 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubTrue } from './utils.js'; - -describe('lodash(...).pop', function() { - it('should remove elements from the end of `array`', function() { - var array = [1, 2], - wrapped = _(array); - - assert.strictEqual(wrapped.pop(), 2); - assert.deepEqual(wrapped.value(), [1]); - assert.strictEqual(wrapped.pop(), 1); - - var actual = wrapped.value(); - assert.strictEqual(actual, array); - assert.deepEqual(actual, []); - }); - - it('should accept falsey arguments', function() { - var expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(value, index) { - try { - var result = index ? _(value).pop() : _().pop(); - return result === undefined; - } catch (e) {} - }); - - assert.deepEqual(actual, expected); - }); -}); diff --git a/test/lodash(...).pop.spec.ts b/test/lodash(...).pop.spec.ts new file mode 100644 index 000000000..ffd087331 --- /dev/null +++ b/test/lodash(...).pop.spec.ts @@ -0,0 +1,31 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubTrue } from './utils'; + +describe('lodash(...).pop', () => { + it('should remove elements from the end of `array`', () => { + const array = [1, 2], + wrapped = _(array); + + assert.strictEqual(wrapped.pop(), 2); + assert.deepEqual(wrapped.value(), [1]); + assert.strictEqual(wrapped.pop(), 1); + + const actual = wrapped.value(); + assert.strictEqual(actual, array); + assert.deepEqual(actual, []); + }); + + it('should accept falsey arguments', () => { + const expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (value, index) => { + try { + const result = index ? _(value).pop() : _().pop(); + return result === undefined; + } catch (e) {} + }); + + assert.deepEqual(actual, expected); + }); +}); diff --git a/test/lodash(...).push.js b/test/lodash(...).push.js deleted file mode 100644 index f29b124cb..000000000 --- a/test/lodash(...).push.js +++ /dev/null @@ -1,27 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubTrue } from './utils.js'; - -describe('lodash(...).push', function() { - it('should append elements to `array`', function() { - var array = [1], - wrapped = _(array).push(2, 3), - actual = wrapped.value(); - - assert.strictEqual(actual, array); - assert.deepEqual(actual, [1, 2, 3]); - }); - - it('should accept falsey arguments', function() { - var expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(value, index) { - try { - var result = index ? _(value).push(1).value() : _().push(1).value(); - return lodashStable.eq(result, value); - } catch (e) {} - }); - - assert.deepEqual(actual, expected); - }); -}); diff --git a/test/lodash(...).push.spec.ts b/test/lodash(...).push.spec.ts new file mode 100644 index 000000000..ea85a3200 --- /dev/null +++ b/test/lodash(...).push.spec.ts @@ -0,0 +1,27 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubTrue } from './utils'; + +describe('lodash(...).push', () => { + it('should append elements to `array`', () => { + const array = [1], + wrapped = _(array).push(2, 3), + actual = wrapped.value(); + + assert.strictEqual(actual, array); + assert.deepEqual(actual, [1, 2, 3]); + }); + + it('should accept falsey arguments', () => { + const expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (value, index) => { + try { + const result = index ? _(value).push(1).value() : _().push(1).value(); + return lodashStable.eq(result, value); + } catch (e) {} + }); + + assert.deepEqual(actual, expected); + }); +}); diff --git a/test/lodash(...).shift.js b/test/lodash(...).shift.js deleted file mode 100644 index b6920283a..000000000 --- a/test/lodash(...).shift.js +++ /dev/null @@ -1,31 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubTrue } from './utils.js'; - -describe('lodash(...).shift', function() { - it('should remove elements from the front of `array`', function() { - var array = [1, 2], - wrapped = _(array); - - assert.strictEqual(wrapped.shift(), 1); - assert.deepEqual(wrapped.value(), [2]); - assert.strictEqual(wrapped.shift(), 2); - - var actual = wrapped.value(); - assert.strictEqual(actual, array); - assert.deepEqual(actual, []); - }); - - it('should accept falsey arguments', function() { - var expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(value, index) { - try { - var result = index ? _(value).shift() : _().shift(); - return result === undefined; - } catch (e) {} - }); - - assert.deepEqual(actual, expected); - }); -}); diff --git a/test/lodash(...).shift.spec.ts b/test/lodash(...).shift.spec.ts new file mode 100644 index 000000000..964a571b2 --- /dev/null +++ b/test/lodash(...).shift.spec.ts @@ -0,0 +1,31 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubTrue } from './utils'; + +describe('lodash(...).shift', () => { + it('should remove elements from the front of `array`', () => { + const array = [1, 2], + wrapped = _(array); + + assert.strictEqual(wrapped.shift(), 1); + assert.deepEqual(wrapped.value(), [2]); + assert.strictEqual(wrapped.shift(), 2); + + const actual = wrapped.value(); + assert.strictEqual(actual, array); + assert.deepEqual(actual, []); + }); + + it('should accept falsey arguments', () => { + const expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (value, index) => { + try { + const result = index ? _(value).shift() : _().shift(); + return result === undefined; + } catch (e) {} + }); + + assert.deepEqual(actual, expected); + }); +}); diff --git a/test/lodash(...).sort.js b/test/lodash(...).sort.js deleted file mode 100644 index e10d5f5a2..000000000 --- a/test/lodash(...).sort.js +++ /dev/null @@ -1,27 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubTrue } from './utils.js'; - -describe('lodash(...).sort', function() { - it('should return the wrapped sorted `array`', function() { - var array = [3, 1, 2], - wrapped = _(array).sort(), - actual = wrapped.value(); - - assert.strictEqual(actual, array); - assert.deepEqual(actual, [1, 2, 3]); - }); - - it('should accept falsey arguments', function() { - var expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(value, index) { - try { - var result = index ? _(value).sort().value() : _().sort().value(); - return lodashStable.eq(result, value); - } catch (e) {} - }); - - assert.deepEqual(actual, expected); - }); -}); diff --git a/test/lodash(...).sort.spec.ts b/test/lodash(...).sort.spec.ts new file mode 100644 index 000000000..f9a932fde --- /dev/null +++ b/test/lodash(...).sort.spec.ts @@ -0,0 +1,27 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubTrue } from './utils'; + +describe('lodash(...).sort', () => { + it('should return the wrapped sorted `array`', () => { + const array = [3, 1, 2], + wrapped = _(array).sort(), + actual = wrapped.value(); + + assert.strictEqual(actual, array); + assert.deepEqual(actual, [1, 2, 3]); + }); + + it('should accept falsey arguments', () => { + const expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (value, index) => { + try { + const result = index ? _(value).sort().value() : _().sort().value(); + return lodashStable.eq(result, value); + } catch (e) {} + }); + + assert.deepEqual(actual, expected); + }); +}); diff --git a/test/lodash(...).splice.js b/test/lodash(...).splice.js deleted file mode 100644 index 8e300b39d..000000000 --- a/test/lodash(...).splice.js +++ /dev/null @@ -1,31 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubTrue } from './utils.js'; - -describe('lodash(...).splice', function() { - it('should support removing and inserting elements', function() { - var array = [1, 2], - wrapped = _(array); - - assert.deepEqual(wrapped.splice(1, 1, 3).value(), [2]); - assert.deepEqual(wrapped.value(), [1, 3]); - assert.deepEqual(wrapped.splice(0, 2).value(), [1, 3]); - - var actual = wrapped.value(); - assert.strictEqual(actual, array); - assert.deepEqual(actual, []); - }); - - it('should accept falsey arguments', function() { - var expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(value, index) { - try { - var result = index ? _(value).splice(0, 1).value() : _().splice(0, 1).value(); - return lodashStable.isEqual(result, []); - } catch (e) {} - }); - - assert.deepEqual(actual, expected); - }); -}); diff --git a/test/lodash(...).splice.spec.ts b/test/lodash(...).splice.spec.ts new file mode 100644 index 000000000..841380e17 --- /dev/null +++ b/test/lodash(...).splice.spec.ts @@ -0,0 +1,31 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubTrue } from './utils'; + +describe('lodash(...).splice', () => { + it('should support removing and inserting elements', () => { + const array = [1, 2], + wrapped = _(array); + + assert.deepEqual(wrapped.splice(1, 1, 3).value(), [2]); + assert.deepEqual(wrapped.value(), [1, 3]); + assert.deepEqual(wrapped.splice(0, 2).value(), [1, 3]); + + const actual = wrapped.value(); + assert.strictEqual(actual, array); + assert.deepEqual(actual, []); + }); + + it('should accept falsey arguments', () => { + const expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (value, index) => { + try { + const result = index ? _(value).splice(0, 1).value() : _().splice(0, 1).value(); + return lodashStable.isEqual(result, []); + } catch (e) {} + }); + + assert.deepEqual(actual, expected); + }); +}); diff --git a/test/lodash(...).unshift.js b/test/lodash(...).unshift.js deleted file mode 100644 index f679c4fd8..000000000 --- a/test/lodash(...).unshift.js +++ /dev/null @@ -1,27 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubTrue } from './utils.js'; - -describe('lodash(...).unshift', function() { - it('should prepend elements to `array`', function() { - var array = [3], - wrapped = _(array).unshift(1, 2), - actual = wrapped.value(); - - assert.strictEqual(actual, array); - assert.deepEqual(actual, [1, 2, 3]); - }); - - it('should accept falsey arguments', function() { - var expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(value, index) { - try { - var result = index ? _(value).unshift(1).value() : _().unshift(1).value(); - return lodashStable.eq(result, value); - } catch (e) {} - }); - - assert.deepEqual(actual, expected); - }); -}); diff --git a/test/lodash(...).unshift.spec.ts b/test/lodash(...).unshift.spec.ts new file mode 100644 index 000000000..3d6d054ed --- /dev/null +++ b/test/lodash(...).unshift.spec.ts @@ -0,0 +1,27 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubTrue } from './utils'; + +describe('lodash(...).unshift', () => { + it('should prepend elements to `array`', () => { + const array = [3], + wrapped = _(array).unshift(1, 2), + actual = wrapped.value(); + + assert.strictEqual(actual, array); + assert.deepEqual(actual, [1, 2, 3]); + }); + + it('should accept falsey arguments', () => { + const expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (value, index) => { + try { + const result = index ? _(value).unshift(1).value() : _().unshift(1).value(); + return lodashStable.eq(result, value); + } catch (e) {} + }); + + assert.deepEqual(actual, expected); + }); +}); diff --git a/test/lodash(...).value.js b/test/lodash(...).value.js deleted file mode 100644 index a883d23fc..000000000 --- a/test/lodash(...).value.js +++ /dev/null @@ -1,33 +0,0 @@ -import assert from 'assert'; -import { isNpm } from './utils.js'; -import prototype from '../prototype.js'; - -describe('lodash(...).value', function() { - it('should execute the chained sequence and extract the unwrapped value', function() { - var array = [1], - wrapped = _(array).push(2).push(3); - - assert.deepEqual(array, [1]); - assert.deepEqual(wrapped.value(), [1, 2, 3]); - assert.deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); - assert.deepEqual(array, [1, 2, 3, 2, 3]); - }); - - it('should return the `valueOf` result of the wrapped value', function() { - var wrapped = _(123); - assert.strictEqual(Number(wrapped), 123); - }); - - it('should stringify the wrapped value when used by `JSON.stringify`', function() { - if (!isNpm && JSON) { - var wrapped = _([1, 2, 3]); - assert.strictEqual(JSON.stringify(wrapped), '[1,2,3]'); - } - }); - - it('should be aliased', function() { - var expected = prototype.value; - assert.strictEqual(prototype.toJSON, expected); - assert.strictEqual(prototype.valueOf, expected); - }); -}); diff --git a/test/lodash(...).value.spec.ts b/test/lodash(...).value.spec.ts new file mode 100644 index 000000000..043f2a2bf --- /dev/null +++ b/test/lodash(...).value.spec.ts @@ -0,0 +1,33 @@ +import assert from 'node:assert'; +import { isNpm } from './utils'; +import prototype from '../src/prototype'; + +describe('lodash(...).value', () => { + it('should execute the chained sequence and extract the unwrapped value', () => { + const array = [1], + wrapped = _(array).push(2).push(3); + + assert.deepEqual(array, [1]); + assert.deepEqual(wrapped.value(), [1, 2, 3]); + assert.deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); + assert.deepEqual(array, [1, 2, 3, 2, 3]); + }); + + it('should return the `valueOf` result of the wrapped value', () => { + const wrapped = _(123); + assert.strictEqual(Number(wrapped), 123); + }); + + it('should stringify the wrapped value when used by `JSON.stringify`', () => { + if (!isNpm && JSON) { + const wrapped = _([1, 2, 3]); + assert.strictEqual(JSON.stringify(wrapped), '[1,2,3]'); + } + }); + + it('should be aliased', () => { + const expected = prototype.value; + assert.strictEqual(prototype.toJSON, expected); + assert.strictEqual(prototype.valueOf, expected); + }); +}); diff --git a/test/lodash-constructor.js b/test/lodash-constructor.js deleted file mode 100644 index c59556eb7..000000000 --- a/test/lodash-constructor.js +++ /dev/null @@ -1,39 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { empties, stubTrue, isNpm, lodashBizarro } from './utils.js'; - -describe('lodash constructor', function() { - var values = empties.concat(true, 1, 'a'), - expected = lodashStable.map(values, stubTrue); - - it('should create a new instance when called without the `new` operator', function() { - var actual = lodashStable.map(values, function(value) { - return _(value) instanceof _; - }); - - assert.deepEqual(actual, expected); - }); - - it('should return the given `lodash` instances', function() { - var actual = lodashStable.map(values, function(value) { - var wrapped = _(value); - return _(wrapped) === wrapped; - }); - - assert.deepEqual(actual, expected); - }); - - it('should convert foreign wrapped values to `lodash` instances', function() { - if (!isNpm && lodashBizarro) { - var actual = lodashStable.map(values, function(value) { - var wrapped = _(lodashBizarro(value)), - unwrapped = wrapped.value(); - - return wrapped instanceof _ && - ((unwrapped === value) || (unwrapped !== unwrapped && value !== value)); - }); - - assert.deepStrictEqual(actual, expected); - } - }); -}); diff --git a/test/lodash-constructor.spec.ts b/test/lodash-constructor.spec.ts new file mode 100644 index 000000000..fb142b7a0 --- /dev/null +++ b/test/lodash-constructor.spec.ts @@ -0,0 +1,39 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { empties, stubTrue, isNpm, lodashBizarro } from './utils'; + +describe('lodash constructor', () => { + const values = empties.concat(true, 1, 'a'), + expected = lodashStable.map(values, stubTrue); + + it('should create a new instance when called without the `new` operator', () => { + const actual = lodashStable.map(values, (value) => _(value) instanceof _); + + assert.deepEqual(actual, expected); + }); + + it('should return the given `lodash` instances', () => { + const actual = lodashStable.map(values, (value) => { + const wrapped = _(value); + return _(wrapped) === wrapped; + }); + + assert.deepEqual(actual, expected); + }); + + it('should convert foreign wrapped values to `lodash` instances', () => { + if (!isNpm && lodashBizarro) { + const actual = lodashStable.map(values, (value) => { + const wrapped = _(lodashBizarro(value)), + unwrapped = wrapped.value(); + + return ( + wrapped instanceof _ && + (unwrapped === value || (unwrapped !== unwrapped && value !== value)) + ); + }); + + assert.deepStrictEqual(actual, expected); + } + }); +}); diff --git a/test/lodash-methods.js b/test/lodash-methods.js deleted file mode 100644 index 2a92a00ba..000000000 --- a/test/lodash-methods.js +++ /dev/null @@ -1,194 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, falsey, stubArray, oldDash, stubTrue, FUNC_ERROR_TEXT } from './utils.js'; -import functions from '../functions.js'; -import bind from '../bind.js'; - -describe('lodash methods', function() { - var allMethods = lodashStable.reject(functions(_).sort(), function(methodName) { - return lodashStable.startsWith(methodName, '_'); - }); - - var checkFuncs = [ - 'after', - 'ary', - 'before', - 'bind', - 'curry', - 'curryRight', - 'debounce', - 'defer', - 'delay', - 'flip', - 'flow', - 'flowRight', - 'memoize', - 'negate', - 'once', - 'partial', - 'partialRight', - 'rearg', - 'rest', - 'spread', - 'throttle', - 'unary' - ]; - - var noBinding = [ - 'flip', - 'memoize', - 'negate', - 'once', - 'overArgs', - 'partial', - 'partialRight', - 'rearg', - 'rest', - 'spread' - ]; - - var rejectFalsey = [ - 'tap', - 'thru' - ].concat(checkFuncs); - - var returnArrays = [ - 'at', - 'chunk', - 'compact', - 'difference', - 'drop', - 'filter', - 'flatten', - 'functions', - 'initial', - 'intersection', - 'invokeMap', - 'keys', - 'map', - 'orderBy', - 'pull', - 'pullAll', - 'pullAt', - 'range', - 'rangeRight', - 'reject', - 'remove', - 'shuffle', - 'sortBy', - 'tail', - 'take', - 'times', - 'toArray', - 'toPairs', - 'toPairsIn', - 'union', - 'uniq', - 'values', - 'without', - 'xor', - 'zip' - ]; - - var acceptFalsey = lodashStable.difference(allMethods, rejectFalsey); - - it('should accept falsey arguments', function() { - var arrays = lodashStable.map(falsey, stubArray); - - lodashStable.each(acceptFalsey, function(methodName) { - var expected = arrays, - func = _[methodName]; - - var actual = lodashStable.map(falsey, function(value, index) { - return index ? func(value) : func(); - }); - - if (methodName == 'noConflict') { - root._ = oldDash; - } - else if (methodName == 'pull' || methodName == 'pullAll') { - expected = falsey; - } - if (lodashStable.includes(returnArrays, methodName) && methodName != 'sample') { - assert.deepStrictEqual(actual, expected, '_.' + methodName + ' returns an array'); - } - assert.ok(true, '`_.' + methodName + '` accepts falsey arguments'); - }); - - // Skip tests for missing methods of modularized builds. - lodashStable.each(['chain', 'noConflict', 'runInContext'], function(methodName) { - if (!_[methodName]) {} - }); - }); - - it('should return an array', function() { - var array = [1, 2, 3]; - - lodashStable.each(returnArrays, function(methodName) { - var actual, - func = _[methodName]; - - switch (methodName) { - case 'invokeMap': - actual = func(array, 'toFixed'); - break; - case 'sample': - actual = func(array, 1); - break; - default: - actual = func(array); - } - assert.ok(lodashStable.isArray(actual), '_.' + methodName + ' returns an array'); - - var isPull = methodName == 'pull' || methodName == 'pullAll'; - assert.strictEqual(actual === array, isPull, '_.' + methodName + ' should ' + (isPull ? '' : 'not ') + 'return the given array'); - }); - }); - - it('should throw an error for falsey arguments', function() { - lodashStable.each(rejectFalsey, function(methodName) { - var expected = lodashStable.map(falsey, stubTrue), - func = _[methodName]; - - var actual = lodashStable.map(falsey, function(value, index) { - var pass = !index && /^(?:backflow|compose|cond|flow(Right)?|over(?:Every|Some)?)$/.test(methodName); - - try { - index ? func(value) : func(); - } catch (e) { - pass = !pass && (e instanceof TypeError) && - (!lodashStable.includes(checkFuncs, methodName) || (e.message == FUNC_ERROR_TEXT)); - } - return pass; - }); - - assert.deepStrictEqual(actual, expected, '`_.' + methodName + '` rejects falsey arguments'); - }); - }); - - it('should use `this` binding of function', function() { - lodashStable.each(noBinding, function(methodName) { - var fn = function() { return this.a; }, - func = _[methodName], - isNegate = methodName == 'negate', - object = { 'a': 1 }, - expected = isNegate ? false : 1; - - var wrapper = func(bind(fn, object)); - assert.strictEqual(wrapper(), expected, '`_.' + methodName + '` can consume a bound function'); - - wrapper = bind(func(fn), object); - assert.strictEqual(wrapper(), expected, '`_.' + methodName + '` can be bound'); - - object.wrapper = func(fn); - assert.strictEqual(object.wrapper(), expected, '`_.' + methodName + '` uses the `this` of its parent object'); - }); - }); - - it('should not contain minified method names (test production builds)', function() { - var shortNames = ['_', 'at', 'eq', 'gt', 'lt']; - assert.ok(lodashStable.every(functions(_), function(methodName) { - return methodName.length > 2 || lodashStable.includes(shortNames, methodName); - })); - }); -}); diff --git a/test/lodash-methods.spec.ts b/test/lodash-methods.spec.ts new file mode 100644 index 000000000..6ab7f638d --- /dev/null +++ b/test/lodash-methods.spec.ts @@ -0,0 +1,218 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, falsey, stubArray, oldDash, stubTrue, FUNC_ERROR_TEXT } from './utils'; +import functions from '../src/functions'; +import bind from '../src/bind'; + +describe('lodash methods', () => { + const allMethods = lodashStable.reject(functions(_).sort(), (methodName) => + lodashStable.startsWith(methodName, '_'), + ); + + const checkFuncs = [ + 'after', + 'ary', + 'before', + 'bind', + 'curry', + 'curryRight', + 'debounce', + 'defer', + 'delay', + 'flip', + 'flow', + 'flowRight', + 'memoize', + 'negate', + 'once', + 'partial', + 'partialRight', + 'rearg', + 'rest', + 'spread', + 'throttle', + 'unary', + ]; + + const noBinding = [ + 'flip', + 'memoize', + 'negate', + 'once', + 'overArgs', + 'partial', + 'partialRight', + 'rearg', + 'rest', + 'spread', + ]; + + const rejectFalsey = ['tap', 'thru'].concat(checkFuncs); + + const returnArrays = [ + 'at', + 'chunk', + 'compact', + 'difference', + 'drop', + 'filter', + 'flatten', + 'functions', + 'initial', + 'intersection', + 'invokeMap', + 'keys', + 'map', + 'orderBy', + 'pull', + 'pullAll', + 'pullAt', + 'range', + 'rangeRight', + 'reject', + 'remove', + 'shuffle', + 'sortBy', + 'tail', + 'take', + 'times', + 'toArray', + 'toPairs', + 'toPairsIn', + 'union', + 'uniq', + 'values', + 'without', + 'xor', + 'zip', + ]; + + const acceptFalsey = lodashStable.difference(allMethods, rejectFalsey); + + it('should accept falsey arguments', () => { + const arrays = lodashStable.map(falsey, stubArray); + + lodashStable.each(acceptFalsey, (methodName) => { + let expected = arrays, + func = _[methodName]; + + const actual = lodashStable.map(falsey, (value, index) => + index ? func(value) : func(), + ); + + if (methodName == 'noConflict') { + root._ = oldDash; + } else if (methodName == 'pull' || methodName == 'pullAll') { + expected = falsey; + } + if (lodashStable.includes(returnArrays, methodName) && methodName != 'sample') { + assert.deepStrictEqual(actual, expected, `_.${methodName} returns an array`); + } + assert.ok(true, `\`_.${methodName}\` accepts falsey arguments`); + }); + + // Skip tests for missing methods of modularized builds. + lodashStable.each(['chain', 'noConflict', 'runInContext'], (methodName) => { + if (!_[methodName]) { + } + }); + }); + + it('should return an array', () => { + const array = [1, 2, 3]; + + lodashStable.each(returnArrays, (methodName) => { + let actual, + func = _[methodName]; + + switch (methodName) { + case 'invokeMap': + actual = func(array, 'toFixed'); + break; + case 'sample': + actual = func(array, 1); + break; + default: + actual = func(array); + } + assert.ok(lodashStable.isArray(actual), `_.${methodName} returns an array`); + + const isPull = methodName == 'pull' || methodName == 'pullAll'; + assert.strictEqual( + actual === array, + isPull, + `_.${methodName} should ${isPull ? '' : 'not '}return the given array`, + ); + }); + }); + + it('should throw an error for falsey arguments', () => { + lodashStable.each(rejectFalsey, (methodName) => { + const expected = lodashStable.map(falsey, stubTrue), + func = _[methodName]; + + const actual = lodashStable.map(falsey, (value, index) => { + let pass = + !index && + /^(?:backflow|compose|cond|flow(Right)?|over(?:Every|Some)?)$/.test(methodName); + + try { + index ? func(value) : func(); + } catch (e) { + pass = + !pass && + e instanceof TypeError && + (!lodashStable.includes(checkFuncs, methodName) || + e.message == FUNC_ERROR_TEXT); + } + return pass; + }); + + assert.deepStrictEqual( + actual, + expected, + `\`_.${methodName}\` rejects falsey arguments`, + ); + }); + }); + + it('should use `this` binding of function', () => { + lodashStable.each(noBinding, (methodName) => { + const fn = function () { + return this.a; + }, + func = _[methodName], + isNegate = methodName == 'negate', + object = { a: 1 }, + expected = isNegate ? false : 1; + + let wrapper = func(bind(fn, object)); + assert.strictEqual( + wrapper(), + expected, + `\`_.${methodName}\` can consume a bound function`, + ); + + wrapper = bind(func(fn), object); + assert.strictEqual(wrapper(), expected, `\`_.${methodName}\` can be bound`); + + object.wrapper = func(fn); + assert.strictEqual( + object.wrapper(), + expected, + `\`_.${methodName}\` uses the \`this\` of its parent object`, + ); + }); + }); + + it('should not contain minified method names (test production builds)', () => { + const shortNames = ['_', 'at', 'eq', 'gt', 'lt']; + assert.ok( + lodashStable.every( + functions(_), + (methodName) => + methodName.length > 2 || lodashStable.includes(shortNames, methodName), + ), + ); + }); +}); diff --git a/test/lodash.methodName.js b/test/lodash.methodName.js deleted file mode 100644 index 632684595..000000000 --- a/test/lodash.methodName.js +++ /dev/null @@ -1,75 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, empties } from './utils.js'; - -lodashStable.each(['find', 'findIndex', 'findKey', 'findLast', 'findLastIndex', 'findLastKey'], function(methodName) { - describe('lodash.' + methodName); - - var array = [1, 2, 3, 4], - func = _[methodName]; - - var objects = [ - { 'a': 0, 'b': 0 }, - { 'a': 1, 'b': 1 }, - { 'a': 2, 'b': 2 } - ]; - - var expected = ({ - 'find': [objects[1], undefined, objects[2]], - 'findIndex': [1, -1, 2], - 'findKey': ['1', undefined, '2'], - 'findLast': [objects[2], undefined, objects[2]], - 'findLastIndex': [2, -1, 2], - 'findLastKey': ['2', undefined, '2'] - })[methodName]; - - it('`_.' + methodName + '` should return the found value', function() { - assert.strictEqual(func(objects, function(object) { return object.a; }), expected[0]); - }); - - it('`_.' + methodName + '` should return `' + expected[1] + '` if value is not found', function() { - assert.strictEqual(func(objects, function(object) { return object.a === 3; }), expected[1]); - }); - - it('`_.' + methodName + '` should work with `_.matches` shorthands', function() { - assert.strictEqual(func(objects, { 'b': 2 }), expected[2]); - }); - - it('`_.' + methodName + '` should work with `_.matchesProperty` shorthands', function() { - assert.strictEqual(func(objects, ['b', 2]), expected[2]); - }); - - it('`_.' + methodName + '` should work with `_.property` shorthands', function() { - assert.strictEqual(func(objects, 'b'), expected[0]); - }); - - it('`_.' + methodName + '` should return `' + expected[1] + '` for empty collections', function() { - var emptyValues = lodashStable.endsWith(methodName, 'Index') ? lodashStable.reject(empties, lodashStable.isPlainObject) : empties, - expecting = lodashStable.map(emptyValues, lodashStable.constant(expected[1])); - - var actual = lodashStable.map(emptyValues, function(value) { - try { - return func(value, { 'a': 3 }); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expecting); - }); - - it('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function() { - var expected = ({ - 'find': 1, - 'findIndex': 0, - 'findKey': '0', - 'findLast': 4, - 'findLastIndex': 3, - 'findLastKey': '3' - })[methodName]; - }); - - it('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function() {}); - - it('`_.' + methodName + '` should not execute immediately when explicitly chaining', function() {}); - - it('`_.' + methodName + '` should work in a lazy sequence', function() {}); -}); diff --git a/test/lodash.methodName.spec.ts b/test/lodash.methodName.spec.ts new file mode 100644 index 000000000..03069cce2 --- /dev/null +++ b/test/lodash.methodName.spec.ts @@ -0,0 +1,86 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, empties } from './utils'; + +lodashStable.each( + ['find', 'findIndex', 'findKey', 'findLast', 'findLastIndex', 'findLastKey'], + (methodName) => { + describe(`lodash.${methodName}`); + + const array = [1, 2, 3, 4], + func = _[methodName]; + + const objects = [ + { a: 0, b: 0 }, + { a: 1, b: 1 }, + { a: 2, b: 2 }, + ]; + + const expected = { + find: [objects[1], undefined, objects[2]], + findIndex: [1, -1, 2], + findKey: ['1', undefined, '2'], + findLast: [objects[2], undefined, objects[2]], + findLastIndex: [2, -1, 2], + findLastKey: ['2', undefined, '2'], + }[methodName]; + + it(`\`_.${methodName}\` should return the found value`, () => { + assert.strictEqual( + func(objects, (object) => object.a), + expected[0], + ); + }); + + it(`\`_.${methodName}\` should return \`${expected[1]}\` if value is not found`, () => { + assert.strictEqual( + func(objects, (object) => object.a === 3), + expected[1], + ); + }); + + it(`\`_.${methodName}\` should work with \`_.matches\` shorthands`, () => { + assert.strictEqual(func(objects, { b: 2 }), expected[2]); + }); + + it(`\`_.${methodName}\` should work with \`_.matchesProperty\` shorthands`, () => { + assert.strictEqual(func(objects, ['b', 2]), expected[2]); + }); + + it(`\`_.${methodName}\` should work with \`_.property\` shorthands`, () => { + assert.strictEqual(func(objects, 'b'), expected[0]); + }); + + it(`\`_.${methodName}\` should return \`${expected[1]}\` for empty collections`, () => { + const emptyValues = lodashStable.endsWith(methodName, 'Index') + ? lodashStable.reject(empties, lodashStable.isPlainObject) + : empties, + expecting = lodashStable.map(emptyValues, lodashStable.constant(expected[1])); + + const actual = lodashStable.map(emptyValues, (value) => { + try { + return func(value, { a: 3 }); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expecting); + }); + + it(`\`_.${methodName}\` should return an unwrapped value when implicitly chaining`, () => { + const expected = { + find: 1, + findIndex: 0, + findKey: '0', + findLast: 4, + findLastIndex: 3, + findLastKey: '3', + }[methodName]; + }); + + it(`\`_.${methodName}\` should return a wrapped value when explicitly chaining`, () => {}); + + it(`\`_.${methodName}\` should not execute immediately when explicitly chaining`, () => {}); + + it(`\`_.${methodName}\` should work in a lazy sequence`, () => {}); + }, +); diff --git a/test/lowerCase.spec.ts b/test/lowerCase.spec.ts new file mode 100644 index 000000000..c06207d17 --- /dev/null +++ b/test/lowerCase.spec.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert'; +import lowerCase from '../src/lowerCase'; + +describe('lowerCase', () => { + it('should lowercase as space-separated words', () => { + assert.strictEqual(lowerCase('--Foo-Bar--'), 'foo bar'); + assert.strictEqual(lowerCase('fooBar'), 'foo bar'); + assert.strictEqual(lowerCase('__FOO_BAR__'), 'foo bar'); + }); +}); diff --git a/test/lowerCase.test.js b/test/lowerCase.test.js deleted file mode 100644 index eca2b7726..000000000 --- a/test/lowerCase.test.js +++ /dev/null @@ -1,10 +0,0 @@ -import assert from 'assert'; -import lowerCase from '../lowerCase.js'; - -describe('lowerCase', function() { - it('should lowercase as space-separated words', function() { - assert.strictEqual(lowerCase('--Foo-Bar--'), 'foo bar'); - assert.strictEqual(lowerCase('fooBar'), 'foo bar'); - assert.strictEqual(lowerCase('__FOO_BAR__'), 'foo bar'); - }); -}); diff --git a/test/lowerFirst.spec.ts b/test/lowerFirst.spec.ts new file mode 100644 index 000000000..2b917ddbf --- /dev/null +++ b/test/lowerFirst.spec.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert'; +import lowerFirst from '../src/lowerFirst'; + +describe('lowerFirst', () => { + it('should lowercase only the first character', () => { + assert.strictEqual(lowerFirst('fred'), 'fred'); + assert.strictEqual(lowerFirst('Fred'), 'fred'); + assert.strictEqual(lowerFirst('FRED'), 'fRED'); + }); +}); diff --git a/test/lowerFirst.test.js b/test/lowerFirst.test.js deleted file mode 100644 index 665e7e71e..000000000 --- a/test/lowerFirst.test.js +++ /dev/null @@ -1,10 +0,0 @@ -import assert from 'assert'; -import lowerFirst from '../lowerFirst.js'; - -describe('lowerFirst', function() { - it('should lowercase only the first character', function() { - assert.strictEqual(lowerFirst('fred'), 'fred'); - assert.strictEqual(lowerFirst('Fred'), 'fred'); - assert.strictEqual(lowerFirst('FRED'), 'fRED'); - }); -}); diff --git a/test/lt.spec.ts b/test/lt.spec.ts new file mode 100644 index 000000000..c8ae9863c --- /dev/null +++ b/test/lt.spec.ts @@ -0,0 +1,16 @@ +import assert from 'node:assert'; +import lt from '../src/lt'; + +describe('lt', () => { + it('should return `true` if `value` is less than `other`', () => { + assert.strictEqual(lt(1, 3), true); + assert.strictEqual(lt('abc', 'def'), true); + }); + + it('should return `false` if `value` >= `other`', () => { + assert.strictEqual(lt(3, 1), false); + assert.strictEqual(lt(3, 3), false); + assert.strictEqual(lt('def', 'abc'), false); + assert.strictEqual(lt('def', 'def'), false); + }); +}); diff --git a/test/lt.test.js b/test/lt.test.js deleted file mode 100644 index 6b4590cb5..000000000 --- a/test/lt.test.js +++ /dev/null @@ -1,16 +0,0 @@ -import assert from 'assert'; -import lt from '../lt.js'; - -describe('lt', function() { - it('should return `true` if `value` is less than `other`', function() { - assert.strictEqual(lt(1, 3), true); - assert.strictEqual(lt('abc', 'def'), true); - }); - - it('should return `false` if `value` >= `other`', function() { - assert.strictEqual(lt(3, 1), false); - assert.strictEqual(lt(3, 3), false); - assert.strictEqual(lt('def', 'abc'), false); - assert.strictEqual(lt('def', 'def'), false); - }); -}); diff --git a/test/lte.spec.ts b/test/lte.spec.ts new file mode 100644 index 000000000..c00deac87 --- /dev/null +++ b/test/lte.spec.ts @@ -0,0 +1,17 @@ +import assert from 'node:assert'; +import lte from '../src/lte'; +import lt from '../src/lt'; + +describe('lte', () => { + it('should return `true` if `value` is <= `other`', () => { + assert.strictEqual(lte(1, 3), true); + assert.strictEqual(lte(3, 3), true); + assert.strictEqual(lte('abc', 'def'), true); + assert.strictEqual(lte('def', 'def'), true); + }); + + it('should return `false` if `value` > `other`', () => { + assert.strictEqual(lt(3, 1), false); + assert.strictEqual(lt('def', 'abc'), false); + }); +}); diff --git a/test/lte.test.js b/test/lte.test.js deleted file mode 100644 index 010a4fefc..000000000 --- a/test/lte.test.js +++ /dev/null @@ -1,17 +0,0 @@ -import assert from 'assert'; -import lte from '../lte.js'; -import lt from '../lt.js'; - -describe('lte', function() { - it('should return `true` if `value` is <= `other`', function() { - assert.strictEqual(lte(1, 3), true); - assert.strictEqual(lte(3, 3), true); - assert.strictEqual(lte('abc', 'def'), true); - assert.strictEqual(lte('def', 'def'), true); - }); - - it('should return `false` if `value` > `other`', function() { - assert.strictEqual(lt(3, 1), false); - assert.strictEqual(lt('def', 'abc'), false); - }); -}); diff --git a/test/map-caches.js b/test/map-caches.js deleted file mode 100644 index 08c2c9af3..000000000 --- a/test/map-caches.js +++ /dev/null @@ -1,63 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { symbol, noop, mapCaches, LARGE_ARRAY_SIZE } from './utils.js'; - -describe('map caches', function() { - var keys = [null, undefined, false, true, 1, -Infinity, NaN, {}, 'a', symbol || noop]; - - var pairs = lodashStable.map(keys, function(key, index) { - var lastIndex = keys.length - 1; - return [key, keys[lastIndex - index]]; - }); - - function createCaches(pairs) { - var largeStack = new mapCaches.Stack(pairs), - length = pairs ? pairs.length : 0; - - lodashStable.times(LARGE_ARRAY_SIZE - length, function() { - largeStack.set({}, {}); - }); - - return { - 'hashes': new mapCaches.Hash(pairs), - 'list caches': new mapCaches.ListCache(pairs), - 'map caches': new mapCaches.MapCache(pairs), - 'stack caches': new mapCaches.Stack(pairs), - 'large stacks': largeStack - }; - } - - lodashStable.forOwn(createCaches(pairs), function(cache, kind) { - var isLarge = /^large/.test(kind); - - it('should implement a `Map` interface for ' + kind, function() { - lodashStable.each(keys, function(key, index) { - var value = pairs[index][1]; - - assert.deepStrictEqual(cache.get(key), value); - assert.strictEqual(cache.has(key), true); - assert.strictEqual(cache.delete(key), true); - assert.strictEqual(cache.has(key), false); - assert.strictEqual(cache.get(key), undefined); - assert.strictEqual(cache.delete(key), false); - assert.strictEqual(cache.set(key, value), cache); - assert.strictEqual(cache.has(key), true); - }); - - assert.strictEqual(cache.size, isLarge ? LARGE_ARRAY_SIZE : keys.length); - assert.strictEqual(cache.clear(), undefined); - assert.ok(lodashStable.every(keys, function(key) { - return !cache.has(key); - })); - }); - }); - - lodashStable.forOwn(createCaches(), function(cache, kind) { - it('should support changing values of ' + kind, function() { - lodashStable.each(keys, function(key) { - cache.set(key, 1).set(key, 2); - assert.strictEqual(cache.get(key), 2); - }); - }); - }); -}); diff --git a/test/map-caches.spec.ts b/test/map-caches.spec.ts new file mode 100644 index 000000000..e4ff65df8 --- /dev/null +++ b/test/map-caches.spec.ts @@ -0,0 +1,61 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { symbol, noop, mapCaches, LARGE_ARRAY_SIZE } from './utils'; + +describe('map caches', () => { + const keys = [null, undefined, false, true, 1, -Infinity, NaN, {}, 'a', symbol || noop]; + + const pairs = lodashStable.map(keys, (key, index) => { + const lastIndex = keys.length - 1; + return [key, keys[lastIndex - index]]; + }); + + function createCaches(pairs) { + const largeStack = new mapCaches.Stack(pairs), + length = pairs ? pairs.length : 0; + + lodashStable.times(LARGE_ARRAY_SIZE - length, () => { + largeStack.set({}, {}); + }); + + return { + hashes: new mapCaches.Hash(pairs), + 'list caches': new mapCaches.ListCache(pairs), + 'map caches': new mapCaches.MapCache(pairs), + 'stack caches': new mapCaches.Stack(pairs), + 'large stacks': largeStack, + }; + } + + lodashStable.forOwn(createCaches(pairs), (cache, kind) => { + const isLarge = /^large/.test(kind); + + it(`should implement a \`Map\` interface for ${kind}`, () => { + lodashStable.each(keys, (key, index) => { + const value = pairs[index][1]; + + assert.deepStrictEqual(cache.get(key), value); + assert.strictEqual(cache.has(key), true); + assert.strictEqual(cache.delete(key), true); + assert.strictEqual(cache.has(key), false); + assert.strictEqual(cache.get(key), undefined); + assert.strictEqual(cache.delete(key), false); + assert.strictEqual(cache.set(key, value), cache); + assert.strictEqual(cache.has(key), true); + }); + + assert.strictEqual(cache.size, isLarge ? LARGE_ARRAY_SIZE : keys.length); + assert.strictEqual(cache.clear(), undefined); + assert.ok(lodashStable.every(keys, (key) => !cache.has(key))); + }); + }); + + lodashStable.forOwn(createCaches(), (cache, kind) => { + it(`should support changing values of ${kind}`, () => { + lodashStable.each(keys, (key) => { + cache.set(key, 1).set(key, 2); + assert.strictEqual(cache.get(key), 2); + }); + }); + }); +}); diff --git a/test/map.js b/test/map.js deleted file mode 100644 index c41b9756b..000000000 --- a/test/map.js +++ /dev/null @@ -1,122 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { identity, falsey, stubArray, document, noop, LARGE_ARRAY_SIZE, square } from './utils.js'; -import map from '../map.js'; - -describe('map', function() { - var array = [1, 2]; - - it('should map values in `collection` to a new array', function() { - var object = { 'a': 1, 'b': 2 }, - expected = ['1', '2']; - - assert.deepStrictEqual(map(array, String), expected); - assert.deepStrictEqual(map(object, String), expected); - }); - - it('should work with `_.property` shorthands', function() { - var objects = [{ 'a': 'x' }, { 'a': 'y' }]; - assert.deepStrictEqual(map(objects, 'a'), ['x', 'y']); - }); - - it('should iterate over own string keyed properties of objects', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var actual = map(new Foo, identity); - assert.deepStrictEqual(actual, [1]); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var object = { 'a': 1, 'b': 2 }, - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant([1, 2])); - - lodashStable.each([array, object], function(collection) { - var actual = lodashStable.map(values, function(value, index) { - return index ? map(collection, value) : map(collection); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should accept a falsey `collection`', function() { - var expected = lodashStable.map(falsey, stubArray); - - var actual = lodashStable.map(falsey, function(collection, index) { - try { - return index ? map(collection) : map(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should treat number values for `collection` as empty', function() { - assert.deepStrictEqual(map(1), []); - }); - - it('should treat a nodelist as an array-like object', function() { - if (document) { - var actual = map(document.getElementsByTagName('body'), function(element) { - return element.nodeName.toLowerCase(); - }); - - assert.deepStrictEqual(actual, ['body']); - } - }); - - it('should work with objects with non-number length properties', function() { - var value = { 'value': 'x' }, - object = { 'length': { 'value': 'x' } }; - - assert.deepStrictEqual(map(object, identity), [value]); - }); - - it('should return a wrapped value when chaining', function() { - assert.ok(_(array).map(noop) instanceof _); - }); - - it('should provide correct `predicate` arguments in a lazy sequence', function() { - var args, - array = lodashStable.range(LARGE_ARRAY_SIZE + 1), - expected = [1, 0, map(array.slice(1), square)]; - - _(array).slice(1).map(function(value, index, array) { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, [1, 0, array.slice(1)]); - - args = undefined; - _(array).slice(1).map(square).map(function(value, index, array) { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, expected); - - args = undefined; - _(array).slice(1).map(square).map(function(value, index) { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, expected); - - args = undefined; - _(array).slice(1).map(square).map(function(value) { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, [1]); - - args = undefined; - _(array).slice(1).map(square).map(function() { - args || (args = slice.call(arguments)); - }).value(); - - assert.deepEqual(args, expected); - }); -}); diff --git a/test/map.spec.ts b/test/map.spec.ts new file mode 100644 index 000000000..02187eb96 --- /dev/null +++ b/test/map.spec.ts @@ -0,0 +1,141 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { identity, falsey, stubArray, document, noop, LARGE_ARRAY_SIZE, square } from './utils'; +import map from '../src/map'; + +describe('map', () => { + const array = [1, 2]; + + it('should map values in `collection` to a new array', () => { + const object = { a: 1, b: 2 }, + expected = ['1', '2']; + + assert.deepStrictEqual(map(array, String), expected); + assert.deepStrictEqual(map(object, String), expected); + }); + + it('should work with `_.property` shorthands', () => { + const objects = [{ a: 'x' }, { a: 'y' }]; + assert.deepStrictEqual(map(objects, 'a'), ['x', 'y']); + }); + + it('should iterate over own string keyed properties of objects', () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const actual = map(new Foo(), identity); + assert.deepStrictEqual(actual, [1]); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const object = { a: 1, b: 2 }, + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant([1, 2])); + + lodashStable.each([array, object], (collection) => { + const actual = lodashStable.map(values, (value, index) => + index ? map(collection, value) : map(collection), + ); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should accept a falsey `collection`', () => { + const expected = lodashStable.map(falsey, stubArray); + + const actual = lodashStable.map(falsey, (collection, index) => { + try { + return index ? map(collection) : map(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should treat number values for `collection` as empty', () => { + assert.deepStrictEqual(map(1), []); + }); + + it('should treat a nodelist as an array-like object', () => { + if (document) { + const actual = map(document.getElementsByTagName('body'), (element) => + element.nodeName.toLowerCase(), + ); + + assert.deepStrictEqual(actual, ['body']); + } + }); + + it('should work with objects with non-number length properties', () => { + const value = { value: 'x' }, + object = { length: { value: 'x' } }; + + assert.deepStrictEqual(map(object, identity), [value]); + }); + + it('should return a wrapped value when chaining', () => { + assert.ok(_(array).map(noop) instanceof _); + }); + + it('should provide correct `predicate` arguments in a lazy sequence', () => { + let args, + array = lodashStable.range(LARGE_ARRAY_SIZE + 1), + expected = [1, 0, map(array.slice(1), square)]; + + _(array) + .slice(1) + .map(function (value, index, array) { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, [1, 0, array.slice(1)]); + + args = undefined; + _(array) + .slice(1) + .map(square) + .map(function (value, index, array) { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, expected); + + args = undefined; + _(array) + .slice(1) + .map(square) + .map(function (value, index) { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, expected); + + args = undefined; + _(array) + .slice(1) + .map(square) + .map(function (value) { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, [1]); + + args = undefined; + _(array) + .slice(1) + .map(square) + .map(function () { + args || (args = slice.call(arguments)); + }) + .value(); + + assert.deepEqual(args, expected); + }); +}); diff --git a/test/mapKeys-and-mapValues.js b/test/mapKeys-and-mapValues.js deleted file mode 100644 index 8ba86f7c8..000000000 --- a/test/mapKeys-and-mapValues.js +++ /dev/null @@ -1,36 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, falsey, stubObject, noop } from './utils.js'; - -describe('mapKeys and mapValues', function() { - lodashStable.each(['mapKeys', 'mapValues'], function(methodName) { - var func = _[methodName], - object = { 'a': 1, 'b': 2 }; - - it('`_.' + methodName + '` should iterate over own string keyed properties of objects', function() { - function Foo() { - this.a = 'a'; - } - Foo.prototype.b = 'b'; - - var actual = func(new Foo, function(value, key) { return key; }); - assert.deepStrictEqual(actual, { 'a': 'a' }); - }); - - it('`_.' + methodName + '` should accept a falsey `object`', function() { - var expected = lodashStable.map(falsey, stubObject); - - var actual = lodashStable.map(falsey, function(object, index) { - try { - return index ? func(object) : func(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return a wrapped value when chaining', function() { - assert.ok(_(object)[methodName](noop) instanceof _); - }); - }); -}); diff --git a/test/mapKeys-and-mapValues.spec.ts b/test/mapKeys-and-mapValues.spec.ts new file mode 100644 index 000000000..f70212f8d --- /dev/null +++ b/test/mapKeys-and-mapValues.spec.ts @@ -0,0 +1,36 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, falsey, stubObject, noop } from './utils'; + +describe('mapKeys and mapValues', () => { + lodashStable.each(['mapKeys', 'mapValues'], (methodName) => { + const func = _[methodName], + object = { a: 1, b: 2 }; + + it(`\`_.${methodName}\` should iterate over own string keyed properties of objects`, () => { + function Foo() { + this.a = 'a'; + } + Foo.prototype.b = 'b'; + + const actual = func(new Foo(), (value, key) => key); + assert.deepStrictEqual(actual, { a: 'a' }); + }); + + it(`\`_.${methodName}\` should accept a falsey \`object\``, () => { + const expected = lodashStable.map(falsey, stubObject); + + const actual = lodashStable.map(falsey, (object, index) => { + try { + return index ? func(object) : func(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return a wrapped value when chaining`, () => { + assert.ok(_(object)[methodName](noop) instanceof _); + }); + }); +}); diff --git a/test/mapKeys.js b/test/mapKeys.js deleted file mode 100644 index a40f90a6f..000000000 --- a/test/mapKeys.js +++ /dev/null @@ -1,35 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import mapKeys from '../mapKeys.js'; - -describe('mapKeys', function() { - var array = [1, 2], - object = { 'a': 1, 'b': 2 }; - - it('should map keys in `object` to a new object', function() { - var actual = mapKeys(object, String); - assert.deepStrictEqual(actual, { '1': 1, '2': 2 }); - }); - - it('should treat arrays like objects', function() { - var actual = mapKeys(array, String); - assert.deepStrictEqual(actual, { '1': 1, '2': 2 }); - }); - - it('should work with `_.property` shorthands', function() { - var actual = mapKeys({ 'a': { 'b': 'c' } }, 'b'); - assert.deepStrictEqual(actual, { 'c': { 'b': 'c' } }); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var object = { 'a': 1, 'b': 2 }, - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant({ '1': 1, '2': 2 })); - - var actual = lodashStable.map(values, function(value, index) { - return index ? mapKeys(object, value) : mapKeys(object); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/mapKeys.spec.ts b/test/mapKeys.spec.ts new file mode 100644 index 000000000..8700b821e --- /dev/null +++ b/test/mapKeys.spec.ts @@ -0,0 +1,35 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import mapKeys from '../src/mapKeys'; + +describe('mapKeys', () => { + const array = [1, 2], + object = { a: 1, b: 2 }; + + it('should map keys in `object` to a new object', () => { + const actual = mapKeys(object, String); + assert.deepStrictEqual(actual, { '1': 1, '2': 2 }); + }); + + it('should treat arrays like objects', () => { + const actual = mapKeys(array, String); + assert.deepStrictEqual(actual, { '1': 1, '2': 2 }); + }); + + it('should work with `_.property` shorthands', () => { + const actual = mapKeys({ a: { b: 'c' } }, 'b'); + assert.deepStrictEqual(actual, { c: { b: 'c' } }); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const object = { a: 1, b: 2 }, + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant({ '1': 1, '2': 2 })); + + const actual = lodashStable.map(values, (value, index) => + index ? mapKeys(object, value) : mapKeys(object), + ); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/mapValues.js b/test/mapValues.js deleted file mode 100644 index 64b5cdc89..000000000 --- a/test/mapValues.js +++ /dev/null @@ -1,36 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import mapValues from '../mapValues.js'; - -describe('mapValues', function() { - var array = [1, 2], - object = { 'a': 1, 'b': 2 }; - - it('should map values in `object` to a new object', function() { - var actual = mapValues(object, String); - assert.deepStrictEqual(actual, { 'a': '1', 'b': '2' }); - }); - - it('should treat arrays like objects', function() { - var actual = mapValues(array, String); - assert.deepStrictEqual(actual, { '0': '1', '1': '2' }); - }); - - it('should work with `_.property` shorthands', function() { - var actual = mapValues({ 'a': { 'b': 2 } }, 'b'); - assert.deepStrictEqual(actual, { 'a': 2 }); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var object = { 'a': 1, 'b': 2 }, - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant([true, false])); - - var actual = lodashStable.map(values, function(value, index) { - var result = index ? mapValues(object, value) : mapValues(object); - return [lodashStable.isEqual(result, object), result === object]; - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/mapValues.spec.ts b/test/mapValues.spec.ts new file mode 100644 index 000000000..2ba03ad12 --- /dev/null +++ b/test/mapValues.spec.ts @@ -0,0 +1,36 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import mapValues from '../src/mapValues'; + +describe('mapValues', () => { + const array = [1, 2], + object = { a: 1, b: 2 }; + + it('should map values in `object` to a new object', () => { + const actual = mapValues(object, String); + assert.deepStrictEqual(actual, { a: '1', b: '2' }); + }); + + it('should treat arrays like objects', () => { + const actual = mapValues(array, String); + assert.deepStrictEqual(actual, { '0': '1', '1': '2' }); + }); + + it('should work with `_.property` shorthands', () => { + const actual = mapValues({ a: { b: 2 } }, 'b'); + assert.deepStrictEqual(actual, { a: 2 }); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const object = { a: 1, b: 2 }, + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant([true, false])); + + const actual = lodashStable.map(values, (value, index) => { + const result = index ? mapValues(object, value) : mapValues(object); + return [lodashStable.isEqual(result, object), result === object]; + }); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/matches-methods.js b/test/matches-methods.js deleted file mode 100644 index 721fdfad5..000000000 --- a/test/matches-methods.js +++ /dev/null @@ -1,294 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, stubTrue, noop, numberProto, stubFalse, empties } from './utils.js'; -import isMatch from '../isMatch.js'; - -describe('matches methods', function() { - lodashStable.each(['matches', 'isMatch'], function(methodName) { - var isMatches = methodName == 'matches'; - - function matches(source) { - return isMatches ? _.matches(source) : function(object) { - return isMatch(object, source); - }; - } - - it('`_.' + methodName + '` should perform a deep comparison between `source` and `object`', function() { - var object = { 'a': 1, 'b': 2, 'c': 3 }, - par = matches({ 'a': 1 }); - - assert.strictEqual(par(object), true); - - par = matches({ 'b': 1 }); - assert.strictEqual(par(object), false); - - par = matches({ 'a': 1, 'c': 3 }); - assert.strictEqual(par(object), true); - - par = matches({ 'c': 3, 'd': 4 }); - assert.strictEqual(par(object), false); - - object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }; - par = matches({ 'a': { 'b': { 'c': 1 } } }); - - assert.strictEqual(par(object), true); - }); - - it('`_.' + methodName + '` should match inherited string keyed `object` properties', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var object = { 'a': new Foo }, - par = matches({ 'a': { 'b': 2 } }); - - assert.strictEqual(par(object), true); - }); - - it('`_.' + methodName + '` should not match by inherited `source` properties', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var objects = [{ 'a': 1 }, { 'a': 1, 'b': 2 }], - source = new Foo, - actual = lodashStable.map(objects, matches(source)), - expected = lodashStable.map(objects, stubTrue); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should compare a variety of `source` property values', function() { - var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, - object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }, - par = matches(object1); - - assert.strictEqual(par(object1), true); - assert.strictEqual(par(object2), false); - }); - - it('`_.' + methodName + '` should match `-0` as `0`', function() { - var object1 = { 'a': -0 }, - object2 = { 'a': 0 }, - par = matches(object1); - - assert.strictEqual(par(object2), true); - - par = matches(object2); - assert.strictEqual(par(object1), true); - }); - - it('`_.' + methodName + '` should compare functions by reference', function() { - var object1 = { 'a': lodashStable.noop }, - object2 = { 'a': noop }, - object3 = { 'a': {} }, - par = matches(object1); - - assert.strictEqual(par(object1), true); - assert.strictEqual(par(object2), false); - assert.strictEqual(par(object3), false); - }); - - it('`_.' + methodName + '` should work with a function for `object`', function() { - function Foo() {} - Foo.a = { 'b': 2, 'c': 3 }; - - var par = matches({ 'a': { 'b': 2 } }); - assert.strictEqual(par(Foo), true); - }); - - it('`_.' + methodName + '` should work with a function for `source`', function() { - function Foo() {} - Foo.a = 1; - Foo.b = function() {}; - Foo.c = 3; - - var objects = [{ 'a': 1 }, { 'a': 1, 'b': Foo.b, 'c': 3 }], - actual = lodashStable.map(objects, matches(Foo)); - - assert.deepStrictEqual(actual, [false, true]); - }); - - it('`_.' + methodName + '` should work with a non-plain `object`', function() { - function Foo(object) { lodashStable.assign(this, object); } - - var object = new Foo({ 'a': new Foo({ 'b': 2, 'c': 3 }) }), - par = matches({ 'a': { 'b': 2 } }); - - assert.strictEqual(par(object), true); - }); - - it('`_.' + methodName + '` should partial match arrays', function() { - var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], - actual = lodashStable.filter(objects, matches({ 'a': ['d'] })); - - assert.deepStrictEqual(actual, [objects[1]]); - - actual = lodashStable.filter(objects, matches({ 'a': ['b', 'd'] })); - assert.deepStrictEqual(actual, []); - - actual = lodashStable.filter(objects, matches({ 'a': ['d', 'b'] })); - assert.deepStrictEqual(actual, []); - }); - - it('`_.' + methodName + '` should partial match arrays with duplicate values', function() { - var objects = [{ 'a': [1, 2] }, { 'a': [2, 2] }], - actual = lodashStable.filter(objects, matches({ 'a': [2, 2] })); - - assert.deepStrictEqual(actual, [objects[1]]); - }); - - it('should partial match arrays of objects', function() { - var objects = [ - { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5, 'd': 6 }] }, - { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 6, 'd': 7 }] } - ]; - - var actual = lodashStable.filter(objects, matches({ 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] })); - assert.deepStrictEqual(actual, [objects[0]]); - }); - - it('`_.' + methodName + '` should partial match maps', function() { - if (Map) { - var objects = [{ 'a': new Map }, { 'a': new Map }]; - objects[0].a.set('a', 1); - objects[1].a.set('a', 1); - objects[1].a.set('b', 2); - - var map = new Map; - map.set('b', 2); - var actual = lodashStable.filter(objects, matches({ 'a': map })); - - assert.deepStrictEqual(actual, [objects[1]]); - - map.delete('b'); - actual = lodashStable.filter(objects, matches({ 'a': map })); - - assert.deepStrictEqual(actual, objects); - - map.set('c', 3); - actual = lodashStable.filter(objects, matches({ 'a': map })); - - assert.deepStrictEqual(actual, []); - } - }); - - it('`_.' + methodName + '` should partial match sets', function() { - if (Set) { - var objects = [{ 'a': new Set }, { 'a': new Set }]; - objects[0].a.add(1); - objects[1].a.add(1); - objects[1].a.add(2); - - var set = new Set; - set.add(2); - var actual = lodashStable.filter(objects, matches({ 'a': set })); - - assert.deepStrictEqual(actual, [objects[1]]); - - set.delete(2); - actual = lodashStable.filter(objects, matches({ 'a': set })); - - assert.deepStrictEqual(actual, objects); - - set.add(3); - actual = lodashStable.filter(objects, matches({ 'a': set })); - - assert.deepStrictEqual(actual, []); - } - }); - - it('`_.' + methodName + '` should match `undefined` values', function() { - var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], - actual = lodashStable.map(objects, matches({ 'b': undefined })), - expected = [false, false, true]; - - assert.deepStrictEqual(actual, expected); - - actual = lodashStable.map(objects, matches({ 'a': 1, 'b': undefined })); - - assert.deepStrictEqual(actual, expected); - - objects = [{ 'a': { 'b': 2 } }, { 'a': { 'b': 2, 'c': 3 } }, { 'a': { 'b': 2, 'c': undefined } }]; - actual = lodashStable.map(objects, matches({ 'a': { 'c': undefined } })); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should match `undefined` values on primitives', function() { - numberProto.a = 1; - numberProto.b = undefined; - - try { - var par = matches({ 'b': undefined }); - assert.strictEqual(par(1), true); - } catch (e) { - assert.ok(false, e.message); - } - try { - par = matches({ 'a': 1, 'b': undefined }); - assert.strictEqual(par(1), true); - } catch (e) { - assert.ok(false, e.message); - } - numberProto.a = { 'b': 1, 'c': undefined }; - try { - par = matches({ 'a': { 'c': undefined } }); - assert.strictEqual(par(1), true); - } catch (e) { - assert.ok(false, e.message); - } - delete numberProto.a; - delete numberProto.b; - }); - - it('`_.' + methodName + '` should return `false` when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubFalse), - par = matches({ 'a': 1 }); - - var actual = lodashStable.map(values, function(value, index) { - try { - return index ? par(value) : par(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return `true` when comparing an empty `source`', function() { - var object = { 'a': 1 }, - expected = lodashStable.map(empties, stubTrue); - - var actual = lodashStable.map(empties, function(value) { - var par = matches(value); - return par(object); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return `true` when comparing an empty `source` to a nullish `object`', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubTrue), - par = matches({}); - - var actual = lodashStable.map(values, function(value, index) { - try { - return index ? par(value) : par(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should return `true` when comparing a `source` of empty arrays and objects', function() { - var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], - actual = lodashStable.filter(objects, matches({ 'a': [], 'b': {} })); - - assert.deepStrictEqual(actual, objects); - }); - }); -}); diff --git a/test/matches-methods.spec.ts b/test/matches-methods.spec.ts new file mode 100644 index 000000000..368ae4689 --- /dev/null +++ b/test/matches-methods.spec.ts @@ -0,0 +1,311 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, stubTrue, noop, numberProto, stubFalse, empties } from './utils'; +import isMatch from '../src/isMatch'; + +describe('matches methods', () => { + lodashStable.each(['matches', 'isMatch'], (methodName) => { + const isMatches = methodName == 'matches'; + + function matches(source) { + return isMatches + ? _.matches(source) + : function (object) { + return isMatch(object, source); + }; + } + + it(`\`_.${methodName}\` should perform a deep comparison between \`source\` and \`object\``, () => { + let object = { a: 1, b: 2, c: 3 }, + par = matches({ a: 1 }); + + assert.strictEqual(par(object), true); + + par = matches({ b: 1 }); + assert.strictEqual(par(object), false); + + par = matches({ a: 1, c: 3 }); + assert.strictEqual(par(object), true); + + par = matches({ c: 3, d: 4 }); + assert.strictEqual(par(object), false); + + object = { a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 }; + par = matches({ a: { b: { c: 1 } } }); + + assert.strictEqual(par(object), true); + }); + + it(`\`_.${methodName}\` should match inherited string keyed \`object\` properties`, () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const object = { a: new Foo() }, + par = matches({ a: { b: 2 } }); + + assert.strictEqual(par(object), true); + }); + + it(`\`_.${methodName}\` should not match by inherited \`source\` properties`, () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const objects = [{ a: 1 }, { a: 1, b: 2 }], + source = new Foo(), + actual = lodashStable.map(objects, matches(source)), + expected = lodashStable.map(objects, stubTrue); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should compare a variety of \`source\` property values`, () => { + const object1 = { a: false, b: true, c: '3', d: 4, e: [5], f: { g: 6 } }, + object2 = { a: 0, b: 1, c: 3, d: '4', e: ['5'], f: { g: '6' } }, + par = matches(object1); + + assert.strictEqual(par(object1), true); + assert.strictEqual(par(object2), false); + }); + + it(`\`_.${methodName}\` should match \`-0\` as \`0\``, () => { + let object1 = { a: -0 }, + object2 = { a: 0 }, + par = matches(object1); + + assert.strictEqual(par(object2), true); + + par = matches(object2); + assert.strictEqual(par(object1), true); + }); + + it(`\`_.${methodName}\` should compare functions by reference`, () => { + const object1 = { a: lodashStable.noop }, + object2 = { a: noop }, + object3 = { a: {} }, + par = matches(object1); + + assert.strictEqual(par(object1), true); + assert.strictEqual(par(object2), false); + assert.strictEqual(par(object3), false); + }); + + it(`\`_.${methodName}\` should work with a function for \`object\``, () => { + function Foo() {} + Foo.a = { b: 2, c: 3 }; + + const par = matches({ a: { b: 2 } }); + assert.strictEqual(par(Foo), true); + }); + + it(`\`_.${methodName}\` should work with a function for \`source\``, () => { + function Foo() {} + Foo.a = 1; + Foo.b = function () {}; + Foo.c = 3; + + const objects = [{ a: 1 }, { a: 1, b: Foo.b, c: 3 }], + actual = lodashStable.map(objects, matches(Foo)); + + assert.deepStrictEqual(actual, [false, true]); + }); + + it(`\`_.${methodName}\` should work with a non-plain \`object\``, () => { + function Foo(object) { + lodashStable.assign(this, object); + } + + const object = new Foo({ a: new Foo({ b: 2, c: 3 }) }), + par = matches({ a: { b: 2 } }); + + assert.strictEqual(par(object), true); + }); + + it(`\`_.${methodName}\` should partial match arrays`, () => { + let objects = [{ a: ['b'] }, { a: ['c', 'd'] }], + actual = lodashStable.filter(objects, matches({ a: ['d'] })); + + assert.deepStrictEqual(actual, [objects[1]]); + + actual = lodashStable.filter(objects, matches({ a: ['b', 'd'] })); + assert.deepStrictEqual(actual, []); + + actual = lodashStable.filter(objects, matches({ a: ['d', 'b'] })); + assert.deepStrictEqual(actual, []); + }); + + it(`\`_.${methodName}\` should partial match arrays with duplicate values`, () => { + const objects = [{ a: [1, 2] }, { a: [2, 2] }], + actual = lodashStable.filter(objects, matches({ a: [2, 2] })); + + assert.deepStrictEqual(actual, [objects[1]]); + }); + + it('should partial match arrays of objects', () => { + const objects = [ + { + a: [ + { b: 1, c: 2 }, + { b: 4, c: 5, d: 6 }, + ], + }, + { + a: [ + { b: 1, c: 2 }, + { b: 4, c: 6, d: 7 }, + ], + }, + ]; + + const actual = lodashStable.filter(objects, matches({ a: [{ b: 1 }, { b: 4, c: 5 }] })); + assert.deepStrictEqual(actual, [objects[0]]); + }); + + it(`\`_.${methodName}\` should partial match maps`, () => { + if (Map) { + const objects = [{ a: new Map() }, { a: new Map() }]; + objects[0].a.set('a', 1); + objects[1].a.set('a', 1); + objects[1].a.set('b', 2); + + const map = new Map(); + map.set('b', 2); + let actual = lodashStable.filter(objects, matches({ a: map })); + + assert.deepStrictEqual(actual, [objects[1]]); + + map.delete('b'); + actual = lodashStable.filter(objects, matches({ a: map })); + + assert.deepStrictEqual(actual, objects); + + map.set('c', 3); + actual = lodashStable.filter(objects, matches({ a: map })); + + assert.deepStrictEqual(actual, []); + } + }); + + it(`\`_.${methodName}\` should partial match sets`, () => { + if (Set) { + const objects = [{ a: new Set() }, { a: new Set() }]; + objects[0].a.add(1); + objects[1].a.add(1); + objects[1].a.add(2); + + const set = new Set(); + set.add(2); + let actual = lodashStable.filter(objects, matches({ a: set })); + + assert.deepStrictEqual(actual, [objects[1]]); + + set.delete(2); + actual = lodashStable.filter(objects, matches({ a: set })); + + assert.deepStrictEqual(actual, objects); + + set.add(3); + actual = lodashStable.filter(objects, matches({ a: set })); + + assert.deepStrictEqual(actual, []); + } + }); + + it(`\`_.${methodName}\` should match \`undefined\` values`, () => { + let objects = [{ a: 1 }, { a: 1, b: 1 }, { a: 1, b: undefined }], + actual = lodashStable.map(objects, matches({ b: undefined })), + expected = [false, false, true]; + + assert.deepStrictEqual(actual, expected); + + actual = lodashStable.map(objects, matches({ a: 1, b: undefined })); + + assert.deepStrictEqual(actual, expected); + + objects = [{ a: { b: 2 } }, { a: { b: 2, c: 3 } }, { a: { b: 2, c: undefined } }]; + actual = lodashStable.map(objects, matches({ a: { c: undefined } })); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should match \`undefined\` values on primitives`, () => { + numberProto.a = 1; + numberProto.b = undefined; + + try { + var par = matches({ b: undefined }); + assert.strictEqual(par(1), true); + } catch (e) { + assert.ok(false, e.message); + } + try { + par = matches({ a: 1, b: undefined }); + assert.strictEqual(par(1), true); + } catch (e) { + assert.ok(false, e.message); + } + numberProto.a = { b: 1, c: undefined }; + try { + par = matches({ a: { c: undefined } }); + assert.strictEqual(par(1), true); + } catch (e) { + assert.ok(false, e.message); + } + delete numberProto.a; + delete numberProto.b; + }); + + it(`\`_.${methodName}\` should return \`false\` when \`object\` is nullish`, () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubFalse), + par = matches({ a: 1 }); + + const actual = lodashStable.map(values, (value, index) => { + try { + return index ? par(value) : par(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return \`true\` when comparing an empty \`source\``, () => { + const object = { a: 1 }, + expected = lodashStable.map(empties, stubTrue); + + const actual = lodashStable.map(empties, (value) => { + const par = matches(value); + return par(object); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return \`true\` when comparing an empty \`source\` to a nullish \`object\``, () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubTrue), + par = matches({}); + + const actual = lodashStable.map(values, (value, index) => { + try { + return index ? par(value) : par(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should return \`true\` when comparing a \`source\` of empty arrays and objects`, () => { + const objects = [ + { a: [1], b: { c: 1 } }, + { a: [2, 3], b: { d: 2 } }, + ], + actual = lodashStable.filter(objects, matches({ a: [], b: {} })); + + assert.deepStrictEqual(actual, objects); + }); + }); +}); diff --git a/test/matches.js b/test/matches.js deleted file mode 100644 index 5901655ee..000000000 --- a/test/matches.js +++ /dev/null @@ -1,32 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import matches from '../matches.js'; - -describe('matches', function() { - it('should not change behavior if `source` is modified', function() { - var sources = [ - { 'a': { 'b': 2, 'c': 3 } }, - { 'a': 1, 'b': 2 }, - { 'a': 1 } - ]; - - lodashStable.each(sources, function(source, index) { - var object = lodashStable.cloneDeep(source), - par = matches(source); - - assert.strictEqual(par(object), true); - - if (index) { - source.a = 2; - source.b = 1; - source.c = 3; - } else { - source.a.b = 1; - source.a.c = 2; - source.a.d = 3; - } - assert.strictEqual(par(object), true); - assert.strictEqual(par(source), false); - }); - }); -}); diff --git a/test/matches.spec.ts b/test/matches.spec.ts new file mode 100644 index 000000000..55ad04cb3 --- /dev/null +++ b/test/matches.spec.ts @@ -0,0 +1,28 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import matches from '../src/matches'; + +describe('matches', () => { + it('should not change behavior if `source` is modified', () => { + const sources = [{ a: { b: 2, c: 3 } }, { a: 1, b: 2 }, { a: 1 }]; + + lodashStable.each(sources, (source, index) => { + const object = lodashStable.cloneDeep(source), + par = matches(source); + + assert.strictEqual(par(object), true); + + if (index) { + source.a = 2; + source.b = 1; + source.c = 3; + } else { + source.a.b = 1; + source.a.c = 2; + source.a.d = 3; + } + assert.strictEqual(par(object), true); + assert.strictEqual(par(source), false); + }); + }); +}); diff --git a/test/matchesProperty.js b/test/matchesProperty.js deleted file mode 100644 index 23eb04218..000000000 --- a/test/matchesProperty.js +++ /dev/null @@ -1,368 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubTrue, stubFalse, noop, numberProto } from './utils.js'; -import matchesProperty from '../matchesProperty.js'; - -describe('matchesProperty', function() { - it('should create a function that performs a deep comparison between a property value and `srcValue`', function() { - var object = { 'a': 1, 'b': 2, 'c': 3 }, - matches = matchesProperty('a', 1); - - assert.strictEqual(matches.length, 1); - assert.strictEqual(matches(object), true); - - matches = matchesProperty('b', 3); - assert.strictEqual(matches(object), false); - - matches = matchesProperty('a', { 'a': 1, 'c': 3 }); - assert.strictEqual(matches({ 'a': object }), true); - - matches = matchesProperty('a', { 'c': 3, 'd': 4 }); - assert.strictEqual(matches(object), false); - - object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }; - matches = matchesProperty('a', { 'b': { 'c': 1 } }); - - assert.strictEqual(matches(object), true); - }); - - it('should support deep paths', function() { - var object = { 'a': { 'b': 2 } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var matches = matchesProperty(path, 2); - assert.strictEqual(matches(object), true); - }); - }); - - it('should work with a non-string `path`', function() { - var array = [1, 2, 3]; - - lodashStable.each([1, [1]], function(path) { - var matches = matchesProperty(path, 2); - assert.strictEqual(matches(array), true); - }); - }); - - it('should preserve the sign of `0`', function() { - var object1 = { '-0': 'a' }, - object2 = { '0': 'b' }, - pairs = [[object1, object2], [object1, object2], [object2, object1], [object2, object1]], - props = [-0, Object(-0), 0, Object(0)], - values = ['a', 'a', 'b', 'b'], - expected = lodashStable.map(props, lodashStable.constant([true, false])); - - var actual = lodashStable.map(props, function(key, index) { - var matches = matchesProperty(key, values[index]), - pair = pairs[index]; - - return [matches(pair[0]), matches(pair[1])]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should coerce `path` to a string', function() { - function fn() {} - fn.toString = lodashStable.constant('fn'); - - var object = { 'null': 1, 'undefined': 2, 'fn': 3, '[object Object]': 4 }, - paths = [null, undefined, fn, {}], - expected = lodashStable.map(paths, stubTrue); - - lodashStable.times(2, function(index) { - var actual = lodashStable.map(paths, function(path) { - var matches = matchesProperty(index ? [path] : path, object[path]); - return matches(object); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should match a key over a path', function() { - var object = { 'a.b': 1, 'a': { 'b': 2 } }; - - lodashStable.each(['a.b', ['a.b']], function(path) { - var matches = matchesProperty(path, 1); - assert.strictEqual(matches(object), true); - }); - }); - - it('should return `false` when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubFalse); - - lodashStable.each(['constructor', ['constructor']], function(path) { - var matches = matchesProperty(path, 1); - - var actual = lodashStable.map(values, function(value, index) { - try { - return index ? matches(value) : matches(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `false` for deep paths when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubFalse); - - lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { - var matches = matchesProperty(path, 1); - - var actual = lodashStable.map(values, function(value, index) { - try { - return index ? matches(value) : matches(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `false` if parts of `path` are missing', function() { - var object = {}; - - lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { - var matches = matchesProperty(path, 1); - assert.strictEqual(matches(object), false); - }); - }); - - it('should match inherited string keyed `srcValue` properties', function() { - function Foo() {} - Foo.prototype.b = 2; - - var object = { 'a': new Foo }; - - lodashStable.each(['a', ['a']], function(path) { - var matches = matchesProperty(path, { 'b': 2 }); - assert.strictEqual(matches(object), true); - }); - }); - - it('should not match by inherited `srcValue` properties', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': 2 } }], - expected = lodashStable.map(objects, stubTrue); - - lodashStable.each(['a', ['a']], function(path) { - assert.deepStrictEqual(lodashStable.map(objects, matchesProperty(path, new Foo)), expected); - }); - }); - - it('should compare a variety of values', function() { - var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, - object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }, - matches = matchesProperty('a', object1); - - assert.strictEqual(matches({ 'a': object1 }), true); - assert.strictEqual(matches({ 'a': object2 }), false); - }); - - it('should match `-0` as `0`', function() { - var matches = matchesProperty('a', -0); - assert.strictEqual(matches({ 'a': 0 }), true); - - matches = matchesProperty('a', 0); - assert.strictEqual(matches({ 'a': -0 }), true); - }); - - it('should compare functions by reference', function() { - var object1 = { 'a': lodashStable.noop }, - object2 = { 'a': noop }, - object3 = { 'a': {} }, - matches = matchesProperty('a', object1); - - assert.strictEqual(matches({ 'a': object1 }), true); - assert.strictEqual(matches({ 'a': object2 }), false); - assert.strictEqual(matches({ 'a': object3 }), false); - }); - - it('should work with a function for `srcValue`', function() { - function Foo() {} - Foo.a = 1; - Foo.b = function() {}; - Foo.c = 3; - - var objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': Foo.b, 'c': 3 } }], - actual = lodashStable.map(objects, matchesProperty('a', Foo)); - - assert.deepStrictEqual(actual, [false, true]); - }); - - it('should work with a non-plain `srcValue`', function() { - function Foo(object) { lodashStable.assign(this, object); } - - var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), - matches = matchesProperty('a', { 'b': 1 }); - - assert.strictEqual(matches(object), true); - }); - - it('should partial match arrays', function() { - var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], - actual = lodashStable.filter(objects, matchesProperty('a', ['d'])); - - assert.deepStrictEqual(actual, [objects[1]]); - - actual = lodashStable.filter(objects, matchesProperty('a', ['b', 'd'])); - assert.deepStrictEqual(actual, []); - - actual = lodashStable.filter(objects, matchesProperty('a', ['d', 'b'])); - assert.deepStrictEqual(actual, []); - }); - - it('should partial match arrays with duplicate values', function() { - var objects = [{ 'a': [1, 2] }, { 'a': [2, 2] }], - actual = lodashStable.filter(objects, matchesProperty('a', [2, 2])); - - assert.deepStrictEqual(actual, [objects[1]]); - }); - - it('should partial match arrays of objects', function() { - var objects = [ - { 'a': [{ 'a': 1, 'b': 2 }, { 'a': 4, 'b': 5, 'c': 6 }] }, - { 'a': [{ 'a': 1, 'b': 2 }, { 'a': 4, 'b': 6, 'c': 7 }] } - ]; - - var actual = lodashStable.filter(objects, matchesProperty('a', [{ 'a': 1 }, { 'a': 4, 'b': 5 }])); - assert.deepStrictEqual(actual, [objects[0]]); - }); - it('should partial match maps', function() { - if (Map) { - var objects = [{ 'a': new Map }, { 'a': new Map }]; - objects[0].a.set('a', 1); - objects[1].a.set('a', 1); - objects[1].a.set('b', 2); - - var map = new Map; - map.set('b', 2); - var actual = lodashStable.filter(objects, matchesProperty('a', map)); - - assert.deepStrictEqual(actual, [objects[1]]); - - map.delete('b'); - actual = lodashStable.filter(objects, matchesProperty('a', map)); - - assert.deepStrictEqual(actual, objects); - - map.set('c', 3); - actual = lodashStable.filter(objects, matchesProperty('a', map)); - - assert.deepStrictEqual(actual, []); - } - }); - - it('should partial match sets', function() { - if (Set) { - var objects = [{ 'a': new Set }, { 'a': new Set }]; - objects[0].a.add(1); - objects[1].a.add(1); - objects[1].a.add(2); - - var set = new Set; - set.add(2); - var actual = lodashStable.filter(objects, matchesProperty('a', set)); - - assert.deepStrictEqual(actual, [objects[1]]); - - set.delete(2); - actual = lodashStable.filter(objects, matchesProperty('a', set)); - - assert.deepStrictEqual(actual, objects); - - set.add(3); - actual = lodashStable.filter(objects, matchesProperty('a', set)); - - assert.deepStrictEqual(actual, []); - } - }); - - it('should match `undefined` values', function() { - var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], - actual = lodashStable.map(objects, matchesProperty('b', undefined)), - expected = [false, false, true]; - - assert.deepStrictEqual(actual, expected); - - objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': 1 } }, { 'a': { 'a': 1, 'b': undefined } }]; - actual = lodashStable.map(objects, matchesProperty('a', { 'b': undefined })); - - assert.deepStrictEqual(actual, expected); - }); - - it('should match `undefined` values of nested objects', function() { - var object = { 'a': { 'b': undefined } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var matches = matchesProperty(path, undefined); - assert.strictEqual(matches(object), true); - }); - - lodashStable.each(['a.a', ['a', 'a']], function(path) { - var matches = matchesProperty(path, undefined); - assert.strictEqual(matches(object), false); - }); - }); - - it('should match `undefined` values on primitives', function() { - numberProto.a = 1; - numberProto.b = undefined; - - try { - var matches = matchesProperty('b', undefined); - assert.strictEqual(matches(1), true); - } catch (e) { - assert.ok(false, e.message); - } - numberProto.a = { 'b': 1, 'c': undefined }; - try { - matches = matchesProperty('a', { 'c': undefined }); - assert.strictEqual(matches(1), true); - } catch (e) { - assert.ok(false, e.message); - } - delete numberProto.a; - delete numberProto.b; - }); - - it('should return `true` when comparing a `srcValue` of empty arrays and objects', function() { - var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], - matches = matchesProperty('a', { 'a': [], 'b': {} }); - - var actual = lodashStable.filter(objects, function(object) { - return matches({ 'a': object }); - }); - - assert.deepStrictEqual(actual, objects); - }); - - it('should not change behavior if `srcValue` is modified', function() { - lodashStable.each([{ 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 }], function(source, index) { - var object = lodashStable.cloneDeep(source), - matches = matchesProperty('a', source); - - assert.strictEqual(matches({ 'a': object }), true); - - if (index) { - source.a = 2; - source.b = 1; - source.c = 3; - } else { - source.a.b = 1; - source.a.c = 2; - source.a.d = 3; - } - assert.strictEqual(matches({ 'a': object }), true); - assert.strictEqual(matches({ 'a': source }), false); - }); - }); -}); diff --git a/test/matchesProperty.spec.ts b/test/matchesProperty.spec.ts new file mode 100644 index 000000000..99e70740e --- /dev/null +++ b/test/matchesProperty.spec.ts @@ -0,0 +1,395 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubTrue, stubFalse, noop, numberProto } from './utils'; +import matchesProperty from '../src/matchesProperty'; + +describe('matchesProperty', () => { + it('should create a function that performs a deep comparison between a property value and `srcValue`', () => { + let object = { a: 1, b: 2, c: 3 }, + matches = matchesProperty('a', 1); + + assert.strictEqual(matches.length, 1); + assert.strictEqual(matches(object), true); + + matches = matchesProperty('b', 3); + assert.strictEqual(matches(object), false); + + matches = matchesProperty('a', { a: 1, c: 3 }); + assert.strictEqual(matches({ a: object }), true); + + matches = matchesProperty('a', { c: 3, d: 4 }); + assert.strictEqual(matches(object), false); + + object = { a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 }; + matches = matchesProperty('a', { b: { c: 1 } }); + + assert.strictEqual(matches(object), true); + }); + + it('should support deep paths', () => { + const object = { a: { b: 2 } }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const matches = matchesProperty(path, 2); + assert.strictEqual(matches(object), true); + }); + }); + + it('should work with a non-string `path`', () => { + const array = [1, 2, 3]; + + lodashStable.each([1, [1]], (path) => { + const matches = matchesProperty(path, 2); + assert.strictEqual(matches(array), true); + }); + }); + + it('should preserve the sign of `0`', () => { + const object1 = { '-0': 'a' }, + object2 = { '0': 'b' }, + pairs = [ + [object1, object2], + [object1, object2], + [object2, object1], + [object2, object1], + ], + props = [-0, Object(-0), 0, Object(0)], + values = ['a', 'a', 'b', 'b'], + expected = lodashStable.map(props, lodashStable.constant([true, false])); + + const actual = lodashStable.map(props, (key, index) => { + const matches = matchesProperty(key, values[index]), + pair = pairs[index]; + + return [matches(pair[0]), matches(pair[1])]; + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should coerce `path` to a string', () => { + function fn() {} + fn.toString = lodashStable.constant('fn'); + + const object = { null: 1, undefined: 2, fn: 3, '[object Object]': 4 }, + paths = [null, undefined, fn, {}], + expected = lodashStable.map(paths, stubTrue); + + lodashStable.times(2, (index) => { + const actual = lodashStable.map(paths, (path) => { + const matches = matchesProperty(index ? [path] : path, object[path]); + return matches(object); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should match a key over a path', () => { + const object = { 'a.b': 1, a: { b: 2 } }; + + lodashStable.each(['a.b', ['a.b']], (path) => { + const matches = matchesProperty(path, 1); + assert.strictEqual(matches(object), true); + }); + }); + + it('should return `false` when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubFalse); + + lodashStable.each(['constructor', ['constructor']], (path) => { + const matches = matchesProperty(path, 1); + + const actual = lodashStable.map(values, (value, index) => { + try { + return index ? matches(value) : matches(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should return `false` for deep paths when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubFalse); + + lodashStable.each( + ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], + (path) => { + const matches = matchesProperty(path, 1); + + const actual = lodashStable.map(values, (value, index) => { + try { + return index ? matches(value) : matches(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }, + ); + }); + + it('should return `false` if parts of `path` are missing', () => { + const object = {}; + + lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], (path) => { + const matches = matchesProperty(path, 1); + assert.strictEqual(matches(object), false); + }); + }); + + it('should match inherited string keyed `srcValue` properties', () => { + function Foo() {} + Foo.prototype.b = 2; + + const object = { a: new Foo() }; + + lodashStable.each(['a', ['a']], (path) => { + const matches = matchesProperty(path, { b: 2 }); + assert.strictEqual(matches(object), true); + }); + }); + + it('should not match by inherited `srcValue` properties', () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const objects = [{ a: { a: 1 } }, { a: { a: 1, b: 2 } }], + expected = lodashStable.map(objects, stubTrue); + + lodashStable.each(['a', ['a']], (path) => { + assert.deepStrictEqual( + lodashStable.map(objects, matchesProperty(path, new Foo())), + expected, + ); + }); + }); + + it('should compare a variety of values', () => { + const object1 = { a: false, b: true, c: '3', d: 4, e: [5], f: { g: 6 } }, + object2 = { a: 0, b: 1, c: 3, d: '4', e: ['5'], f: { g: '6' } }, + matches = matchesProperty('a', object1); + + assert.strictEqual(matches({ a: object1 }), true); + assert.strictEqual(matches({ a: object2 }), false); + }); + + it('should match `-0` as `0`', () => { + let matches = matchesProperty('a', -0); + assert.strictEqual(matches({ a: 0 }), true); + + matches = matchesProperty('a', 0); + assert.strictEqual(matches({ a: -0 }), true); + }); + + it('should compare functions by reference', () => { + const object1 = { a: lodashStable.noop }, + object2 = { a: noop }, + object3 = { a: {} }, + matches = matchesProperty('a', object1); + + assert.strictEqual(matches({ a: object1 }), true); + assert.strictEqual(matches({ a: object2 }), false); + assert.strictEqual(matches({ a: object3 }), false); + }); + + it('should work with a function for `srcValue`', () => { + function Foo() {} + Foo.a = 1; + Foo.b = function () {}; + Foo.c = 3; + + const objects = [{ a: { a: 1 } }, { a: { a: 1, b: Foo.b, c: 3 } }], + actual = lodashStable.map(objects, matchesProperty('a', Foo)); + + assert.deepStrictEqual(actual, [false, true]); + }); + + it('should work with a non-plain `srcValue`', () => { + function Foo(object) { + lodashStable.assign(this, object); + } + + const object = new Foo({ a: new Foo({ b: 1, c: 2 }) }), + matches = matchesProperty('a', { b: 1 }); + + assert.strictEqual(matches(object), true); + }); + + it('should partial match arrays', () => { + let objects = [{ a: ['b'] }, { a: ['c', 'd'] }], + actual = lodashStable.filter(objects, matchesProperty('a', ['d'])); + + assert.deepStrictEqual(actual, [objects[1]]); + + actual = lodashStable.filter(objects, matchesProperty('a', ['b', 'd'])); + assert.deepStrictEqual(actual, []); + + actual = lodashStable.filter(objects, matchesProperty('a', ['d', 'b'])); + assert.deepStrictEqual(actual, []); + }); + + it('should partial match arrays with duplicate values', () => { + const objects = [{ a: [1, 2] }, { a: [2, 2] }], + actual = lodashStable.filter(objects, matchesProperty('a', [2, 2])); + + assert.deepStrictEqual(actual, [objects[1]]); + }); + + it('should partial match arrays of objects', () => { + const objects = [ + { + a: [ + { a: 1, b: 2 }, + { a: 4, b: 5, c: 6 }, + ], + }, + { + a: [ + { a: 1, b: 2 }, + { a: 4, b: 6, c: 7 }, + ], + }, + ]; + + const actual = lodashStable.filter( + objects, + matchesProperty('a', [{ a: 1 }, { a: 4, b: 5 }]), + ); + assert.deepStrictEqual(actual, [objects[0]]); + }); + it('should partial match maps', () => { + if (Map) { + const objects = [{ a: new Map() }, { a: new Map() }]; + objects[0].a.set('a', 1); + objects[1].a.set('a', 1); + objects[1].a.set('b', 2); + + const map = new Map(); + map.set('b', 2); + let actual = lodashStable.filter(objects, matchesProperty('a', map)); + + assert.deepStrictEqual(actual, [objects[1]]); + + map.delete('b'); + actual = lodashStable.filter(objects, matchesProperty('a', map)); + + assert.deepStrictEqual(actual, objects); + + map.set('c', 3); + actual = lodashStable.filter(objects, matchesProperty('a', map)); + + assert.deepStrictEqual(actual, []); + } + }); + + it('should partial match sets', () => { + if (Set) { + const objects = [{ a: new Set() }, { a: new Set() }]; + objects[0].a.add(1); + objects[1].a.add(1); + objects[1].a.add(2); + + const set = new Set(); + set.add(2); + let actual = lodashStable.filter(objects, matchesProperty('a', set)); + + assert.deepStrictEqual(actual, [objects[1]]); + + set.delete(2); + actual = lodashStable.filter(objects, matchesProperty('a', set)); + + assert.deepStrictEqual(actual, objects); + + set.add(3); + actual = lodashStable.filter(objects, matchesProperty('a', set)); + + assert.deepStrictEqual(actual, []); + } + }); + + it('should match `undefined` values', () => { + let objects = [{ a: 1 }, { a: 1, b: 1 }, { a: 1, b: undefined }], + actual = lodashStable.map(objects, matchesProperty('b', undefined)), + expected = [false, false, true]; + + assert.deepStrictEqual(actual, expected); + + objects = [{ a: { a: 1 } }, { a: { a: 1, b: 1 } }, { a: { a: 1, b: undefined } }]; + actual = lodashStable.map(objects, matchesProperty('a', { b: undefined })); + + assert.deepStrictEqual(actual, expected); + }); + + it('should match `undefined` values of nested objects', () => { + const object = { a: { b: undefined } }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const matches = matchesProperty(path, undefined); + assert.strictEqual(matches(object), true); + }); + + lodashStable.each(['a.a', ['a', 'a']], (path) => { + const matches = matchesProperty(path, undefined); + assert.strictEqual(matches(object), false); + }); + }); + + it('should match `undefined` values on primitives', () => { + numberProto.a = 1; + numberProto.b = undefined; + + try { + var matches = matchesProperty('b', undefined); + assert.strictEqual(matches(1), true); + } catch (e) { + assert.ok(false, e.message); + } + numberProto.a = { b: 1, c: undefined }; + try { + matches = matchesProperty('a', { c: undefined }); + assert.strictEqual(matches(1), true); + } catch (e) { + assert.ok(false, e.message); + } + delete numberProto.a; + delete numberProto.b; + }); + + it('should return `true` when comparing a `srcValue` of empty arrays and objects', () => { + const objects = [ + { a: [1], b: { c: 1 } }, + { a: [2, 3], b: { d: 2 } }, + ], + matches = matchesProperty('a', { a: [], b: {} }); + + const actual = lodashStable.filter(objects, (object) => matches({ a: object })); + + assert.deepStrictEqual(actual, objects); + }); + + it('should not change behavior if `srcValue` is modified', () => { + lodashStable.each([{ a: { b: 2, c: 3 } }, { a: 1, b: 2 }, { a: 1 }], (source, index) => { + const object = lodashStable.cloneDeep(source), + matches = matchesProperty('a', source); + + assert.strictEqual(matches({ a: object }), true); + + if (index) { + source.a = 2; + source.b = 1; + source.c = 3; + } else { + source.a.b = 1; + source.a.c = 2; + source.a.d = 3; + } + assert.strictEqual(matches({ a: object }), true); + assert.strictEqual(matches({ a: source }), false); + }); + }); +}); diff --git a/test/math-operator-methods.js b/test/math-operator-methods.js deleted file mode 100644 index cd5e88c4e..000000000 --- a/test/math-operator-methods.js +++ /dev/null @@ -1,56 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, symbol } from './utils.js'; - -describe('math operator methods', function() { - lodashStable.each(['add', 'divide', 'multiply', 'subtract'], function(methodName) { - var func = _[methodName], - isAddSub = methodName == 'add' || methodName == 'subtract'; - - it('`_.' + methodName + '` should return `' + (isAddSub ? 0 : 1) + '` when no arguments are given', function() { - assert.strictEqual(func(), isAddSub ? 0 : 1); - }); - - it('`_.' + methodName + '` should work with only one defined argument', function() { - assert.strictEqual(func(6), 6); - assert.strictEqual(func(6, undefined), 6); - assert.strictEqual(func(undefined, 4), 4); - }); - - it('`_.' + methodName + '` should preserve the sign of `0`', function() { - var values = [0, '0', -0, '-0'], - expected = [[0, Infinity], ['0', Infinity], [-0, -Infinity], ['-0', -Infinity]]; - - lodashStable.times(2, function(index) { - var actual = lodashStable.map(values, function(value) { - var result = index ? func(undefined, value) : func(value); - return [result, 1 / result]; - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('`_.' + methodName + '` should convert objects to `NaN`', function() { - assert.deepStrictEqual(func(0, {}), NaN); - assert.deepStrictEqual(func({}, 0), NaN); - }); - - it('`_.' + methodName + '` should convert symbols to `NaN`', function() { - if (Symbol) { - assert.deepStrictEqual(func(0, symbol), NaN); - assert.deepStrictEqual(func(symbol, 0), NaN); - } - }); - - it('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function() { - var actual = _(1)[methodName](2); - assert.notOk(actual instanceof _); - }); - - it('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function() { - var actual = _(1).chain()[methodName](2); - assert.ok(actual instanceof _); - }); - }); -}); diff --git a/test/math-operator-methods.spec.ts b/test/math-operator-methods.spec.ts new file mode 100644 index 000000000..a1c99ff42 --- /dev/null +++ b/test/math-operator-methods.spec.ts @@ -0,0 +1,63 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, symbol } from './utils'; + +describe('math operator methods', () => { + lodashStable.each(['add', 'divide', 'multiply', 'subtract'], (methodName) => { + const func = _[methodName], + isAddSub = methodName == 'add' || methodName == 'subtract'; + + it(`\`_.${methodName}\` should return \`${ + isAddSub ? 0 : 1 + }\` when no arguments are given`, () => { + assert.strictEqual(func(), isAddSub ? 0 : 1); + }); + + it(`\`_.${methodName}\` should work with only one defined argument`, () => { + assert.strictEqual(func(6), 6); + assert.strictEqual(func(6, undefined), 6); + assert.strictEqual(func(undefined, 4), 4); + }); + + it(`\`_.${methodName}\` should preserve the sign of \`0\``, () => { + const values = [0, '0', -0, '-0'], + expected = [ + [0, Infinity], + ['0', Infinity], + [-0, -Infinity], + ['-0', -Infinity], + ]; + + lodashStable.times(2, (index) => { + const actual = lodashStable.map(values, (value) => { + const result = index ? func(undefined, value) : func(value); + return [result, 1 / result]; + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it(`\`_.${methodName}\` should convert objects to \`NaN\``, () => { + assert.deepStrictEqual(func(0, {}), NaN); + assert.deepStrictEqual(func({}, 0), NaN); + }); + + it(`\`_.${methodName}\` should convert symbols to \`NaN\``, () => { + if (Symbol) { + assert.deepStrictEqual(func(0, symbol), NaN); + assert.deepStrictEqual(func(symbol, 0), NaN); + } + }); + + it(`\`_.${methodName}\` should return an unwrapped value when implicitly chaining`, () => { + const actual = _(1)[methodName](2); + assert.notOk(actual instanceof _); + }); + + it(`\`_.${methodName}\` should return a wrapped value when explicitly chaining`, () => { + const actual = _(1).chain()[methodName](2); + assert.ok(actual instanceof _); + }); + }); +}); diff --git a/test/max.js b/test/max.js deleted file mode 100644 index 28fca7954..000000000 --- a/test/max.js +++ /dev/null @@ -1,27 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, noop } from './utils.js'; -import max from '../max.js'; - -describe('max', function() { - it('should return the largest value from a collection', function() { - assert.strictEqual(max([1, 2, 3]), 3); - }); - - it('should return `undefined` for empty collections', function() { - var values = falsey.concat([[]]), - expected = lodashStable.map(values, noop); - - var actual = lodashStable.map(values, function(value, index) { - try { - return index ? max(value) : max(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with non-numeric collection values', function() { - assert.strictEqual(max(['a', 'b']), 'b'); - }); -}); diff --git a/test/max.spec.ts b/test/max.spec.ts new file mode 100644 index 000000000..4361bf4ab --- /dev/null +++ b/test/max.spec.ts @@ -0,0 +1,27 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, noop } from './utils'; +import max from '../src/max'; + +describe('max', () => { + it('should return the largest value from a collection', () => { + assert.strictEqual(max([1, 2, 3]), 3); + }); + + it('should return `undefined` for empty collections', () => { + const values = falsey.concat([[]]), + expected = lodashStable.map(values, noop); + + const actual = lodashStable.map(values, (value, index) => { + try { + return index ? max(value) : max(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with non-numeric collection values', () => { + assert.strictEqual(max(['a', 'b']), 'b'); + }); +}); diff --git a/test/mean.spec.ts b/test/mean.spec.ts new file mode 100644 index 000000000..ef705da06 --- /dev/null +++ b/test/mean.spec.ts @@ -0,0 +1,18 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { empties, stubNaN } from './utils'; +import mean from '../src/mean'; + +describe('mean', () => { + it('should return the mean of an array of numbers', () => { + const array = [4, 2, 8, 6]; + assert.strictEqual(mean(array), 5); + }); + + it('should return `NaN` when passing empty `array` values', () => { + const expected = lodashStable.map(empties, stubNaN), + actual = lodashStable.map(empties, mean); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/mean.test.js b/test/mean.test.js deleted file mode 100644 index f0f09061b..000000000 --- a/test/mean.test.js +++ /dev/null @@ -1,18 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { empties, stubNaN } from './utils.js'; -import mean from '../mean.js'; - -describe('mean', function() { - it('should return the mean of an array of numbers', function() { - var array = [4, 2, 8, 6]; - assert.strictEqual(mean(array), 5); - }); - - it('should return `NaN` when passing empty `array` values', function() { - var expected = lodashStable.map(empties, stubNaN), - actual = lodashStable.map(empties, mean); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/meanBy.js b/test/meanBy.js deleted file mode 100644 index 987eebdd3..000000000 --- a/test/meanBy.js +++ /dev/null @@ -1,31 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import meanBy from '../meanBy.js'; - -describe('meanBy', function() { - var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; - - it('should work with an `iteratee`', function() { - var actual = meanBy(objects, function(object) { - return object.a; - }); - - assert.deepStrictEqual(actual, 2); - }); - - it('should provide correct `iteratee` arguments', function() { - var args; - - meanBy(objects, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [{ 'a': 2 }]); - }); - - it('should work with `_.property` shorthands', function() { - var arrays = [[2], [3], [1]]; - assert.strictEqual(meanBy(arrays, 0), 2); - assert.strictEqual(meanBy(objects, 'a'), 2); - }); -}); diff --git a/test/meanBy.spec.ts b/test/meanBy.spec.ts new file mode 100644 index 000000000..d0da5f176 --- /dev/null +++ b/test/meanBy.spec.ts @@ -0,0 +1,29 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import meanBy from '../src/meanBy'; + +describe('meanBy', () => { + const objects = [{ a: 2 }, { a: 3 }, { a: 1 }]; + + it('should work with an `iteratee`', () => { + const actual = meanBy(objects, (object) => object.a); + + assert.deepStrictEqual(actual, 2); + }); + + it('should provide correct `iteratee` arguments', () => { + let args; + + meanBy(objects, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [{ a: 2 }]); + }); + + it('should work with `_.property` shorthands', () => { + const arrays = [[2], [3], [1]]; + assert.strictEqual(meanBy(arrays, 0), 2); + assert.strictEqual(meanBy(objects, 'a'), 2); + }); +}); diff --git a/test/memoize.spec.ts b/test/memoize.spec.ts new file mode 100644 index 000000000..3ba4e8d30 --- /dev/null +++ b/test/memoize.spec.ts @@ -0,0 +1,176 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { noop, stubTrue, identity } from './utils'; +import memoize from '../src/memoize'; +import isFunction from '../src/isFunction'; + +describe('memoize', () => { + function CustomCache() { + this.clear(); + } + + CustomCache.prototype = { + clear: function () { + this.__data__ = []; + return this; + }, + get: function (key) { + const entry = lodashStable.find(this.__data__, ['key', key]); + return entry && entry.value; + }, + has: function (key) { + return lodashStable.some(this.__data__, ['key', key]); + }, + set: function (key, value) { + this.__data__.push({ key: key, value: value }); + return this; + }, + }; + + function ImmutableCache() { + this.__data__ = []; + } + + ImmutableCache.prototype = lodashStable.create(CustomCache.prototype, { + constructor: ImmutableCache, + clear: function () { + return new ImmutableCache(); + }, + set: function (key, value) { + const result = new ImmutableCache(); + result.__data__ = this.__data__.concat({ key: key, value: value }); + return result; + }, + }); + + it('should memoize results based on the first argument given', () => { + const memoized = memoize((a, b, c) => a + b + c); + + assert.strictEqual(memoized(1, 2, 3), 6); + assert.strictEqual(memoized(1, 3, 5), 6); + }); + + it('should support a `resolver`', () => { + const fn = function (a, b, c) { + return a + b + c; + }, + memoized = memoize(fn, fn); + + assert.strictEqual(memoized(1, 2, 3), 6); + assert.strictEqual(memoized(1, 3, 5), 9); + }); + + it('should use `this` binding of function for `resolver`', () => { + const fn = function (a, b, c) { + return a + this.b + this.c; + }, + memoized = memoize(fn, fn); + + const object = { memoized: memoized, b: 2, c: 3 }; + assert.strictEqual(object.memoized(1), 6); + + object.b = 3; + object.c = 5; + assert.strictEqual(object.memoized(1), 9); + }); + + it('should throw a TypeError if `resolve` is truthy and not a function', () => { + assert.throws(() => { + memoize(noop, true); + }, TypeError); + }); + + it('should not error if `resolver` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (resolver, index) => { + try { + return isFunction(index ? memoize(noop, resolver) : memoize(noop)); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should check cache for own properties', () => { + const props = [ + 'constructor', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'toLocaleString', + 'toString', + 'valueOf', + ]; + + const memoized = memoize(identity); + + const actual = lodashStable.map(props, (value) => memoized(value)); + + assert.deepStrictEqual(actual, props); + }); + + it('should cache the `__proto__` key', () => { + const array = [], + key = '__proto__'; + + lodashStable.times(2, (index) => { + let count = 0, + resolver = index ? identity : undefined; + + const memoized = memoize(() => { + count++; + return array; + }, resolver); + + const cache = memoized.cache; + + memoized(key); + memoized(key); + + assert.strictEqual(count, 1); + assert.strictEqual(cache.get(key), array); + assert.ok(!(cache.__data__ instanceof Array)); + assert.strictEqual(cache.delete(key), true); + }); + }); + + it('should allow `_.memoize.Cache` to be customized', () => { + const oldCache = memoize.Cache; + memoize.Cache = CustomCache; + + const memoized = memoize((object) => object.id); + + const cache = memoized.cache, + key1 = { id: 'a' }, + key2 = { id: 'b' }; + + assert.strictEqual(memoized(key1), 'a'); + assert.strictEqual(cache.has(key1), true); + + assert.strictEqual(memoized(key2), 'b'); + assert.strictEqual(cache.has(key2), true); + + memoize.Cache = oldCache; + }); + + it('should works with an immutable `_.memoize.Cache` ', () => { + const oldCache = memoize.Cache; + memoize.Cache = ImmutableCache; + + const memoized = memoize((object) => object.id); + + const key1 = { id: 'a' }, + key2 = { id: 'b' }; + + memoized(key1); + memoized(key2); + + const cache = memoized.cache; + assert.strictEqual(cache.has(key1), true); + assert.strictEqual(cache.has(key2), true); + + memoize.Cache = oldCache; + }); +}); diff --git a/test/memoize.test.js b/test/memoize.test.js deleted file mode 100644 index e3f92cd6d..000000000 --- a/test/memoize.test.js +++ /dev/null @@ -1,178 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { noop, stubTrue, identity } from './utils.js'; -import memoize from '../memoize.js'; -import isFunction from '../isFunction.js'; - -describe('memoize', function() { - function CustomCache() { - this.clear(); - } - - CustomCache.prototype = { - 'clear': function() { - this.__data__ = []; - return this; - }, - 'get': function(key) { - var entry = lodashStable.find(this.__data__, ['key', key]); - return entry && entry.value; - }, - 'has': function(key) { - return lodashStable.some(this.__data__, ['key', key]); - }, - 'set': function(key, value) { - this.__data__.push({ 'key': key, 'value': value }); - return this; - } - }; - - function ImmutableCache() { - this.__data__ = []; - } - - ImmutableCache.prototype = lodashStable.create(CustomCache.prototype, { - 'constructor': ImmutableCache, - 'clear': function() { - return new ImmutableCache; - }, - 'set': function(key, value) { - var result = new ImmutableCache; - result.__data__ = this.__data__.concat({ 'key': key, 'value': value }); - return result; - } - }); - - it('should memoize results based on the first argument given', function() { - var memoized = memoize(function(a, b, c) { - return a + b + c; - }); - - assert.strictEqual(memoized(1, 2, 3), 6); - assert.strictEqual(memoized(1, 3, 5), 6); - }); - - it('should support a `resolver`', function() { - var fn = function(a, b, c) { return a + b + c; }, - memoized = memoize(fn, fn); - - assert.strictEqual(memoized(1, 2, 3), 6); - assert.strictEqual(memoized(1, 3, 5), 9); - }); - - it('should use `this` binding of function for `resolver`', function() { - var fn = function(a, b, c) { return a + this.b + this.c; }, - memoized = memoize(fn, fn); - - var object = { 'memoized': memoized, 'b': 2, 'c': 3 }; - assert.strictEqual(object.memoized(1), 6); - - object.b = 3; - object.c = 5; - assert.strictEqual(object.memoized(1), 9); - }); - - it('should throw a TypeError if `resolve` is truthy and not a function', function() { - assert.throws(function() { memoize(noop, true); }, TypeError); - }); - - it('should not error if `resolver` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(resolver, index) { - try { - return isFunction(index ? memoize(noop, resolver) : memoize(noop)); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should check cache for own properties', function() { - var props = [ - 'constructor', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'toLocaleString', - 'toString', - 'valueOf' - ]; - - var memoized = memoize(identity); - - var actual = lodashStable.map(props, function(value) { - return memoized(value); - }); - - assert.deepStrictEqual(actual, props); - }); - - it('should cache the `__proto__` key', function() { - var array = [], - key = '__proto__'; - - lodashStable.times(2, function(index) { - var count = 0, - resolver = index ? identity : undefined; - - var memoized = memoize(function() { - count++; - return array; - }, resolver); - - var cache = memoized.cache; - - memoized(key); - memoized(key); - - assert.strictEqual(count, 1); - assert.strictEqual(cache.get(key), array); - assert.ok(!(cache.__data__ instanceof Array)); - assert.strictEqual(cache.delete(key), true); - }); - }); - - it('should allow `_.memoize.Cache` to be customized', function() { - var oldCache = memoize.Cache; - memoize.Cache = CustomCache; - - var memoized = memoize(function(object) { - return object.id; - }); - - var cache = memoized.cache, - key1 = { 'id': 'a' }, - key2 = { 'id': 'b' }; - - assert.strictEqual(memoized(key1), 'a'); - assert.strictEqual(cache.has(key1), true); - - assert.strictEqual(memoized(key2), 'b'); - assert.strictEqual(cache.has(key2), true); - - memoize.Cache = oldCache; - }); - - it('should works with an immutable `_.memoize.Cache` ', function() { - var oldCache = memoize.Cache; - memoize.Cache = ImmutableCache; - - var memoized = memoize(function(object) { - return object.id; - }); - - var key1 = { 'id': 'a' }, - key2 = { 'id': 'b' }; - - memoized(key1); - memoized(key2); - - var cache = memoized.cache; - assert.strictEqual(cache.has(key1), true); - assert.strictEqual(cache.has(key2), true); - - memoize.Cache = oldCache; - }); -}); diff --git a/test/memoizeCapped.spec.ts b/test/memoizeCapped.spec.ts new file mode 100644 index 000000000..863f40fed --- /dev/null +++ b/test/memoizeCapped.spec.ts @@ -0,0 +1,21 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { identity, MAX_MEMOIZE_SIZE } from './utils'; +import _memoizeCapped from '../src/.internal/memoizeCapped'; + +describe('memoizeCapped', () => { + const func = _memoizeCapped; + + it('should enforce a max cache size of `MAX_MEMOIZE_SIZE`', () => { + if (func) { + const memoized = func(identity), + cache = memoized.cache; + + lodashStable.times(MAX_MEMOIZE_SIZE, memoized); + assert.strictEqual(cache.size, MAX_MEMOIZE_SIZE); + + memoized(MAX_MEMOIZE_SIZE); + assert.strictEqual(cache.size, 1); + } + }); +}); diff --git a/test/memoizeCapped.test.js b/test/memoizeCapped.test.js deleted file mode 100644 index c87920a2d..000000000 --- a/test/memoizeCapped.test.js +++ /dev/null @@ -1,21 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { identity, MAX_MEMOIZE_SIZE } from './utils.js'; -import _memoizeCapped from '../.internal/memoizeCapped.js'; - -describe('memoizeCapped', function() { - var func = _memoizeCapped; - - it('should enforce a max cache size of `MAX_MEMOIZE_SIZE`', function() { - if (func) { - var memoized = func(identity), - cache = memoized.cache; - - lodashStable.times(MAX_MEMOIZE_SIZE, memoized); - assert.strictEqual(cache.size, MAX_MEMOIZE_SIZE); - - memoized(MAX_MEMOIZE_SIZE); - assert.strictEqual(cache.size, 1); - } - }); -}); diff --git a/test/merge.spec.ts b/test/merge.spec.ts new file mode 100644 index 000000000..331136e15 --- /dev/null +++ b/test/merge.spec.ts @@ -0,0 +1,354 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, typedArrays, stubTrue, defineProperty, document, root } from './utils'; +import merge from '../src/merge'; +import isArguments from '../src/isArguments'; + +describe('merge', () => { + it('should merge `source` into `object`', () => { + const names = { + characters: [{ name: 'barney' }, { name: 'fred' }], + }; + + const ages = { + characters: [{ age: 36 }, { age: 40 }], + }; + + const heights = { + characters: [{ height: '5\'4"' }, { height: '5\'5"' }], + }; + + const expected = { + characters: [ + { name: 'barney', age: 36, height: '5\'4"' }, + { name: 'fred', age: 40, height: '5\'5"' }, + ], + }; + + assert.deepStrictEqual(merge(names, ages, heights), expected); + }); + + it('should merge sources containing circular references', () => { + const object = { + foo: { a: 1 }, + bar: { a: 2 }, + }; + + const source = { + foo: { b: { c: { d: {} } } }, + bar: {}, + }; + + source.foo.b.c.d = source; + source.bar.b = source.foo.b; + + const actual = merge(object, source); + + assert.notStrictEqual(actual.bar.b, actual.foo.b); + assert.strictEqual(actual.foo.b.c.d, actual.foo.b.c.d.foo.b.c.d); + }); + + it('should work with four arguments', () => { + const expected = { a: 4 }, + actual = merge({ a: 1 }, { a: 2 }, { a: 3 }, expected); + + assert.deepStrictEqual(actual, expected); + }); + + it('should merge onto function `object` values', () => { + function Foo() {} + + const source = { a: 1 }, + actual = merge(Foo, source); + + assert.strictEqual(actual, Foo); + assert.strictEqual(Foo.a, 1); + }); + + it('should merge first source object properties to function', () => { + const fn = function () {}, + object = { prop: {} }, + actual = merge({ prop: fn }, object); + + assert.deepStrictEqual(actual, object); + }); + + it('should merge first and second source object properties to function', () => { + const fn = function () {}, + object = { prop: {} }, + actual = merge({ prop: fn }, { prop: fn }, object); + + assert.deepStrictEqual(actual, object); + }); + + it('should not merge onto function values of sources', () => { + let source1 = { a: function () {} }, + source2 = { a: { b: 2 } }, + expected = { a: { b: 2 } }, + actual = merge({}, source1, source2); + + assert.deepStrictEqual(actual, expected); + assert.ok(!('b' in source1.a)); + + actual = merge(source1, source2); + assert.deepStrictEqual(actual, expected); + }); + + it('should merge onto non-plain `object` values', () => { + function Foo() {} + + const object = new Foo(), + actual = merge(object, { a: 1 }); + + assert.strictEqual(actual, object); + assert.strictEqual(object.a, 1); + }); + + // TODO: revisit. + it.skip('should treat sparse array sources as dense', () => { + const array = [1]; + array[2] = 3; + + const actual = merge([], array), + expected = array.slice(); + + expected[1] = undefined; + + assert.ok('1' in actual); + assert.deepStrictEqual(actual, expected); + }); + + it('should merge `arguments` objects', () => { + let object1 = { value: args }, + object2 = { value: { '3': 4 } }, + expected = { '0': 1, '1': 2, '2': 3, '3': 4 }, + actual = merge(object1, object2); + + assert.ok(!('3' in args)); + assert.ok(!isArguments(actual.value)); + assert.deepStrictEqual(actual.value, expected); + object1.value = args; + + actual = merge(object2, object1); + assert.ok(!isArguments(actual.value)); + assert.deepStrictEqual(actual.value, expected); + + expected = { '0': 1, '1': 2, '2': 3 }; + + actual = merge({}, object1); + assert.ok(!isArguments(actual.value)); + assert.deepStrictEqual(actual.value, expected); + }); + + it('should merge typed arrays', () => { + const array1 = [0], + array2 = [0, 0], + array3 = [0, 0, 0, 0], + array4 = [0, 0, 0, 0, 0, 0, 0, 0]; + + const arrays = [array2, array1, array4, array3, array2, array4, array4, array3, array2], + buffer = ArrayBuffer && new ArrayBuffer(8); + + let expected = lodashStable.map(typedArrays, (type, index) => { + const array = arrays[index].slice(); + array[0] = 1; + return root[type] ? { value: array } : false; + }); + + let actual = lodashStable.map(typedArrays, (type) => { + const Ctor = root[type]; + return Ctor ? merge({ value: new Ctor(buffer) }, { value: [1] }) : false; + }); + + assert.ok(lodashStable.isArray(actual)); + assert.deepStrictEqual(actual, expected); + + expected = lodashStable.map(typedArrays, (type, index) => { + const array = arrays[index].slice(); + array.push(1); + return root[type] ? { value: array } : false; + }); + + actual = lodashStable.map(typedArrays, (type, index) => { + const Ctor = root[type], + array = lodashStable.range(arrays[index].length); + + array.push(1); + return Ctor ? merge({ value: array }, { value: new Ctor(buffer) }) : false; + }); + + assert.ok(lodashStable.isArray(actual)); + assert.deepStrictEqual(actual, expected); + }); + + it('should assign `null` values', () => { + const actual = merge({ a: 1 }, { a: null }); + assert.strictEqual(actual.a, null); + }); + + it('should assign non array/buffer/typed-array/plain-object source values directly', () => { + function Foo() {} + + const values = [ + new Foo(), + new Boolean(), + new Date(), + Foo, + new Number(), + new String(), + new RegExp(), + ], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (value) => { + const object = merge({}, { a: value, b: { c: value } }); + return object.a === value && object.b.c === value; + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should clone buffer source values', () => { + if (Buffer) { + const buffer = new Buffer([1]), + actual = merge({}, { value: buffer }).value; + + assert.ok(lodashStable.isBuffer(actual)); + assert.strictEqual(actual[0], buffer[0]); + assert.notStrictEqual(actual, buffer); + } + }); + + it('should deep clone array/typed-array/plain-object source values', () => { + const typedArray = Uint8Array ? new Uint8Array([1]) : { buffer: [1] }; + + const props = ['0', 'buffer', 'a'], + values = [[{ a: 1 }], typedArray, { a: [1] }], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (value, index) => { + const key = props[index], + object = merge({}, { value: value }), + subValue = value[key], + newValue = object.value, + newSubValue = newValue[key]; + + return ( + newValue !== value && + newSubValue !== subValue && + lodashStable.isEqual(newValue, value) + ); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should not augment source objects', () => { + var source1 = { a: [{ a: 1 }] }, + source2 = { a: [{ b: 2 }] }, + actual = merge({}, source1, source2); + + assert.deepStrictEqual(source1.a, [{ a: 1 }]); + assert.deepStrictEqual(source2.a, [{ b: 2 }]); + assert.deepStrictEqual(actual.a, [{ a: 1, b: 2 }]); + + var source1 = { a: [[1, 2, 3]] }, + source2 = { a: [[3, 4]] }, + actual = merge({}, source1, source2); + + assert.deepStrictEqual(source1.a, [[1, 2, 3]]); + assert.deepStrictEqual(source2.a, [[3, 4]]); + assert.deepStrictEqual(actual.a, [[3, 4, 3]]); + }); + + it('should merge plain objects onto non-plain objects', () => { + function Foo(object) { + lodashStable.assign(this, object); + } + + let object = { a: 1 }, + actual = merge(new Foo(), object); + + assert.ok(actual instanceof Foo); + assert.deepStrictEqual(actual, new Foo(object)); + + actual = merge([new Foo()], [object]); + assert.ok(actual[0] instanceof Foo); + assert.deepStrictEqual(actual, [new Foo(object)]); + }); + + it('should not overwrite existing values with `undefined` values of object sources', () => { + const actual = merge({ a: 1 }, { a: undefined, b: undefined }); + assert.deepStrictEqual(actual, { a: 1, b: undefined }); + }); + + it('should not overwrite existing values with `undefined` values of array sources', () => { + let array = [1]; + array[2] = 3; + + let actual = merge([4, 5, 6], array), + expected = [1, 5, 3]; + + assert.deepStrictEqual(actual, expected); + + array = [1, , 3]; + array[1] = undefined; + + actual = merge([4, 5, 6], array); + assert.deepStrictEqual(actual, expected); + }); + + it('should skip merging when `object` and `source` are the same value', () => { + let object = {}, + pass = true; + + defineProperty(object, 'a', { + configurable: true, + enumerable: true, + get: function () { + pass = false; + }, + set: function () { + pass = false; + }, + }); + + merge(object, object); + assert.ok(pass); + }); + + it('should convert values to arrays when merging arrays of `source`', () => { + let object = { a: { '1': 'y', b: 'z', length: 2 } }, + actual = merge(object, { a: ['x'] }); + + assert.deepStrictEqual(actual, { a: ['x', 'y'] }); + + actual = merge({ a: {} }, { a: [] }); + assert.deepStrictEqual(actual, { a: [] }); + }); + + it('should convert strings to arrays when merging arrays of `source`', () => { + const object = { a: 'abcde' }, + actual = merge(object, { a: ['x', 'y', 'z'] }); + + assert.deepStrictEqual(actual, { a: ['x', 'y', 'z'] }); + }); + + it('should not error on DOM elements', () => { + const object1 = { el: document && document.createElement('div') }, + object2 = { el: document && document.createElement('div') }, + pairs = [ + [{}, object1], + [object1, object2], + ], + expected = lodashStable.map(pairs, stubTrue); + + const actual = lodashStable.map(pairs, (pair) => { + try { + return merge(pair[0], pair[1]).el === pair[1].el; + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/merge.test.js b/test/merge.test.js deleted file mode 100644 index 397a9aafa..000000000 --- a/test/merge.test.js +++ /dev/null @@ -1,350 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, typedArrays, stubTrue, defineProperty, document, root } from './utils.js'; -import merge from '../merge.js'; -import isArguments from '../isArguments.js'; - -describe('merge', function() { - it('should merge `source` into `object`', function() { - var names = { - 'characters': [ - { 'name': 'barney' }, - { 'name': 'fred' } - ] - }; - - var ages = { - 'characters': [ - { 'age': 36 }, - { 'age': 40 } - ] - }; - - var heights = { - 'characters': [ - { 'height': '5\'4"' }, - { 'height': '5\'5"' } - ] - }; - - var expected = { - 'characters': [ - { 'name': 'barney', 'age': 36, 'height': '5\'4"' }, - { 'name': 'fred', 'age': 40, 'height': '5\'5"' } - ] - }; - - assert.deepStrictEqual(merge(names, ages, heights), expected); - }); - - it('should merge sources containing circular references', function() { - var object = { - 'foo': { 'a': 1 }, - 'bar': { 'a': 2 } - }; - - var source = { - 'foo': { 'b': { 'c': { 'd': {} } } }, - 'bar': {} - }; - - source.foo.b.c.d = source; - source.bar.b = source.foo.b; - - var actual = merge(object, source); - - assert.notStrictEqual(actual.bar.b, actual.foo.b); - assert.strictEqual(actual.foo.b.c.d, actual.foo.b.c.d.foo.b.c.d); - }); - - it('should work with four arguments', function() { - var expected = { 'a': 4 }, - actual = merge({ 'a': 1 }, { 'a': 2 }, { 'a': 3 }, expected); - - assert.deepStrictEqual(actual, expected); - }); - - it('should merge onto function `object` values', function() { - function Foo() {} - - var source = { 'a': 1 }, - actual = merge(Foo, source); - - assert.strictEqual(actual, Foo); - assert.strictEqual(Foo.a, 1); - }); - - it('should merge first source object properties to function', function() { - var fn = function() {}, - object = { 'prop': {} }, - actual = merge({ 'prop': fn }, object); - - assert.deepStrictEqual(actual, object); - }); - - it('should merge first and second source object properties to function', function() { - var fn = function() {}, - object = { 'prop': {} }, - actual = merge({ 'prop': fn }, { 'prop': fn }, object); - - assert.deepStrictEqual(actual, object); - }); - - it('should not merge onto function values of sources', function() { - var source1 = { 'a': function() {} }, - source2 = { 'a': { 'b': 2 } }, - expected = { 'a': { 'b': 2 } }, - actual = merge({}, source1, source2); - - assert.deepStrictEqual(actual, expected); - assert.ok(!('b' in source1.a)); - - actual = merge(source1, source2); - assert.deepStrictEqual(actual, expected); - }); - - it('should merge onto non-plain `object` values', function() { - function Foo() {} - - var object = new Foo, - actual = merge(object, { 'a': 1 }); - - assert.strictEqual(actual, object); - assert.strictEqual(object.a, 1); - }); - - // TODO: revisit. - it.skip('should treat sparse array sources as dense', function() { - var array = [1]; - array[2] = 3; - - var actual = merge([], array), - expected = array.slice(); - - expected[1] = undefined; - - assert.ok('1' in actual); - assert.deepStrictEqual(actual, expected); - }); - - it('should merge `arguments` objects', function() { - var object1 = { 'value': args }, - object2 = { 'value': { '3': 4 } }, - expected = { '0': 1, '1': 2, '2': 3, '3': 4 }, - actual = merge(object1, object2); - - assert.ok(!('3' in args)); - assert.ok(!isArguments(actual.value)); - assert.deepStrictEqual(actual.value, expected); - object1.value = args; - - actual = merge(object2, object1); - assert.ok(!isArguments(actual.value)); - assert.deepStrictEqual(actual.value, expected); - - expected = { '0': 1, '1': 2, '2': 3 }; - - actual = merge({}, object1); - assert.ok(!isArguments(actual.value)); - assert.deepStrictEqual(actual.value, expected); - }); - - it('should merge typed arrays', function() { - var array1 = [0], - array2 = [0, 0], - array3 = [0, 0, 0, 0], - array4 = [0, 0, 0, 0, 0, 0, 0, 0]; - - var arrays = [array2, array1, array4, array3, array2, array4, array4, array3, array2], - buffer = ArrayBuffer && new ArrayBuffer(8); - - var expected = lodashStable.map(typedArrays, function(type, index) { - var array = arrays[index].slice(); - array[0] = 1; - return root[type] ? { 'value': array } : false; - }); - - var actual = lodashStable.map(typedArrays, function(type) { - var Ctor = root[type]; - return Ctor ? merge({ 'value': new Ctor(buffer) }, { 'value': [1] }) : false; - }); - - assert.ok(lodashStable.isArray(actual)); - assert.deepStrictEqual(actual, expected); - - expected = lodashStable.map(typedArrays, function(type, index) { - var array = arrays[index].slice(); - array.push(1); - return root[type] ? { 'value': array } : false; - }); - - actual = lodashStable.map(typedArrays, function(type, index) { - var Ctor = root[type], - array = lodashStable.range(arrays[index].length); - - array.push(1); - return Ctor ? merge({ 'value': array }, { 'value': new Ctor(buffer) }) : false; - }); - - assert.ok(lodashStable.isArray(actual)); - assert.deepStrictEqual(actual, expected); - }); - - it('should assign `null` values', function() { - var actual = merge({ 'a': 1 }, { 'a': null }); - assert.strictEqual(actual.a, null); - }); - - it('should assign non array/buffer/typed-array/plain-object source values directly', function() { - function Foo() {} - - var values = [new Foo, new Boolean, new Date, Foo, new Number, new String, new RegExp], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value) { - var object = merge({}, { 'a': value, 'b': { 'c': value } }); - return object.a === value && object.b.c === value; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should clone buffer source values', function() { - if (Buffer) { - var buffer = new Buffer([1]), - actual = merge({}, { 'value': buffer }).value; - - assert.ok(lodashStable.isBuffer(actual)); - assert.strictEqual(actual[0], buffer[0]); - assert.notStrictEqual(actual, buffer); - } - }); - - it('should deep clone array/typed-array/plain-object source values', function() { - var typedArray = Uint8Array - ? new Uint8Array([1]) - : { 'buffer': [1] }; - - var props = ['0', 'buffer', 'a'], - values = [[{ 'a': 1 }], typedArray, { 'a': [1] }], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value, index) { - var key = props[index], - object = merge({}, { 'value': value }), - subValue = value[key], - newValue = object.value, - newSubValue = newValue[key]; - - return ( - newValue !== value && - newSubValue !== subValue && - lodashStable.isEqual(newValue, value) - ); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should not augment source objects', function() { - var source1 = { 'a': [{ 'a': 1 }] }, - source2 = { 'a': [{ 'b': 2 }] }, - actual = merge({}, source1, source2); - - assert.deepStrictEqual(source1.a, [{ 'a': 1 }]); - assert.deepStrictEqual(source2.a, [{ 'b': 2 }]); - assert.deepStrictEqual(actual.a, [{ 'a': 1, 'b': 2 }]); - - var source1 = { 'a': [[1, 2, 3]] }, - source2 = { 'a': [[3, 4]] }, - actual = merge({}, source1, source2); - - assert.deepStrictEqual(source1.a, [[1, 2, 3]]); - assert.deepStrictEqual(source2.a, [[3, 4]]); - assert.deepStrictEqual(actual.a, [[3, 4, 3]]); - }); - - it('should merge plain objects onto non-plain objects', function() { - function Foo(object) { - lodashStable.assign(this, object); - } - - var object = { 'a': 1 }, - actual = merge(new Foo, object); - - assert.ok(actual instanceof Foo); - assert.deepStrictEqual(actual, new Foo(object)); - - actual = merge([new Foo], [object]); - assert.ok(actual[0] instanceof Foo); - assert.deepStrictEqual(actual, [new Foo(object)]); - }); - - it('should not overwrite existing values with `undefined` values of object sources', function() { - var actual = merge({ 'a': 1 }, { 'a': undefined, 'b': undefined }); - assert.deepStrictEqual(actual, { 'a': 1, 'b': undefined }); - }); - - it('should not overwrite existing values with `undefined` values of array sources', function() { - var array = [1]; - array[2] = 3; - - var actual = merge([4, 5, 6], array), - expected = [1, 5, 3]; - - assert.deepStrictEqual(actual, expected); - - array = [1, , 3]; - array[1] = undefined; - - actual = merge([4, 5, 6], array); - assert.deepStrictEqual(actual, expected); - }); - - it('should skip merging when `object` and `source` are the same value', function() { - var object = {}, - pass = true; - - defineProperty(object, 'a', { - 'configurable': true, - 'enumerable': true, - 'get': function() { pass = false; }, - 'set': function() { pass = false; } - }); - - merge(object, object); - assert.ok(pass); - }); - - it('should convert values to arrays when merging arrays of `source`', function() { - var object = { 'a': { '1': 'y', 'b': 'z', 'length': 2 } }, - actual = merge(object, { 'a': ['x'] }); - - assert.deepStrictEqual(actual, { 'a': ['x', 'y'] }); - - actual = merge({ 'a': {} }, { 'a': [] }); - assert.deepStrictEqual(actual, { 'a': [] }); - }); - - it('should convert strings to arrays when merging arrays of `source`', function() { - var object = { 'a': 'abcde' }, - actual = merge(object, { 'a': ['x', 'y', 'z'] }); - - assert.deepStrictEqual(actual, { 'a': ['x', 'y', 'z'] }); - }); - - it('should not error on DOM elements', function() { - var object1 = { 'el': document && document.createElement('div') }, - object2 = { 'el': document && document.createElement('div') }, - pairs = [[{}, object1], [object1, object2]], - expected = lodashStable.map(pairs, stubTrue); - - var actual = lodashStable.map(pairs, function(pair) { - try { - return merge(pair[0], pair[1]).el === pair[1].el; - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/mergeWith.js b/test/mergeWith.js deleted file mode 100644 index 45f10a907..000000000 --- a/test/mergeWith.js +++ /dev/null @@ -1,64 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { noop, identity, isNpm, mapCaches } from './utils.js'; -import mergeWith from '../mergeWith.js'; -import last from '../last.js'; - -describe('mergeWith', function() { - it('should handle merging when `customizer` returns `undefined`', function() { - var actual = mergeWith({ 'a': { 'b': [1, 1] } }, { 'a': { 'b': [0] } }, noop); - assert.deepStrictEqual(actual, { 'a': { 'b': [0, 1] } }); - - actual = mergeWith([], [undefined], identity); - assert.deepStrictEqual(actual, [undefined]); - }); - - it('should clone sources when `customizer` returns `undefined`', function() { - var source1 = { 'a': { 'b': { 'c': 1 } } }, - source2 = { 'a': { 'b': { 'd': 2 } } }; - - mergeWith({}, source1, source2, noop); - assert.deepStrictEqual(source1.a.b, { 'c': 1 }); - }); - - it('should defer to `customizer` for non `undefined` results', function() { - var actual = mergeWith({ 'a': { 'b': [0, 1] } }, { 'a': { 'b': [2] } }, function(a, b) { - return lodashStable.isArray(a) ? a.concat(b) : undefined; - }); - - assert.deepStrictEqual(actual, { 'a': { 'b': [0, 1, 2] } }); - }); - - it('should provide `stack` to `customizer`', function() { - var actual; - - mergeWith({}, { 'a': { 'b': 2 } }, function() { - actual = last(arguments); - }); - - assert.ok(isNpm - ? actual.constructor.name == 'Stack' - : actual instanceof mapCaches.Stack - ); - }); - - it('should overwrite primitives with source object clones', function() { - var actual = mergeWith({ 'a': 0 }, { 'a': { 'b': ['c'] } }, function(a, b) { - return lodashStable.isArray(a) ? a.concat(b) : undefined; - }); - - assert.deepStrictEqual(actual, { 'a': { 'b': ['c'] } }); - }); - - it('should pop the stack of sources for each sibling property', function() { - var array = ['b', 'c'], - object = { 'a': ['a'] }, - source = { 'a': array, 'b': array }; - - var actual = mergeWith(object, source, function(a, b) { - return lodashStable.isArray(a) ? a.concat(b) : undefined; - }); - - assert.deepStrictEqual(actual, { 'a': ['a', 'b', 'c'], 'b': ['b', 'c'] }); - }); -}); diff --git a/test/mergeWith.spec.ts b/test/mergeWith.spec.ts new file mode 100644 index 000000000..56c3d127e --- /dev/null +++ b/test/mergeWith.spec.ts @@ -0,0 +1,61 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { noop, identity, isNpm, mapCaches } from './utils'; +import mergeWith from '../src/mergeWith'; +import last from '../src/last'; + +describe('mergeWith', () => { + it('should handle merging when `customizer` returns `undefined`', () => { + let actual = mergeWith({ a: { b: [1, 1] } }, { a: { b: [0] } }, noop); + assert.deepStrictEqual(actual, { a: { b: [0, 1] } }); + + actual = mergeWith([], [undefined], identity); + assert.deepStrictEqual(actual, [undefined]); + }); + + it('should clone sources when `customizer` returns `undefined`', () => { + const source1 = { a: { b: { c: 1 } } }, + source2 = { a: { b: { d: 2 } } }; + + mergeWith({}, source1, source2, noop); + assert.deepStrictEqual(source1.a.b, { c: 1 }); + }); + + it('should defer to `customizer` for non `undefined` results', () => { + const actual = mergeWith({ a: { b: [0, 1] } }, { a: { b: [2] } }, (a, b) => + lodashStable.isArray(a) ? a.concat(b) : undefined, + ); + + assert.deepStrictEqual(actual, { a: { b: [0, 1, 2] } }); + }); + + it('should provide `stack` to `customizer`', () => { + let actual; + + mergeWith({}, { a: { b: 2 } }, function () { + actual = last(arguments); + }); + + assert.ok(isNpm ? actual.constructor.name == 'Stack' : actual instanceof mapCaches.Stack); + }); + + it('should overwrite primitives with source object clones', () => { + const actual = mergeWith({ a: 0 }, { a: { b: ['c'] } }, (a, b) => + lodashStable.isArray(a) ? a.concat(b) : undefined, + ); + + assert.deepStrictEqual(actual, { a: { b: ['c'] } }); + }); + + it('should pop the stack of sources for each sibling property', () => { + const array = ['b', 'c'], + object = { a: ['a'] }, + source = { a: array, b: array }; + + const actual = mergeWith(object, source, (a, b) => + lodashStable.isArray(a) ? a.concat(b) : undefined, + ); + + assert.deepStrictEqual(actual, { a: ['a', 'b', 'c'], b: ['b', 'c'] }); + }); +}); diff --git a/test/method.js b/test/method.js deleted file mode 100644 index 617c89105..000000000 --- a/test/method.js +++ /dev/null @@ -1,132 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubOne, _, stubTwo, stubThree, stubFour, noop, slice } from './utils.js'; -import constant from '../constant.js'; - -describe('method', function() { - it('should create a function that calls a method of a given object', function() { - var object = { 'a': stubOne }; - - lodashStable.each(['a', ['a']], function(path) { - var method = _.method(path); - assert.strictEqual(method.length, 1); - assert.strictEqual(method(object), 1); - }); - }); - - it('should work with deep property values', function() { - var object = { 'a': { 'b': stubTwo } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var method = _.method(path); - assert.strictEqual(method(object), 2); - }); - }); - - it('should work with a non-string `path`', function() { - var array = lodashStable.times(3, constant); - - lodashStable.each([1, [1]], function(path) { - var method = _.method(path); - assert.strictEqual(method(array), 1); - }); - }); - - it('should coerce `path` to a string', function() { - function fn() {} - fn.toString = lodashStable.constant('fn'); - - var expected = [1, 2, 3, 4], - object = { 'null': stubOne, 'undefined': stubTwo, 'fn': stubThree, '[object Object]': stubFour }, - paths = [null, undefined, fn, {}]; - - lodashStable.times(2, function(index) { - var actual = lodashStable.map(paths, function(path) { - var method = _.method(index ? [path] : path); - return method(object); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should work with inherited property values', function() { - function Foo() {} - Foo.prototype.a = stubOne; - - lodashStable.each(['a', ['a']], function(path) { - var method = _.method(path); - assert.strictEqual(method(new Foo), 1); - }); - }); - - it('should use a key over a path', function() { - var object = { 'a.b': stubOne, 'a': { 'b': stubTwo } }; - - lodashStable.each(['a.b', ['a.b']], function(path) { - var method = _.method(path); - assert.strictEqual(method(object), 1); - }); - }); - - it('should return `undefined` when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, noop); - - lodashStable.each(['constructor', ['constructor']], function(path) { - var method = _.method(path); - - var actual = lodashStable.map(values, function(value, index) { - return index ? method(value) : method(); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `undefined` for deep paths when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, noop); - - lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { - var method = _.method(path); - - var actual = lodashStable.map(values, function(value, index) { - return index ? method(value) : method(); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `undefined` if parts of `path` are missing', function() { - var object = {}; - - lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { - var method = _.method(path); - assert.strictEqual(method(object), undefined); - }); - }); - - it('should apply partial arguments to function', function() { - var object = { - 'fn': function() { - return slice.call(arguments); - } - }; - - lodashStable.each(['fn', ['fn']], function(path) { - var method = _.method(path, 1, 2, 3); - assert.deepStrictEqual(method(object), [1, 2, 3]); - }); - }); - - it('should invoke deep property methods with the correct `this` binding', function() { - var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var method = _.method(path); - assert.strictEqual(method(object), 1); - }); - }); -}); diff --git a/test/method.spec.ts b/test/method.spec.ts new file mode 100644 index 000000000..6a57a44d5 --- /dev/null +++ b/test/method.spec.ts @@ -0,0 +1,147 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubOne, _, stubTwo, stubThree, stubFour, noop, slice } from './utils'; +import constant from '../src/constant'; + +describe('method', () => { + it('should create a function that calls a method of a given object', () => { + const object = { a: stubOne }; + + lodashStable.each(['a', ['a']], (path) => { + const method = _.method(path); + assert.strictEqual(method.length, 1); + assert.strictEqual(method(object), 1); + }); + }); + + it('should work with deep property values', () => { + const object = { a: { b: stubTwo } }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const method = _.method(path); + assert.strictEqual(method(object), 2); + }); + }); + + it('should work with a non-string `path`', () => { + const array = lodashStable.times(3, constant); + + lodashStable.each([1, [1]], (path) => { + const method = _.method(path); + assert.strictEqual(method(array), 1); + }); + }); + + it('should coerce `path` to a string', () => { + function fn() {} + fn.toString = lodashStable.constant('fn'); + + const expected = [1, 2, 3, 4], + object = { + null: stubOne, + undefined: stubTwo, + fn: stubThree, + '[object Object]': stubFour, + }, + paths = [null, undefined, fn, {}]; + + lodashStable.times(2, (index) => { + const actual = lodashStable.map(paths, (path) => { + const method = _.method(index ? [path] : path); + return method(object); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should work with inherited property values', () => { + function Foo() {} + Foo.prototype.a = stubOne; + + lodashStable.each(['a', ['a']], (path) => { + const method = _.method(path); + assert.strictEqual(method(new Foo()), 1); + }); + }); + + it('should use a key over a path', () => { + const object = { 'a.b': stubOne, a: { b: stubTwo } }; + + lodashStable.each(['a.b', ['a.b']], (path) => { + const method = _.method(path); + assert.strictEqual(method(object), 1); + }); + }); + + it('should return `undefined` when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, noop); + + lodashStable.each(['constructor', ['constructor']], (path) => { + const method = _.method(path); + + const actual = lodashStable.map(values, (value, index) => + index ? method(value) : method(), + ); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should return `undefined` for deep paths when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, noop); + + lodashStable.each( + ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], + (path) => { + const method = _.method(path); + + const actual = lodashStable.map(values, (value, index) => + index ? method(value) : method(), + ); + + assert.deepStrictEqual(actual, expected); + }, + ); + }); + + it('should return `undefined` if parts of `path` are missing', () => { + const object = {}; + + lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], (path) => { + const method = _.method(path); + assert.strictEqual(method(object), undefined); + }); + }); + + it('should apply partial arguments to function', () => { + const object = { + fn: function () { + return slice.call(arguments); + }, + }; + + lodashStable.each(['fn', ['fn']], (path) => { + const method = _.method(path, 1, 2, 3); + assert.deepStrictEqual(method(object), [1, 2, 3]); + }); + }); + + it('should invoke deep property methods with the correct `this` binding', () => { + const object = { + a: { + b: function () { + return this.c; + }, + c: 1, + }, + }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const method = _.method(path); + assert.strictEqual(method(object), 1); + }); + }); +}); diff --git a/test/methodOf.js b/test/methodOf.js deleted file mode 100644 index 29170a29f..000000000 --- a/test/methodOf.js +++ /dev/null @@ -1,131 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubOne, _, stubTwo, stubThree, stubFour, noop, slice } from './utils.js'; -import constant from '../constant.js'; - -describe('methodOf', function() { - it('should create a function that calls a method of a given key', function() { - var object = { 'a': stubOne }; - - lodashStable.each(['a', ['a']], function(path) { - var methodOf = _.methodOf(object); - assert.strictEqual(methodOf.length, 1); - assert.strictEqual(methodOf(path), 1); - }); - }); - - it('should work with deep property values', function() { - var object = { 'a': { 'b': stubTwo } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var methodOf = _.methodOf(object); - assert.strictEqual(methodOf(path), 2); - }); - }); - - it('should work with a non-string `path`', function() { - var array = lodashStable.times(3, constant); - - lodashStable.each([1, [1]], function(path) { - var methodOf = _.methodOf(array); - assert.strictEqual(methodOf(path), 1); - }); - }); - - it('should coerce `path` to a string', function() { - function fn() {} - fn.toString = lodashStable.constant('fn'); - - var expected = [1, 2, 3, 4], - object = { 'null': stubOne, 'undefined': stubTwo, 'fn': stubThree, '[object Object]': stubFour }, - paths = [null, undefined, fn, {}]; - - lodashStable.times(2, function(index) { - var actual = lodashStable.map(paths, function(path) { - var methodOf = _.methodOf(object); - return methodOf(index ? [path] : path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should work with inherited property values', function() { - function Foo() {} - Foo.prototype.a = stubOne; - - lodashStable.each(['a', ['a']], function(path) { - var methodOf = _.methodOf(new Foo); - assert.strictEqual(methodOf(path), 1); - }); - }); - - it('should use a key over a path', function() { - var object = { 'a.b': stubOne, 'a': { 'b': stubTwo } }; - - lodashStable.each(['a.b', ['a.b']], function(path) { - var methodOf = _.methodOf(object); - assert.strictEqual(methodOf(path), 1); - }); - }); - - it('should return `undefined` when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, noop); - - lodashStable.each(['constructor', ['constructor']], function(path) { - var actual = lodashStable.map(values, function(value, index) { - var methodOf = index ? _.methodOf() : _.methodOf(value); - return methodOf(path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `undefined` for deep paths when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, noop); - - lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { - var actual = lodashStable.map(values, function(value, index) { - var methodOf = index ? _.methodOf() : _.methodOf(value); - return methodOf(path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `undefined` if parts of `path` are missing', function() { - var object = {}, - methodOf = _.methodOf(object); - - lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { - assert.strictEqual(methodOf(path), undefined); - }); - }); - - it('should apply partial arguments to function', function() { - var object = { - 'fn': function() { - return slice.call(arguments); - } - }; - - var methodOf = _.methodOf(object, 1, 2, 3); - - lodashStable.each(['fn', ['fn']], function(path) { - assert.deepStrictEqual(methodOf(path), [1, 2, 3]); - }); - }); - - it('should invoke deep property methods with the correct `this` binding', function() { - var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }, - methodOf = _.methodOf(object); - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.strictEqual(methodOf(path), 1); - }); - }); -}); diff --git a/test/methodOf.spec.ts b/test/methodOf.spec.ts new file mode 100644 index 000000000..c2c93bfe4 --- /dev/null +++ b/test/methodOf.spec.ts @@ -0,0 +1,146 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubOne, _, stubTwo, stubThree, stubFour, noop, slice } from './utils'; +import constant from '../src/constant'; + +describe('methodOf', () => { + it('should create a function that calls a method of a given key', () => { + const object = { a: stubOne }; + + lodashStable.each(['a', ['a']], (path) => { + const methodOf = _.methodOf(object); + assert.strictEqual(methodOf.length, 1); + assert.strictEqual(methodOf(path), 1); + }); + }); + + it('should work with deep property values', () => { + const object = { a: { b: stubTwo } }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const methodOf = _.methodOf(object); + assert.strictEqual(methodOf(path), 2); + }); + }); + + it('should work with a non-string `path`', () => { + const array = lodashStable.times(3, constant); + + lodashStable.each([1, [1]], (path) => { + const methodOf = _.methodOf(array); + assert.strictEqual(methodOf(path), 1); + }); + }); + + it('should coerce `path` to a string', () => { + function fn() {} + fn.toString = lodashStable.constant('fn'); + + const expected = [1, 2, 3, 4], + object = { + null: stubOne, + undefined: stubTwo, + fn: stubThree, + '[object Object]': stubFour, + }, + paths = [null, undefined, fn, {}]; + + lodashStable.times(2, (index) => { + const actual = lodashStable.map(paths, (path) => { + const methodOf = _.methodOf(object); + return methodOf(index ? [path] : path); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should work with inherited property values', () => { + function Foo() {} + Foo.prototype.a = stubOne; + + lodashStable.each(['a', ['a']], (path) => { + const methodOf = _.methodOf(new Foo()); + assert.strictEqual(methodOf(path), 1); + }); + }); + + it('should use a key over a path', () => { + const object = { 'a.b': stubOne, a: { b: stubTwo } }; + + lodashStable.each(['a.b', ['a.b']], (path) => { + const methodOf = _.methodOf(object); + assert.strictEqual(methodOf(path), 1); + }); + }); + + it('should return `undefined` when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, noop); + + lodashStable.each(['constructor', ['constructor']], (path) => { + const actual = lodashStable.map(values, (value, index) => { + const methodOf = index ? _.methodOf() : _.methodOf(value); + return methodOf(path); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should return `undefined` for deep paths when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, noop); + + lodashStable.each( + ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], + (path) => { + const actual = lodashStable.map(values, (value, index) => { + const methodOf = index ? _.methodOf() : _.methodOf(value); + return methodOf(path); + }); + + assert.deepStrictEqual(actual, expected); + }, + ); + }); + + it('should return `undefined` if parts of `path` are missing', () => { + const object = {}, + methodOf = _.methodOf(object); + + lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], (path) => { + assert.strictEqual(methodOf(path), undefined); + }); + }); + + it('should apply partial arguments to function', () => { + const object = { + fn: function () { + return slice.call(arguments); + }, + }; + + const methodOf = _.methodOf(object, 1, 2, 3); + + lodashStable.each(['fn', ['fn']], (path) => { + assert.deepStrictEqual(methodOf(path), [1, 2, 3]); + }); + }); + + it('should invoke deep property methods with the correct `this` binding', () => { + const object = { + a: { + b: function () { + return this.c; + }, + c: 1, + }, + }, + methodOf = _.methodOf(object); + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.strictEqual(methodOf(path), 1); + }); + }); +}); diff --git a/test/methods-using-createWrapper.js b/test/methods-using-createWrapper.js deleted file mode 100644 index df44aa770..000000000 --- a/test/methods-using-createWrapper.js +++ /dev/null @@ -1,198 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, _, push, HOT_COUNT } from './utils.js'; -import bind from '../bind.js'; -import bindKey from '../bindKey.js'; -import partial from '../partial.js'; -import partialRight from '../partialRight.js'; -import last from '../last.js'; - -describe('methods using `createWrapper`', function() { - function fn() { - return slice.call(arguments); - } - - var ph1 = bind.placeholder, - ph2 = bindKey.placeholder, - ph3 = partial.placeholder, - ph4 = partialRight.placeholder; - - it('should work with combinations of partial functions', function() { - var a = partial(fn), - b = partialRight(a, 3), - c = partial(b, 1); - - assert.deepStrictEqual(c(2), [1, 2, 3]); - }); - - it('should work with combinations of bound and partial functions', function() { - var fn = function() { - var result = [this.a]; - push.apply(result, arguments); - return result; - }; - - var expected = [1, 2, 3, 4], - object = { 'a': 1, 'fn': fn }; - - var a = bindKey(object, 'fn'), - b = partialRight(a, 4), - c = partial(b, 2); - - assert.deepStrictEqual(c(3), expected); - - a = bind(fn, object); - b = partialRight(a, 4); - c = partial(b, 2); - - assert.deepStrictEqual(c(3), expected); - - a = partial(fn, 2); - b = bind(a, object); - c = partialRight(b, 4); - - assert.deepStrictEqual(c(3), expected); - }); - - it('should ensure `new combo` is an instance of `func`', function() { - function Foo(a, b, c) { - return b === 0 && object; - } - - var combo = partial(partialRight(Foo, 3), 1), - object = {}; - - assert.ok(new combo(2) instanceof Foo); - assert.strictEqual(new combo(0), object); - }); - - it('should work with combinations of functions with placeholders', function() { - var expected = [1, 2, 3, 4, 5, 6], - object = { 'fn': fn }; - - var a = bindKey(object, 'fn', ph2, 2), - b = partialRight(a, ph4, 6), - c = partial(b, 1, ph3, 4); - - assert.deepStrictEqual(c(3, 5), expected); - - a = bind(fn, object, ph1, 2); - b = partialRight(a, ph4, 6); - c = partial(b, 1, ph3, 4); - - assert.deepStrictEqual(c(3, 5), expected); - - a = partial(fn, ph3, 2); - b = bind(a, object, 1, ph1, 4); - c = partialRight(b, ph4, 6); - - assert.deepStrictEqual(c(3, 5), expected); - }); - - it('should work with combinations of functions with overlapping placeholders', function() { - var expected = [1, 2, 3, 4], - object = { 'fn': fn }; - - var a = bindKey(object, 'fn', ph2, 2), - b = partialRight(a, ph4, 4), - c = partial(b, ph3, 3); - - assert.deepStrictEqual(c(1), expected); - - a = bind(fn, object, ph1, 2); - b = partialRight(a, ph4, 4); - c = partial(b, ph3, 3); - - assert.deepStrictEqual(c(1), expected); - - a = partial(fn, ph3, 2); - b = bind(a, object, ph1, 3); - c = partialRight(b, ph4, 4); - - assert.deepStrictEqual(c(1), expected); - }); - - it('should work with recursively bound functions', function() { - var fn = function() { - return this.a; - }; - - var a = bind(fn, { 'a': 1 }), - b = bind(a, { 'a': 2 }), - c = bind(b, { 'a': 3 }); - - assert.strictEqual(c(), 1); - }); - - it('should work when hot', function() { - lodashStable.times(2, function(index) { - var fn = function() { - var result = [this]; - push.apply(result, arguments); - return result; - }; - - var object = {}, - bound1 = index ? bind(fn, object, 1) : bind(fn, object), - expected = [object, 1, 2, 3]; - - var actual = last(lodashStable.times(HOT_COUNT, function() { - var bound2 = index ? bind(bound1, null, 2) : bind(bound1); - return index ? bound2(3) : bound2(1, 2, 3); - })); - - assert.deepStrictEqual(actual, expected); - - actual = last(lodashStable.times(HOT_COUNT, function() { - var bound1 = index ? bind(fn, object, 1) : bind(fn, object), - bound2 = index ? bind(bound1, null, 2) : bind(bound1); - - return index ? bound2(3) : bound2(1, 2, 3); - })); - - assert.deepStrictEqual(actual, expected); - }); - - lodashStable.each(['curry', 'curryRight'], function(methodName, index) { - var fn = function(a, b, c) { return [a, b, c]; }, - curried = _[methodName](fn), - expected = index ? [3, 2, 1] : [1, 2, 3]; - - var actual = last(lodashStable.times(HOT_COUNT, function() { - return curried(1)(2)(3); - })); - - assert.deepStrictEqual(actual, expected); - - actual = last(lodashStable.times(HOT_COUNT, function() { - var curried = _[methodName](fn); - return curried(1)(2)(3); - })); - - assert.deepStrictEqual(actual, expected); - }); - - lodashStable.each(['partial', 'partialRight'], function(methodName, index) { - var func = _[methodName], - fn = function() { return slice.call(arguments); }, - par1 = func(fn, 1), - expected = index ? [3, 2, 1] : [1, 2, 3]; - - var actual = last(lodashStable.times(HOT_COUNT, function() { - var par2 = func(par1, 2); - return par2(3); - })); - - assert.deepStrictEqual(actual, expected); - - actual = last(lodashStable.times(HOT_COUNT, function() { - var par1 = func(fn, 1), - par2 = func(par1, 2); - - return par2(3); - })); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/methods-using-createWrapper.spec.ts b/test/methods-using-createWrapper.spec.ts new file mode 100644 index 000000000..7a62d5de2 --- /dev/null +++ b/test/methods-using-createWrapper.spec.ts @@ -0,0 +1,210 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, _, push, HOT_COUNT } from './utils'; +import bind from '../src/bind'; +import bindKey from '../src/bindKey'; +import partial from '../src/partial'; +import partialRight from '../src/partialRight'; +import last from '../src/last'; + +describe('methods using `createWrapper`', () => { + function fn() { + return slice.call(arguments); + } + + const ph1 = bind.placeholder, + ph2 = bindKey.placeholder, + ph3 = partial.placeholder, + ph4 = partialRight.placeholder; + + it('should work with combinations of partial functions', () => { + const a = partial(fn), + b = partialRight(a, 3), + c = partial(b, 1); + + assert.deepStrictEqual(c(2), [1, 2, 3]); + }); + + it('should work with combinations of bound and partial functions', () => { + const fn = function () { + const result = [this.a]; + push.apply(result, arguments); + return result; + }; + + const expected = [1, 2, 3, 4], + object = { a: 1, fn: fn }; + + let a = bindKey(object, 'fn'), + b = partialRight(a, 4), + c = partial(b, 2); + + assert.deepStrictEqual(c(3), expected); + + a = bind(fn, object); + b = partialRight(a, 4); + c = partial(b, 2); + + assert.deepStrictEqual(c(3), expected); + + a = partial(fn, 2); + b = bind(a, object); + c = partialRight(b, 4); + + assert.deepStrictEqual(c(3), expected); + }); + + it('should ensure `new combo` is an instance of `func`', () => { + function Foo(a, b, c) { + return b === 0 && object; + } + + var combo = partial(partialRight(Foo, 3), 1), + object = {}; + + assert.ok(new combo(2) instanceof Foo); + assert.strictEqual(new combo(0), object); + }); + + it('should work with combinations of functions with placeholders', () => { + const expected = [1, 2, 3, 4, 5, 6], + object = { fn: fn }; + + let a = bindKey(object, 'fn', ph2, 2), + b = partialRight(a, ph4, 6), + c = partial(b, 1, ph3, 4); + + assert.deepStrictEqual(c(3, 5), expected); + + a = bind(fn, object, ph1, 2); + b = partialRight(a, ph4, 6); + c = partial(b, 1, ph3, 4); + + assert.deepStrictEqual(c(3, 5), expected); + + a = partial(fn, ph3, 2); + b = bind(a, object, 1, ph1, 4); + c = partialRight(b, ph4, 6); + + assert.deepStrictEqual(c(3, 5), expected); + }); + + it('should work with combinations of functions with overlapping placeholders', () => { + const expected = [1, 2, 3, 4], + object = { fn: fn }; + + let a = bindKey(object, 'fn', ph2, 2), + b = partialRight(a, ph4, 4), + c = partial(b, ph3, 3); + + assert.deepStrictEqual(c(1), expected); + + a = bind(fn, object, ph1, 2); + b = partialRight(a, ph4, 4); + c = partial(b, ph3, 3); + + assert.deepStrictEqual(c(1), expected); + + a = partial(fn, ph3, 2); + b = bind(a, object, ph1, 3); + c = partialRight(b, ph4, 4); + + assert.deepStrictEqual(c(1), expected); + }); + + it('should work with recursively bound functions', () => { + const fn = function () { + return this.a; + }; + + const a = bind(fn, { a: 1 }), + b = bind(a, { a: 2 }), + c = bind(b, { a: 3 }); + + assert.strictEqual(c(), 1); + }); + + it('should work when hot', () => { + lodashStable.times(2, (index) => { + const fn = function () { + const result = [this]; + push.apply(result, arguments); + return result; + }; + + const object = {}, + bound1 = index ? bind(fn, object, 1) : bind(fn, object), + expected = [object, 1, 2, 3]; + + let actual = last( + lodashStable.times(HOT_COUNT, () => { + const bound2 = index ? bind(bound1, null, 2) : bind(bound1); + return index ? bound2(3) : bound2(1, 2, 3); + }), + ); + + assert.deepStrictEqual(actual, expected); + + actual = last( + lodashStable.times(HOT_COUNT, () => { + const bound1 = index ? bind(fn, object, 1) : bind(fn, object), + bound2 = index ? bind(bound1, null, 2) : bind(bound1); + + return index ? bound2(3) : bound2(1, 2, 3); + }), + ); + + assert.deepStrictEqual(actual, expected); + }); + + lodashStable.each(['curry', 'curryRight'], (methodName, index) => { + const fn = function (a, b, c) { + return [a, b, c]; + }, + curried = _[methodName](fn), + expected = index ? [3, 2, 1] : [1, 2, 3]; + + let actual = last(lodashStable.times(HOT_COUNT, () => curried(1)(2)(3))); + + assert.deepStrictEqual(actual, expected); + + actual = last( + lodashStable.times(HOT_COUNT, () => { + const curried = _[methodName](fn); + return curried(1)(2)(3); + }), + ); + + assert.deepStrictEqual(actual, expected); + }); + + lodashStable.each(['partial', 'partialRight'], (methodName, index) => { + const func = _[methodName], + fn = function () { + return slice.call(arguments); + }, + par1 = func(fn, 1), + expected = index ? [3, 2, 1] : [1, 2, 3]; + + let actual = last( + lodashStable.times(HOT_COUNT, () => { + const par2 = func(par1, 2); + return par2(3); + }), + ); + + assert.deepStrictEqual(actual, expected); + + actual = last( + lodashStable.times(HOT_COUNT, () => { + const par1 = func(fn, 1), + par2 = func(par1, 2); + + return par2(3); + }), + ); + + assert.deepStrictEqual(actual, expected); + }); + }); +}); diff --git a/test/min.js b/test/min.js deleted file mode 100644 index 271d44431..000000000 --- a/test/min.js +++ /dev/null @@ -1,27 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, noop } from './utils.js'; -import min from '../min.js'; - -describe('min', function() { - it('should return the smallest value from a collection', function() { - assert.strictEqual(min([1, 2, 3]), 1); - }); - - it('should return `undefined` for empty collections', function() { - var values = falsey.concat([[]]), - expected = lodashStable.map(values, noop); - - var actual = lodashStable.map(values, function(value, index) { - try { - return index ? min(value) : min(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with non-numeric collection values', function() { - assert.strictEqual(min(['a', 'b']), 'a'); - }); -}); diff --git a/test/min.spec.ts b/test/min.spec.ts new file mode 100644 index 000000000..0800b9e8e --- /dev/null +++ b/test/min.spec.ts @@ -0,0 +1,27 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, noop } from './utils'; +import min from '../src/min'; + +describe('min', () => { + it('should return the smallest value from a collection', () => { + assert.strictEqual(min([1, 2, 3]), 1); + }); + + it('should return `undefined` for empty collections', () => { + const values = falsey.concat([[]]), + expected = lodashStable.map(values, noop); + + const actual = lodashStable.map(values, (value: false, index: number) => { + try { + return index ? min(value) : min(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with non-numeric collection values', () => { + assert.strictEqual(min(['a', 'b']), 'a'); + }); +}); diff --git a/test/mixin.js b/test/mixin.js deleted file mode 100644 index 4b78cf848..000000000 --- a/test/mixin.js +++ /dev/null @@ -1,189 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, getUnwrappedValue, noop } from './utils.js'; -import has from '../has.js'; -import mixin from '../mixin.js'; -import prototype from '../prototype.js'; -import countBy from '../countBy.js'; -import filter from '../filter.js'; - -describe('mixin', function() { - function reset(wrapper) { - delete wrapper.a; - delete wrapper.prototype.a; - delete wrapper.b; - delete wrapper.prototype.b; - } - - function Wrapper(value) { - if (!(this instanceof Wrapper)) { - return new Wrapper(value); - } - if (has(value, '__wrapped__')) { - var actions = slice.call(value.__actions__), - chain = value.__chain__; - - value = value.__wrapped__; - } - this.__wrapped__ = value; - this.__actions__ = actions || []; - this.__chain__ = chain || false; - } - - Wrapper.prototype.value = function() { - return getUnwrappedValue(this); - }; - - var array = ['a'], - source = { 'a': function(array) { return array[0]; }, 'b': 'B' }; - - it('should mixin `source` methods into lodash', function() { - mixin(source); - - assert.strictEqual(_.a(array), 'a'); - assert.strictEqual(_(array).a().value(), 'a'); - assert.notOk('b' in _); - assert.notOk('b' in prototype); - - reset(_); - }); - - it('should mixin chaining methods by reference', function() { - mixin(source); - _.a = stubB; - - assert.strictEqual(_.a(array), 'b'); - assert.strictEqual(_(array).a().value(), 'a'); - - reset(_); - }); - - it('should use a default `object` of `this`', function() { - var object = lodashStable.create(_); - object.mixin(source); - - assert.strictEqual(object.a(array), 'a'); - assert.ok(!('a' in _)); - assert.ok(!('a' in prototype)); - - reset(_); - }); - - it('should accept an `object`', function() { - var object = {}; - mixin(object, source); - assert.strictEqual(object.a(array), 'a'); - }); - - it('should accept a function `object`', function() { - mixin(Wrapper, source); - - var wrapped = Wrapper(array), - actual = wrapped.a(); - - assert.strictEqual(actual.value(), 'a'); - assert.ok(actual instanceof Wrapper); - - reset(Wrapper); - }); - - it('should return `object`', function() { - var object = {}; - assert.strictEqual(mixin(object, source), object); - assert.strictEqual(mixin(Wrapper, source), Wrapper); - assert.strictEqual(mixin(), _); - - reset(Wrapper); - }); - - it('should not assign inherited `source` methods', function() { - function Foo() {} - Foo.prototype.a = noop; - - var object = {}; - assert.strictEqual(mixin(object, new Foo), object); - }); - - it('should accept an `options`', function() { - function message(func, chain) { - return (func === _ ? 'lodash' : 'given') + ' function should ' + (chain ? '' : 'not ') + 'chain'; - } - - lodashStable.each([_, Wrapper], function(func) { - lodashStable.each([{ 'chain': false }, { 'chain': true }], function(options) { - if (func === _) { - mixin(source, options); - } else { - mixin(func, source, options); - } - var wrapped = func(array), - actual = wrapped.a(); - - if (options.chain) { - assert.strictEqual(actual.value(), 'a', message(func, true)); - assert.ok(actual instanceof func, message(func, true)); - } else { - assert.strictEqual(actual, 'a', message(func, false)); - assert.notOk(actual instanceof func, message(func, false)); - } - reset(func); - }); - }); - }); - - it('should not extend lodash when an `object` is given with an empty `options` object', function() { - mixin({ 'a': noop }, {}); - assert.ok(!('a' in _)); - reset(_); - }); - - it('should not error for non-object `options` values', function() { - var pass = true; - - try { - mixin({}, source, 1); - } catch (e) { - pass = false; - } - assert.ok(pass); - - pass = true; - - try { - mixin(source, 1); - } catch (e) { - pass = false; - } - assert.ok(pass); - - reset(_); - }); - - it('should not return the existing wrapped value when chaining', function() { - lodashStable.each([_, Wrapper], function(func) { - if (func === _) { - var wrapped = _(source), - actual = wrapped.mixin(); - - assert.strictEqual(actual.value(), _); - } - else { - wrapped = _(func); - actual = wrapped.mixin(source); - assert.notStrictEqual(actual, wrapped); - } - reset(func); - }); - }); - - it('should produce methods that work in a lazy sequence', function() { - mixin({ 'a': countBy, 'b': filter }); - - var array = lodashStable.range(LARGE_ARRAY_SIZE), - actual = _(array).a().map(square).b(isEven).take().value(); - - assert.deepEqual(actual, _.take(_.b(_.map(_.a(array), square), isEven))); - - reset(_); - }); -}); diff --git a/test/mixin.spec.ts b/test/mixin.spec.ts new file mode 100644 index 000000000..286ca6e83 --- /dev/null +++ b/test/mixin.spec.ts @@ -0,0 +1,193 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, slice, getUnwrappedValue, noop } from './utils'; +import has from '../src/has'; +import mixin from '../src/mixin'; +import prototype from '../src/prototype'; +import countBy from '../src/countBy'; +import filter from '../src/filter'; + +describe('mixin', () => { + function reset(wrapper) { + delete wrapper.a; + delete wrapper.prototype.a; + delete wrapper.b; + delete wrapper.prototype.b; + } + + function Wrapper(value) { + if (!(this instanceof Wrapper)) { + return new Wrapper(value); + } + if (has(value, '__wrapped__')) { + var actions = slice.call(value.__actions__), + chain = value.__chain__; + + value = value.__wrapped__; + } + this.__wrapped__ = value; + this.__actions__ = actions || []; + this.__chain__ = chain || false; + } + + Wrapper.prototype.value = function () { + return getUnwrappedValue(this); + }; + + const array = ['a'], + source = { + a: function (array) { + return array[0]; + }, + b: 'B', + }; + + it('should mixin `source` methods into lodash', () => { + mixin(source); + + assert.strictEqual(_.a(array), 'a'); + assert.strictEqual(_(array).a().value(), 'a'); + assert.notOk('b' in _); + assert.notOk('b' in prototype); + + reset(_); + }); + + it('should mixin chaining methods by reference', () => { + mixin(source); + _.a = stubB; + + assert.strictEqual(_.a(array), 'b'); + assert.strictEqual(_(array).a().value(), 'a'); + + reset(_); + }); + + it('should use a default `object` of `this`', () => { + const object = lodashStable.create(_); + object.mixin(source); + + assert.strictEqual(object.a(array), 'a'); + assert.ok(!('a' in _)); + assert.ok(!('a' in prototype)); + + reset(_); + }); + + it('should accept an `object`', () => { + const object = {}; + mixin(object, source); + assert.strictEqual(object.a(array), 'a'); + }); + + it('should accept a function `object`', () => { + mixin(Wrapper, source); + + const wrapped = Wrapper(array), + actual = wrapped.a(); + + assert.strictEqual(actual.value(), 'a'); + assert.ok(actual instanceof Wrapper); + + reset(Wrapper); + }); + + it('should return `object`', () => { + const object = {}; + assert.strictEqual(mixin(object, source), object); + assert.strictEqual(mixin(Wrapper, source), Wrapper); + assert.strictEqual(mixin(), _); + + reset(Wrapper); + }); + + it('should not assign inherited `source` methods', () => { + function Foo() {} + Foo.prototype.a = noop; + + const object = {}; + assert.strictEqual(mixin(object, new Foo()), object); + }); + + it('should accept an `options`', () => { + function message(func, chain) { + return `${func === _ ? 'lodash' : 'given'} function should ${chain ? '' : 'not '}chain`; + } + + lodashStable.each([_, Wrapper], (func) => { + lodashStable.each([{ chain: false }, { chain: true }], (options) => { + if (func === _) { + mixin(source, options); + } else { + mixin(func, source, options); + } + const wrapped = func(array), + actual = wrapped.a(); + + if (options.chain) { + assert.strictEqual(actual.value(), 'a', message(func, true)); + assert.ok(actual instanceof func, message(func, true)); + } else { + assert.strictEqual(actual, 'a', message(func, false)); + assert.notOk(actual instanceof func, message(func, false)); + } + reset(func); + }); + }); + }); + + it('should not extend lodash when an `object` is given with an empty `options` object', () => { + mixin({ a: noop }, {}); + assert.ok(!('a' in _)); + reset(_); + }); + + it('should not error for non-object `options` values', () => { + let pass = true; + + try { + mixin({}, source, 1); + } catch (e) { + pass = false; + } + assert.ok(pass); + + pass = true; + + try { + mixin(source, 1); + } catch (e) { + pass = false; + } + assert.ok(pass); + + reset(_); + }); + + it('should not return the existing wrapped value when chaining', () => { + lodashStable.each([_, Wrapper], (func) => { + if (func === _) { + var wrapped = _(source), + actual = wrapped.mixin(); + + assert.strictEqual(actual.value(), _); + } else { + wrapped = _(func); + actual = wrapped.mixin(source); + assert.notStrictEqual(actual, wrapped); + } + reset(func); + }); + }); + + it('should produce methods that work in a lazy sequence', () => { + mixin({ a: countBy, b: filter }); + + const array = lodashStable.range(LARGE_ARRAY_SIZE), + actual = _(array).a().map(square).b(isEven).take().value(); + + assert.deepEqual(actual, _.take(_.b(_.map(_.a(array), square), isEven))); + + reset(_); + }); +}); diff --git a/test/multiply.spec.ts b/test/multiply.spec.ts new file mode 100644 index 000000000..b11604d5e --- /dev/null +++ b/test/multiply.spec.ts @@ -0,0 +1,15 @@ +import assert from 'node:assert'; +import multiply from '../src/multiply'; + +describe('multiply', () => { + it('should multiply two numbers', () => { + assert.strictEqual(multiply(6, 4), 24); + assert.strictEqual(multiply(-6, 4), -24); + assert.strictEqual(multiply(-6, -4), 24); + }); + + it('should coerce arguments to numbers', () => { + assert.strictEqual(multiply('6', '4'), 24); + assert.deepStrictEqual(multiply('x', 'y'), NaN); + }); +}); diff --git a/test/multiply.test.js b/test/multiply.test.js deleted file mode 100644 index 23e966fb9..000000000 --- a/test/multiply.test.js +++ /dev/null @@ -1,15 +0,0 @@ -import assert from 'assert'; -import multiply from '../multiply.js'; - -describe('multiply', function() { - it('should multiply two numbers', function() { - assert.strictEqual(multiply(6, 4), 24); - assert.strictEqual(multiply(-6, 4), -24); - assert.strictEqual(multiply(-6, -4), 24); - }); - - it('should coerce arguments to numbers', function() { - assert.strictEqual(multiply('6', '4'), 24); - assert.deepStrictEqual(multiply('x', 'y'), NaN); - }); -}); diff --git a/test/negate.js b/test/negate.js deleted file mode 100644 index 3f7725592..000000000 --- a/test/negate.js +++ /dev/null @@ -1,39 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, isEven, stubTrue } from './utils.js'; - -describe('negate', function() { - it('should create a function that negates the result of `func`', function() { - var negate = _.negate(isEven); - - assert.strictEqual(negate(1), true); - assert.strictEqual(negate(2), false); - }); - - it('should create a function that negates the result of `func`', function() { - var negate = _.negate(isEven); - - assert.strictEqual(negate(1), true); - assert.strictEqual(negate(2), false); - }); - - it('should create a function that accepts multiple arguments', function() { - var argCount, - count = 5, - negate = _.negate(function() { argCount = arguments.length; }), - expected = lodashStable.times(count, stubTrue); - - var actual = lodashStable.times(count, function(index) { - switch (index) { - case 0: negate(); break; - case 1: negate(1); break; - case 2: negate(1, 2); break; - case 3: negate(1, 2, 3); break; - case 4: negate(1, 2, 3, 4); - } - return argCount == index; - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/negate.spec.ts b/test/negate.spec.ts new file mode 100644 index 000000000..057f49fa7 --- /dev/null +++ b/test/negate.spec.ts @@ -0,0 +1,50 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, isEven, stubTrue } from './utils'; + +describe('negate', () => { + it('should create a function that negates the result of `func`', () => { + const negate = _.negate(isEven); + + assert.strictEqual(negate(1), true); + assert.strictEqual(negate(2), false); + }); + + it('should create a function that negates the result of `func`', () => { + const negate = _.negate(isEven); + + assert.strictEqual(negate(1), true); + assert.strictEqual(negate(2), false); + }); + + it('should create a function that accepts multiple arguments', () => { + let argCount, + count = 5, + negate = _.negate(function () { + argCount = arguments.length; + }), + expected = lodashStable.times(count, stubTrue); + + const actual = lodashStable.times(count, (index) => { + switch (index) { + case 0: + negate(); + break; + case 1: + negate(1); + break; + case 2: + negate(1, 2); + break; + case 3: + negate(1, 2, 3); + break; + case 4: + negate(1, 2, 3, 4); + } + return argCount == index; + }); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/noConflict.js b/test/noConflict.js deleted file mode 100644 index 419130d5b..000000000 --- a/test/noConflict.js +++ /dev/null @@ -1,33 +0,0 @@ -import assert from 'assert'; -import { oldDash, coverage, document, isModularize, realm, filePath } from './utils.js'; -import noConflict from '../noConflict.js'; - -describe('noConflict', function() { - it('should return the `lodash` function', function() { - assert.strictEqual(noConflict(), oldDash); - assert.notStrictEqual(root._, oldDash); - root._ = oldDash; - }); - - it('should restore `_` only if `lodash` is the current `_` value', function() { - var object = root._ = {}; - assert.strictEqual(noConflict(), oldDash); - assert.strictEqual(root._, object); - root._ = oldDash; - }); - - it('should work with a `root` of `this`', function() { - if (!coverage && !document && !isModularize && realm.object) { - var fs = require('fs'), - vm = require('vm'), - expected = {}, - context = vm.createContext({ '_': expected, 'console': console }), - source = fs.readFileSync(filePath, 'utf8'); - - vm.runInContext(source + '\nthis.lodash = this._.noConflict()', context); - - assert.strictEqual(context._, expected); - assert.ok(context.lodash); - } - }); -}); diff --git a/test/noConflict.spec.ts b/test/noConflict.spec.ts new file mode 100644 index 000000000..04a8043d8 --- /dev/null +++ b/test/noConflict.spec.ts @@ -0,0 +1,33 @@ +import assert from 'node:assert'; +import { oldDash, coverage, document, isModularize, realm, filePath } from './utils'; +import noConflict from '../src/noConflict'; + +describe('noConflict', () => { + it('should return the `lodash` function', () => { + assert.strictEqual(noConflict(), oldDash); + assert.notStrictEqual(root._, oldDash); + root._ = oldDash; + }); + + it('should restore `_` only if `lodash` is the current `_` value', () => { + const object = (root._ = {}); + assert.strictEqual(noConflict(), oldDash); + assert.strictEqual(root._, object); + root._ = oldDash; + }); + + it('should work with a `root` of `this`', () => { + if (!coverage && !document && !isModularize && realm.object) { + const fs = require('fs'), + vm = require('vm'), + expected = {}, + context = vm.createContext({ _: expected, console: console }), + source = fs.readFileSync(filePath, 'utf8'); + + vm.runInContext(`${source}\nthis.lodash = this._.noConflict()`, context); + + assert.strictEqual(context._, expected); + assert.ok(context.lodash); + } + }); +}); diff --git a/test/now.js b/test/now.js deleted file mode 100644 index 6b2febb24..000000000 --- a/test/now.js +++ /dev/null @@ -1,26 +0,0 @@ -import assert from 'assert'; -import { _, stubA } from './utils.js'; - -describe('now', function() { - it('should return the number of milliseconds that have elapsed since the Unix epoch', function(done) { - var stamp = +new Date, - actual = _.now(); - - assert.ok(actual >= stamp); - - setTimeout(function() { - assert.ok(_.now() > actual); - done(); - }, 32); - }); - - it('should work with mocked `Date.now`', function() { - var now = Date.now; - Date.now = stubA; - - var actual = _.now(); - Date.now = now; - - assert.strictEqual(actual, 'a'); - }); -}); diff --git a/test/now.spec.ts b/test/now.spec.ts new file mode 100644 index 000000000..72a541c6b --- /dev/null +++ b/test/now.spec.ts @@ -0,0 +1,26 @@ +import assert from 'node:assert'; +import { _, stubA } from './utils'; + +describe('now', () => { + it('should return the number of milliseconds that have elapsed since the Unix epoch', (done) => { + const stamp = +new Date(), + actual = _.now(); + + assert.ok(actual >= stamp); + + setTimeout(() => { + assert.ok(_.now() > actual); + done(); + }, 32); + }); + + it('should work with mocked `Date.now`', () => { + const now = Date.now; + Date.now = stubA; + + const actual = _.now(); + Date.now = now; + + assert.strictEqual(actual, 'a'); + }); +}); diff --git a/test/nth.js b/test/nth.js deleted file mode 100644 index 49c0fcf2e..000000000 --- a/test/nth.js +++ /dev/null @@ -1,69 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubA, stubB, noop } from './utils.js'; -import nth from '../nth.js'; - -describe('nth', function() { - var array = ['a', 'b', 'c', 'd']; - - it('should get the nth element of `array`', function() { - var actual = lodashStable.map(array, function(value, index) { - return nth(array, index); - }); - - assert.deepStrictEqual(actual, array); - }); - - it('should work with a negative `n`', function() { - var actual = lodashStable.map(lodashStable.range(1, array.length + 1), function(n) { - return nth(array, -n); - }); - - assert.deepStrictEqual(actual, ['d', 'c', 'b', 'a']); - }); - - it('should coerce `n` to an integer', function() { - var values = falsey, - expected = lodashStable.map(values, stubA); - - var actual = lodashStable.map(values, function(n) { - return n ? nth(array, n) : nth(array); - }); - - assert.deepStrictEqual(actual, expected); - - values = ['1', 1.6]; - expected = lodashStable.map(values, stubB); - - actual = lodashStable.map(values, function(n) { - return nth(array, n); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `undefined` for empty arrays', function() { - var values = [null, undefined, []], - expected = lodashStable.map(values, noop); - - var actual = lodashStable.map(values, function(array) { - return nth(array, 1); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `undefined` for non-indexes', function() { - var array = [1, 2], - values = [Infinity, array.length], - expected = lodashStable.map(values, noop); - - array[-1] = 3; - - var actual = lodashStable.map(values, function(n) { - return nth(array, n); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/nth.spec.ts b/test/nth.spec.ts new file mode 100644 index 000000000..975d1bc64 --- /dev/null +++ b/test/nth.spec.ts @@ -0,0 +1,59 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubA, stubB, noop } from './utils'; +import nth from '../src/nth'; + +describe('nth', () => { + const array = ['a', 'b', 'c', 'd']; + + it('should get the nth element of `array`', () => { + const actual = lodashStable.map(array, (value, index) => nth(array, index)); + + assert.deepStrictEqual(actual, array); + }); + + it('should work with a negative `n`', () => { + const actual = lodashStable.map(lodashStable.range(1, array.length + 1), (n) => + nth(array, -n), + ); + + assert.deepStrictEqual(actual, ['d', 'c', 'b', 'a']); + }); + + it('should coerce `n` to an integer', () => { + let values = falsey, + expected = lodashStable.map(values, stubA); + + let actual = lodashStable.map(values, (n) => (n ? nth(array, n) : nth(array))); + + assert.deepStrictEqual(actual, expected); + + values = ['1', 1.6]; + expected = lodashStable.map(values, stubB); + + actual = lodashStable.map(values, (n) => nth(array, n)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `undefined` for empty arrays', () => { + const values = [null, undefined, []], + expected = lodashStable.map(values, noop); + + const actual = lodashStable.map(values, (array) => nth(array, 1)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `undefined` for non-indexes', () => { + const array = [1, 2], + values = [Infinity, array.length], + expected = lodashStable.map(values, noop); + + array[-1] = 3; + + const actual = lodashStable.map(values, (n) => nth(array, n)); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/nthArg.js b/test/nthArg.js deleted file mode 100644 index 387e15f7d..000000000 --- a/test/nthArg.js +++ /dev/null @@ -1,65 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, falsey, stubA, stubB, noop } from './utils.js'; -import nthArg from '../nthArg.js'; - -describe('nthArg', function() { - var args = ['a', 'b', 'c', 'd']; - - it('should create a function that returns its nth argument', function() { - var actual = lodashStable.map(args, function(value, index) { - var func = nthArg(index); - return func.apply(undefined, args); - }); - - assert.deepStrictEqual(actual, args); - }); - - it('should work with a negative `n`', function() { - var actual = lodashStable.map(lodashStable.range(1, args.length + 1), function(n) { - var func = nthArg(-n); - return func.apply(undefined, args); - }); - - assert.deepStrictEqual(actual, ['d', 'c', 'b', 'a']); - }); - - it('should coerce `n` to an integer', function() { - var values = falsey, - expected = lodashStable.map(values, stubA); - - var actual = lodashStable.map(values, function(n) { - var func = n ? nthArg(n) : nthArg(); - return func.apply(undefined, args); - }); - - assert.deepStrictEqual(actual, expected); - - values = ['1', 1.6]; - expected = lodashStable.map(values, stubB); - - actual = lodashStable.map(values, function(n) { - var func = nthArg(n); - return func.apply(undefined, args); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `undefined` for empty arrays', function() { - var func = nthArg(1); - assert.strictEqual(func(), undefined); - }); - - it('should return `undefined` for non-indexes', function() { - var values = [Infinity, args.length], - expected = lodashStable.map(values, noop); - - var actual = lodashStable.map(values, function(n) { - var func = nthArg(n); - return func.apply(undefined, args); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/nthArg.spec.ts b/test/nthArg.spec.ts new file mode 100644 index 000000000..21a74ffab --- /dev/null +++ b/test/nthArg.spec.ts @@ -0,0 +1,65 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, falsey, stubA, stubB, noop } from './utils'; +import nthArg from '../src/nthArg'; + +describe('nthArg', () => { + const args = ['a', 'b', 'c', 'd']; + + it('should create a function that returns its nth argument', () => { + const actual = lodashStable.map(args, (value, index) => { + const func = nthArg(index); + return func.apply(undefined, args); + }); + + assert.deepStrictEqual(actual, args); + }); + + it('should work with a negative `n`', () => { + const actual = lodashStable.map(lodashStable.range(1, args.length + 1), (n) => { + const func = nthArg(-n); + return func.apply(undefined, args); + }); + + assert.deepStrictEqual(actual, ['d', 'c', 'b', 'a']); + }); + + it('should coerce `n` to an integer', () => { + let values = falsey, + expected = lodashStable.map(values, stubA); + + let actual = lodashStable.map(values, (n) => { + const func = n ? nthArg(n) : nthArg(); + return func.apply(undefined, args); + }); + + assert.deepStrictEqual(actual, expected); + + values = ['1', 1.6]; + expected = lodashStable.map(values, stubB); + + actual = lodashStable.map(values, (n) => { + const func = nthArg(n); + return func.apply(undefined, args); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `undefined` for empty arrays', () => { + const func = nthArg(1); + assert.strictEqual(func(), undefined); + }); + + it('should return `undefined` for non-indexes', () => { + const values = [Infinity, args.length], + expected = lodashStable.map(values, noop); + + const actual = lodashStable.map(values, (n) => { + const func = nthArg(n); + return func.apply(undefined, args); + }); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/number-coercion-methods.js b/test/number-coercion-methods.js deleted file mode 100644 index edf982d62..000000000 --- a/test/number-coercion-methods.js +++ /dev/null @@ -1,248 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - _, - identity, - whitespace, - MAX_SAFE_INTEGER, - MAX_INTEGER, - MAX_ARRAY_LENGTH, - symbol, - falsey, -} from './utils.js'; - -describe('number coercion methods', function() { - lodashStable.each(['toFinite', 'toInteger', 'toNumber', 'toSafeInteger'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should preserve the sign of `0`', function() { - var values = [0, '0', -0, '-0'], - expected = [[0, Infinity], [0, Infinity], [-0, -Infinity], [-0, -Infinity]]; - - lodashStable.times(2, function(index) { - var others = lodashStable.map(values, index ? Object : identity); - - var actual = lodashStable.map(others, function(value) { - var result = func(value); - return [result, 1 / result]; - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - }); - - lodashStable.each(['toFinite', 'toInteger', 'toLength', 'toNumber', 'toSafeInteger'], function(methodName) { - var func = _[methodName], - isToFinite = methodName == 'toFinite', - isToLength = methodName == 'toLength', - isToNumber = methodName == 'toNumber', - isToSafeInteger = methodName == 'toSafeInteger'; - - function negative(string) { - return '-' + string; - } - - function pad(string) { - return whitespace + string + whitespace; - } - - function positive(string) { - return '+' + string; - } - - it('`_.' + methodName + '` should pass thru primitive number values', function() { - var values = [0, 1, NaN]; - - var expected = lodashStable.map(values, function(value) { - return (!isToNumber && value !== value) ? 0 : value; - }); - - var actual = lodashStable.map(values, func); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should convert number primitives and objects to numbers', function() { - var values = [2, 1.2, MAX_SAFE_INTEGER, MAX_INTEGER, Infinity, NaN]; - - var expected = lodashStable.map(values, function(value) { - if (!isToNumber) { - if (!isToFinite && value == 1.2) { - value = 1; - } - else if (value == Infinity) { - value = MAX_INTEGER; - } - else if (value !== value) { - value = 0; - } - if (isToLength || isToSafeInteger) { - value = Math.min(value, isToLength ? MAX_ARRAY_LENGTH : MAX_SAFE_INTEGER); - } - } - var neg = isToLength ? 0 : -value; - return [value, value, neg, neg]; - }); - - var actual = lodashStable.map(values, function(value) { - return [func(value), func(Object(value)), func(-value), func(Object(-value))]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should convert string primitives and objects to numbers', function() { - var transforms = [identity, pad, positive, negative]; - - var values = [ - '10', '1.234567890', (MAX_SAFE_INTEGER + ''), - '1e+308', '1e308', '1E+308', '1E308', - '5e-324', '5E-324', - 'Infinity', 'NaN' - ]; - - var expected = lodashStable.map(values, function(value) { - var n = +value; - if (!isToNumber) { - if (!isToFinite && n == 1.234567890) { - n = 1; - } - else if (n == Infinity) { - n = MAX_INTEGER; - } - else if ((!isToFinite && n == Number.MIN_VALUE) || n !== n) { - n = 0; - } - if (isToLength || isToSafeInteger) { - n = Math.min(n, isToLength ? MAX_ARRAY_LENGTH : MAX_SAFE_INTEGER); - } - } - var neg = isToLength ? 0 : -n; - return [n, n, n, n, n, n, neg, neg]; - }); - - var actual = lodashStable.map(values, function(value) { - return lodashStable.flatMap(transforms, function(mod) { - return [func(mod(value)), func(Object(mod(value)))]; - }); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should convert binary/octal strings to numbers', function() { - var numbers = [42, 5349, 1715004], - transforms = [identity, pad], - values = ['0b101010', '0o12345', '0x1a2b3c']; - - var expected = lodashStable.map(numbers, function(n) { - return lodashStable.times(8, lodashStable.constant(n)); - }); - - var actual = lodashStable.map(values, function(value) { - var upper = value.toUpperCase(); - return lodashStable.flatMap(transforms, function(mod) { - return [func(mod(value)), func(Object(mod(value))), func(mod(upper)), func(Object(mod(upper)))]; - }); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should convert invalid binary/octal strings to `' + (isToNumber ? 'NaN' : '0') + '`', function() { - var transforms = [identity, pad, positive, negative], - values = ['0b', '0o', '0x', '0b1010102', '0o123458', '0x1a2b3x']; - - var expected = lodashStable.map(values, function(n) { - return lodashStable.times(8, lodashStable.constant(isToNumber ? NaN : 0)); - }); - - var actual = lodashStable.map(values, function(value) { - return lodashStable.flatMap(transforms, function(mod) { - return [func(mod(value)), func(Object(mod(value)))]; - }); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should convert symbols to `' + (isToNumber ? 'NaN' : '0') + '`', function() { - if (Symbol) { - var object1 = Object(symbol), - object2 = Object(symbol), - values = [symbol, object1, object2], - expected = lodashStable.map(values, lodashStable.constant(isToNumber ? NaN : 0)); - - object2.valueOf = undefined; - var actual = lodashStable.map(values, func); - - assert.deepStrictEqual(actual, expected); - } - }); - - it('`_.' + methodName + '` should convert empty values to `0` or `NaN`', function() { - var values = falsey.concat(whitespace); - - var expected = lodashStable.map(values, function(value) { - return (isToNumber && value !== whitespace) ? Number(value) : 0; - }); - - var actual = lodashStable.map(values, function(value, index) { - return index ? func(value) : func(); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should coerce objects to numbers', function() { - var values = [ - {}, - [], - [1], - [1, 2], - { 'valueOf': '1.1' }, - { 'valueOf': '1.1', 'toString': lodashStable.constant('2.2') }, - { 'valueOf': lodashStable.constant('1.1'), 'toString': '2.2' }, - { 'valueOf': lodashStable.constant('1.1'), 'toString': lodashStable.constant('2.2') }, - { 'valueOf': lodashStable.constant('-0x1a2b3c') }, - { 'toString': lodashStable.constant('-0x1a2b3c') }, - { 'valueOf': lodashStable.constant('0o12345') }, - { 'toString': lodashStable.constant('0o12345') }, - { 'valueOf': lodashStable.constant('0b101010') }, - { 'toString': lodashStable.constant('0b101010') } - ]; - - var expected = [ - NaN, 0, 1, NaN, - NaN, 2.2, 1.1, 1.1, - NaN, NaN, - 5349, 5349, - 42, 42 - ]; - - if (isToFinite) { - expected = [ - 0, 0, 1, 0, - 0, 2.2, 1.1, 1.1, - 0, 0, - 5349, 5349, - 42, 42 - ]; - } - else if (!isToNumber) { - expected = [ - 0, 0, 1, 0, - 0, 2, 1, 1, - 0, 0, - 5349, 5349, - 42, 42 - ]; - } - var actual = lodashStable.map(values, func); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/number-coercion-methods.spec.ts b/test/number-coercion-methods.spec.ts new file mode 100644 index 000000000..18a3bb6d3 --- /dev/null +++ b/test/number-coercion-methods.spec.ts @@ -0,0 +1,261 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + _, + identity, + whitespace, + MAX_SAFE_INTEGER, + MAX_INTEGER, + MAX_ARRAY_LENGTH, + symbol, + falsey, +} from './utils'; + +describe('number coercion methods', () => { + lodashStable.each(['toFinite', 'toInteger', 'toNumber', 'toSafeInteger'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should preserve the sign of \`0\``, () => { + const values = [0, '0', -0, '-0'], + expected = [ + [0, Infinity], + [0, Infinity], + [-0, -Infinity], + [-0, -Infinity], + ]; + + lodashStable.times(2, (index) => { + const others = lodashStable.map(values, index ? Object : identity); + + const actual = lodashStable.map(others, (value) => { + const result = func(value); + return [result, 1 / result]; + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + }); + + lodashStable.each( + ['toFinite', 'toInteger', 'toLength', 'toNumber', 'toSafeInteger'], + (methodName) => { + const func = _[methodName], + isToFinite = methodName == 'toFinite', + isToLength = methodName == 'toLength', + isToNumber = methodName == 'toNumber', + isToSafeInteger = methodName == 'toSafeInteger'; + + function negative(string) { + return `-${string}`; + } + + function pad(string) { + return whitespace + string + whitespace; + } + + function positive(string) { + return `+${string}`; + } + + it(`\`_.${methodName}\` should pass thru primitive number values`, () => { + const values = [0, 1, NaN]; + + const expected = lodashStable.map(values, (value) => + !isToNumber && value !== value ? 0 : value, + ); + + const actual = lodashStable.map(values, func); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should convert number primitives and objects to numbers`, () => { + const values = [2, 1.2, MAX_SAFE_INTEGER, MAX_INTEGER, Infinity, NaN]; + + const expected = lodashStable.map(values, (value) => { + if (!isToNumber) { + if (!isToFinite && value == 1.2) { + value = 1; + } else if (value == Infinity) { + value = MAX_INTEGER; + } else if (value !== value) { + value = 0; + } + if (isToLength || isToSafeInteger) { + value = Math.min( + value, + isToLength ? MAX_ARRAY_LENGTH : MAX_SAFE_INTEGER, + ); + } + } + const neg = isToLength ? 0 : -value; + return [value, value, neg, neg]; + }); + + const actual = lodashStable.map(values, (value) => [ + func(value), + func(Object(value)), + func(-value), + func(Object(-value)), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should convert string primitives and objects to numbers`, () => { + const transforms = [identity, pad, positive, negative]; + + const values = [ + '10', + '1.234567890', + `${MAX_SAFE_INTEGER}`, + '1e+308', + '1e308', + '1E+308', + '1E308', + '5e-324', + '5E-324', + 'Infinity', + 'NaN', + ]; + + const expected = lodashStable.map(values, (value) => { + let n = +value; + if (!isToNumber) { + if (!isToFinite && n == 1.23456789) { + n = 1; + } else if (n == Infinity) { + n = MAX_INTEGER; + } else if ((!isToFinite && n == Number.MIN_VALUE) || n !== n) { + n = 0; + } + if (isToLength || isToSafeInteger) { + n = Math.min(n, isToLength ? MAX_ARRAY_LENGTH : MAX_SAFE_INTEGER); + } + } + const neg = isToLength ? 0 : -n; + return [n, n, n, n, n, n, neg, neg]; + }); + + const actual = lodashStable.map(values, (value) => + lodashStable.flatMap(transforms, (mod) => [ + func(mod(value)), + func(Object(mod(value))), + ]), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should convert binary/octal strings to numbers`, () => { + const numbers = [42, 5349, 1715004], + transforms = [identity, pad], + values = ['0b101010', '0o12345', '0x1a2b3c']; + + const expected = lodashStable.map(numbers, (n) => + lodashStable.times(8, lodashStable.constant(n)), + ); + + const actual = lodashStable.map(values, (value) => { + const upper = value.toUpperCase(); + return lodashStable.flatMap(transforms, (mod) => [ + func(mod(value)), + func(Object(mod(value))), + func(mod(upper)), + func(Object(mod(upper))), + ]); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should convert invalid binary/octal strings to \`${ + isToNumber ? 'NaN' : '0' + }\``, () => { + const transforms = [identity, pad, positive, negative], + values = ['0b', '0o', '0x', '0b1010102', '0o123458', '0x1a2b3x']; + + const expected = lodashStable.map(values, (n) => + lodashStable.times(8, lodashStable.constant(isToNumber ? NaN : 0)), + ); + + const actual = lodashStable.map(values, (value) => + lodashStable.flatMap(transforms, (mod) => [ + func(mod(value)), + func(Object(mod(value))), + ]), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should convert symbols to \`${ + isToNumber ? 'NaN' : '0' + }\``, () => { + if (Symbol) { + const object1 = Object(symbol), + object2 = Object(symbol), + values = [symbol, object1, object2], + expected = lodashStable.map( + values, + lodashStable.constant(isToNumber ? NaN : 0), + ); + + object2.valueOf = undefined; + const actual = lodashStable.map(values, func); + + assert.deepStrictEqual(actual, expected); + } + }); + + it(`\`_.${methodName}\` should convert empty values to \`0\` or \`NaN\``, () => { + const values = falsey.concat(whitespace); + + const expected = lodashStable.map(values, (value) => + isToNumber && value !== whitespace ? Number(value) : 0, + ); + + const actual = lodashStable.map(values, (value, index) => + index ? func(value) : func(), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should coerce objects to numbers`, () => { + const values = [ + {}, + [], + [1], + [1, 2], + { valueOf: '1.1' }, + { valueOf: '1.1', toString: lodashStable.constant('2.2') }, + { valueOf: lodashStable.constant('1.1'), toString: '2.2' }, + { + valueOf: lodashStable.constant('1.1'), + toString: lodashStable.constant('2.2'), + }, + { valueOf: lodashStable.constant('-0x1a2b3c') }, + { toString: lodashStable.constant('-0x1a2b3c') }, + { valueOf: lodashStable.constant('0o12345') }, + { toString: lodashStable.constant('0o12345') }, + { valueOf: lodashStable.constant('0b101010') }, + { toString: lodashStable.constant('0b101010') }, + ]; + + let expected = [NaN, 0, 1, NaN, NaN, 2.2, 1.1, 1.1, NaN, NaN, 5349, 5349, 42, 42]; + + if (isToFinite) { + expected = [0, 0, 1, 0, 0, 2.2, 1.1, 1.1, 0, 0, 5349, 5349, 42, 42]; + } else if (!isToNumber) { + expected = [0, 0, 1, 0, 0, 2, 1, 1, 0, 0, 5349, 5349, 42, 42]; + } + const actual = lodashStable.map(values, func); + + assert.deepStrictEqual(actual, expected); + }); + }, + ); +}); diff --git a/test/object-assignments.js b/test/object-assignments.js deleted file mode 100644 index a9cb8b0cb..000000000 --- a/test/object-assignments.js +++ /dev/null @@ -1,180 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, primitives, stubTrue, defineProperty, slice } from './utils.js'; -import has from '../has.js'; - -describe('object assignments', function() { - lodashStable.each(['assign', 'assignIn', 'defaults', 'defaultsDeep', 'merge'], function(methodName) { - var func = _[methodName], - isAssign = methodName == 'assign', - isDefaults = /^defaults/.test(methodName); - - it('`_.' + methodName + '` should coerce primitives to objects', function() { - var expected = lodashStable.map(primitives, function(value) { - var object = Object(value); - object.a = 1; - return object; - }); - - var actual = lodashStable.map(primitives, function(value) { - return func(value, { 'a': 1 }); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should assign own ' + (isAssign ? '' : 'and inherited ') + 'string keyed source properties', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var expected = isAssign ? { 'a': 1 } : { 'a': 1, 'b': 2 }; - assert.deepStrictEqual(func({}, new Foo), expected); - }); - - it('`_.' + methodName + '` should not skip a trailing function source', function() { - function fn() {} - fn.b = 2; - - assert.deepStrictEqual(func({}, { 'a': 1 }, fn), { 'a': 1, 'b': 2 }); - }); - - it('`_.' + methodName + '` should not error on nullish sources', function() { - try { - assert.deepStrictEqual(func({ 'a': 1 }, undefined, { 'b': 2 }, null), { 'a': 1, 'b': 2 }); - } catch (e) { - assert.ok(false, e.message); - } - }); - - it('`_.' + methodName + '` should create an object when `object` is nullish', function() { - var source = { 'a': 1 }, - values = [null, undefined], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value) { - var object = func(value, source); - return object !== source && lodashStable.isEqual(object, source); - }); - - assert.deepStrictEqual(actual, expected); - - actual = lodashStable.map(values, function(value) { - return lodashStable.isEqual(func(value), {}); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work as an iteratee for methods like `_.reduce`', function() { - var array = [{ 'a': 1 }, { 'b': 2 }, { 'c': 3 }], - expected = { 'a': isDefaults ? 0 : 1, 'b': 2, 'c': 3 }; - - function fn() {} - fn.a = array[0]; - fn.b = array[1]; - fn.c = array[2]; - - assert.deepStrictEqual(lodashStable.reduce(array, func, { 'a': 0 }), expected); - assert.deepStrictEqual(lodashStable.reduce(fn, func, { 'a': 0 }), expected); - }); - - it('`_.' + methodName + '` should not return the existing wrapped value when chaining', function() { - var wrapped = _({ 'a': 1 }), - actual = wrapped[methodName]({ 'b': 2 }); - - assert.notStrictEqual(actual, wrapped); - }); - }); - - lodashStable.each(['assign', 'assignIn', 'merge'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should not treat `object` as `source`', function() { - function Foo() {} - Foo.prototype.a = 1; - - var actual = func(new Foo, { 'b': 2 }); - assert.ok(!has(actual, 'a')); - }); - }); - - lodashStable.each(['assign', 'assignIn', 'assignInWith', 'assignWith', 'defaults', 'defaultsDeep', 'merge', 'mergeWith'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should not assign values that are the same as their destinations', function() { - lodashStable.each(['a', ['a'], { 'a': 1 }, NaN], function(value) { - var object = {}, - pass = true; - - defineProperty(object, 'a', { - 'configurable': true, - 'enumerable': true, - 'get': lodashStable.constant(value), - 'set': function() { pass = false; } - }); - - func(object, { 'a': value }); - assert.ok(pass); - }); - }); - }); - - lodashStable.each(['assignWith', 'assignInWith', 'mergeWith'], function(methodName) { - var func = _[methodName], - isMergeWith = methodName == 'mergeWith'; - - it('`_.' + methodName + '` should provide correct `customizer` arguments', function() { - var args, - object = { 'a': 1 }, - source = { 'a': 2 }, - expected = lodashStable.map([1, 2, 'a', object, source], lodashStable.cloneDeep); - - func(object, source, function() { - args || (args = lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep)); - }); - - assert.deepStrictEqual(args, expected, 'primitive values'); - - var argsList = [], - objectValue = [1, 2], - sourceValue = { 'b': 2 }; - - object = { 'a': objectValue }; - source = { 'a': sourceValue }; - expected = [lodashStable.map([objectValue, sourceValue, 'a', object, source], lodashStable.cloneDeep)]; - - if (isMergeWith) { - expected.push(lodashStable.map([undefined, 2, 'b', objectValue, sourceValue], lodashStable.cloneDeep)); - } - func(object, source, function() { - argsList.push(lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep)); - }); - - assert.deepStrictEqual(argsList, expected, 'object values'); - - args = undefined; - object = { 'a': 1 }; - source = { 'b': 2 }; - expected = lodashStable.map([undefined, 2, 'b', object, source], lodashStable.cloneDeep); - - func(object, source, function() { - args || (args = lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep)); - }); - - assert.deepStrictEqual(args, expected, 'undefined properties'); - }); - - it('`_.' + methodName + '` should not treat the second argument as a `customizer` callback', function() { - function callback() {} - callback.b = 2; - - var actual = func({ 'a': 1 }, callback); - assert.deepStrictEqual(actual, { 'a': 1, 'b': 2 }); - - actual = func({ 'a': 1 }, callback, { 'c': 3 }); - assert.deepStrictEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); - }); - }); -}); diff --git a/test/object-assignments.spec.ts b/test/object-assignments.spec.ts new file mode 100644 index 000000000..b7b58bbe2 --- /dev/null +++ b/test/object-assignments.spec.ts @@ -0,0 +1,209 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, primitives, stubTrue, defineProperty, slice } from './utils'; +import has from '../src/has'; + +describe('object assignments', () => { + lodashStable.each(['assign', 'assignIn', 'defaults', 'defaultsDeep', 'merge'], (methodName) => { + const func = _[methodName], + isAssign = methodName == 'assign', + isDefaults = /^defaults/.test(methodName); + + it(`\`_.${methodName}\` should coerce primitives to objects`, () => { + const expected = lodashStable.map(primitives, (value) => { + const object = Object(value); + object.a = 1; + return object; + }); + + const actual = lodashStable.map(primitives, (value) => func(value, { a: 1 })); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should assign own ${ + isAssign ? '' : 'and inherited ' + }string keyed source properties`, () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const expected = isAssign ? { a: 1 } : { a: 1, b: 2 }; + assert.deepStrictEqual(func({}, new Foo()), expected); + }); + + it(`\`_.${methodName}\` should not skip a trailing function source`, () => { + function fn() {} + fn.b = 2; + + assert.deepStrictEqual(func({}, { a: 1 }, fn), { a: 1, b: 2 }); + }); + + it(`\`_.${methodName}\` should not error on nullish sources`, () => { + try { + assert.deepStrictEqual(func({ a: 1 }, undefined, { b: 2 }, null), { a: 1, b: 2 }); + } catch (e) { + assert.ok(false, e.message); + } + }); + + it(`\`_.${methodName}\` should create an object when \`object\` is nullish`, () => { + const source = { a: 1 }, + values = [null, undefined], + expected = lodashStable.map(values, stubTrue); + + let actual = lodashStable.map(values, (value) => { + const object = func(value, source); + return object !== source && lodashStable.isEqual(object, source); + }); + + assert.deepStrictEqual(actual, expected); + + actual = lodashStable.map(values, (value) => lodashStable.isEqual(func(value), {})); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work as an iteratee for methods like \`_.reduce\``, () => { + const array = [{ a: 1 }, { b: 2 }, { c: 3 }], + expected = { a: isDefaults ? 0 : 1, b: 2, c: 3 }; + + function fn() {} + fn.a = array[0]; + fn.b = array[1]; + fn.c = array[2]; + + assert.deepStrictEqual(lodashStable.reduce(array, func, { a: 0 }), expected); + assert.deepStrictEqual(lodashStable.reduce(fn, func, { a: 0 }), expected); + }); + + it(`\`_.${methodName}\` should not return the existing wrapped value when chaining`, () => { + const wrapped = _({ a: 1 }), + actual = wrapped[methodName]({ b: 2 }); + + assert.notStrictEqual(actual, wrapped); + }); + }); + + lodashStable.each(['assign', 'assignIn', 'merge'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should not treat \`object\` as \`source\``, () => { + function Foo() {} + Foo.prototype.a = 1; + + const actual = func(new Foo(), { b: 2 }); + assert.ok(!has(actual, 'a')); + }); + }); + + lodashStable.each( + [ + 'assign', + 'assignIn', + 'assignInWith', + 'assignWith', + 'defaults', + 'defaultsDeep', + 'merge', + 'mergeWith', + ], + (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should not assign values that are the same as their destinations`, () => { + lodashStable.each(['a', ['a'], { a: 1 }, NaN], (value) => { + let object = {}, + pass = true; + + defineProperty(object, 'a', { + configurable: true, + enumerable: true, + get: lodashStable.constant(value), + set: function () { + pass = false; + }, + }); + + func(object, { a: value }); + assert.ok(pass); + }); + }); + }, + ); + + lodashStable.each(['assignWith', 'assignInWith', 'mergeWith'], (methodName) => { + const func = _[methodName], + isMergeWith = methodName == 'mergeWith'; + + it(`\`_.${methodName}\` should provide correct \`customizer\` arguments`, () => { + let args, + object = { a: 1 }, + source = { a: 2 }, + expected = lodashStable.map([1, 2, 'a', object, source], lodashStable.cloneDeep); + + func(object, source, function () { + args || + (args = lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep)); + }); + + assert.deepStrictEqual(args, expected, 'primitive values'); + + const argsList = [], + objectValue = [1, 2], + sourceValue = { b: 2 }; + + object = { a: objectValue }; + source = { a: sourceValue }; + expected = [ + lodashStable.map( + [objectValue, sourceValue, 'a', object, source], + lodashStable.cloneDeep, + ), + ]; + + if (isMergeWith) { + expected.push( + lodashStable.map( + [undefined, 2, 'b', objectValue, sourceValue], + lodashStable.cloneDeep, + ), + ); + } + func(object, source, function () { + argsList.push( + lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep), + ); + }); + + assert.deepStrictEqual(argsList, expected, 'object values'); + + args = undefined; + object = { a: 1 }; + source = { b: 2 }; + expected = lodashStable.map( + [undefined, 2, 'b', object, source], + lodashStable.cloneDeep, + ); + + func(object, source, function () { + args || + (args = lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep)); + }); + + assert.deepStrictEqual(args, expected, 'undefined properties'); + }); + + it(`\`_.${methodName}\` should not treat the second argument as a \`customizer\` callback`, () => { + function callback() {} + callback.b = 2; + + let actual = func({ a: 1 }, callback); + assert.deepStrictEqual(actual, { a: 1, b: 2 }); + + actual = func({ a: 1 }, callback, { c: 3 }); + assert.deepStrictEqual(actual, { a: 1, b: 2, c: 3 }); + }); + }); +}); diff --git a/test/omit-methods.js b/test/omit-methods.js deleted file mode 100644 index 750cb9f34..000000000 --- a/test/omit-methods.js +++ /dev/null @@ -1,114 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, symbol, defineProperty } from './utils.js'; - -describe('omit methods', function() { - lodashStable.each(['omit', 'omitBy'], function(methodName) { - var expected = { 'b': 2, 'd': 4 }, - func = _[methodName], - object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, - resolve = lodashStable.nthArg(1); - - if (methodName == 'omitBy') { - resolve = function(object, props) { - props = lodashStable.castArray(props); - return function(value) { - return lodashStable.some(props, function(key) { - key = lodashStable.isSymbol(key) ? key : lodashStable.toString(key); - return object[key] === value; - }); - }; - }; - } - it('`_.' + methodName + '` should create an object with omitted string keyed properties', function() { - assert.deepStrictEqual(func(object, resolve(object, 'a')), { 'b': 2, 'c': 3, 'd': 4 }); - assert.deepStrictEqual(func(object, resolve(object, ['a', 'c'])), expected); - }); - - it('`_.' + methodName + '` should include inherited string keyed properties', function() { - function Foo() {} - Foo.prototype = object; - - assert.deepStrictEqual(func(new Foo, resolve(object, ['a', 'c'])), expected); - }); - - it('`_.' + methodName + '` should preserve the sign of `0`', function() { - var object = { '-0': 'a', '0': 'b' }, - props = [-0, Object(-0), 0, Object(0)], - expected = [{ '0': 'b' }, { '0': 'b' }, { '-0': 'a' }, { '-0': 'a' }]; - - var actual = lodashStable.map(props, function(key) { - return func(object, resolve(object, key)); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should include symbols', function() { - function Foo() { - this.a = 0; - this[symbol] = 1; - } - - if (Symbol) { - var symbol2 = Symbol('b'); - Foo.prototype[symbol2] = 2; - - var symbol3 = Symbol('c'); - defineProperty(Foo.prototype, symbol3, { - 'configurable': true, - 'enumerable': false, - 'writable': true, - 'value': 3 - }); - - var foo = new Foo, - actual = func(foo, resolve(foo, 'a')); - - assert.strictEqual(actual[symbol], 1); - assert.strictEqual(actual[symbol2], 2); - assert.ok(!(symbol3 in actual)); - } - }); - - it('`_.' + methodName + '` should create an object with omitted symbols', function() { - function Foo() { - this.a = 0; - this[symbol] = 1; - } - - if (Symbol) { - var symbol2 = Symbol('b'); - Foo.prototype[symbol2] = 2; - - var symbol3 = Symbol('c'); - defineProperty(Foo.prototype, symbol3, { - 'configurable': true, - 'enumerable': false, - 'writable': true, - 'value': 3 - }); - - var foo = new Foo, - actual = func(foo, resolve(foo, symbol)); - - assert.strictEqual(actual.a, 0); - assert.ok(!(symbol in actual)); - assert.strictEqual(actual[symbol2], 2); - assert.ok(!(symbol3 in actual)); - - actual = func(foo, resolve(foo, symbol2)); - - assert.strictEqual(actual.a, 0); - assert.strictEqual(actual[symbol], 1); - assert.ok(!(symbol2 in actual)); - assert.ok(!(symbol3 in actual)); - } - }); - - it('`_.' + methodName + '` should work with an array `object`', function() { - var array = [1, 2, 3]; - assert.deepStrictEqual(func(array, resolve(array, ['0', '2'])), { '1': 2 }); - }); - }); -}); diff --git a/test/omit-methods.spec.ts b/test/omit-methods.spec.ts new file mode 100644 index 000000000..8101c562d --- /dev/null +++ b/test/omit-methods.spec.ts @@ -0,0 +1,112 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, symbol, defineProperty } from './utils'; + +describe('omit methods', () => { + lodashStable.each(['omit', 'omitBy'], (methodName) => { + let expected = { b: 2, d: 4 }, + func = _[methodName], + object = { a: 1, b: 2, c: 3, d: 4 }, + resolve = lodashStable.nthArg(1); + + if (methodName == 'omitBy') { + resolve = function (object, props) { + props = lodashStable.castArray(props); + return function (value) { + return lodashStable.some(props, (key) => { + key = lodashStable.isSymbol(key) ? key : lodashStable.toString(key); + return object[key] === value; + }); + }; + }; + } + it(`\`_.${methodName}\` should create an object with omitted string keyed properties`, () => { + assert.deepStrictEqual(func(object, resolve(object, 'a')), { b: 2, c: 3, d: 4 }); + assert.deepStrictEqual(func(object, resolve(object, ['a', 'c'])), expected); + }); + + it(`\`_.${methodName}\` should include inherited string keyed properties`, () => { + function Foo() {} + Foo.prototype = object; + + assert.deepStrictEqual(func(new Foo(), resolve(object, ['a', 'c'])), expected); + }); + + it(`\`_.${methodName}\` should preserve the sign of \`0\``, () => { + const object = { '-0': 'a', '0': 'b' }, + props = [-0, Object(-0), 0, Object(0)], + expected = [{ '0': 'b' }, { '0': 'b' }, { '-0': 'a' }, { '-0': 'a' }]; + + const actual = lodashStable.map(props, (key) => func(object, resolve(object, key))); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should include symbols`, () => { + function Foo() { + this.a = 0; + this[symbol] = 1; + } + + if (Symbol) { + const symbol2 = Symbol('b'); + Foo.prototype[symbol2] = 2; + + const symbol3 = Symbol('c'); + defineProperty(Foo.prototype, symbol3, { + configurable: true, + enumerable: false, + writable: true, + value: 3, + }); + + const foo = new Foo(), + actual = func(foo, resolve(foo, 'a')); + + assert.strictEqual(actual[symbol], 1); + assert.strictEqual(actual[symbol2], 2); + assert.ok(!(symbol3 in actual)); + } + }); + + it(`\`_.${methodName}\` should create an object with omitted symbols`, () => { + function Foo() { + this.a = 0; + this[symbol] = 1; + } + + if (Symbol) { + const symbol2 = Symbol('b'); + Foo.prototype[symbol2] = 2; + + const symbol3 = Symbol('c'); + defineProperty(Foo.prototype, symbol3, { + configurable: true, + enumerable: false, + writable: true, + value: 3, + }); + + let foo = new Foo(), + actual = func(foo, resolve(foo, symbol)); + + assert.strictEqual(actual.a, 0); + assert.ok(!(symbol in actual)); + assert.strictEqual(actual[symbol2], 2); + assert.ok(!(symbol3 in actual)); + + actual = func(foo, resolve(foo, symbol2)); + + assert.strictEqual(actual.a, 0); + assert.strictEqual(actual[symbol], 1); + assert.ok(!(symbol2 in actual)); + assert.ok(!(symbol3 in actual)); + } + }); + + it(`\`_.${methodName}\` should work with an array \`object\``, () => { + const array = [1, 2, 3]; + assert.deepStrictEqual(func(array, resolve(array, ['0', '2'])), { '1': 2 }); + }); + }); +}); diff --git a/test/omit.js b/test/omit.js deleted file mode 100644 index 7bde8dc8d..000000000 --- a/test/omit.js +++ /dev/null @@ -1,69 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, toArgs, objectProto, stringProto } from './utils.js'; -import omit from '../omit.js'; - -describe('omit', function() { - var args = toArgs(['a', 'c']), - object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, - nested = { 'a': 1, 'b': { 'c': 2, 'd': 3 } }; - - it('should flatten `paths`', function() { - assert.deepStrictEqual(omit(object, 'a', 'c'), { 'b': 2, 'd': 4 }); - assert.deepStrictEqual(omit(object, ['a', 'd'], 'c'), { 'b': 2 }); - }); - - it('should support deep paths', function() { - assert.deepStrictEqual(omit(nested, 'b.c'), { 'a': 1, 'b': { 'd': 3} }); - }); - - it('should support path arrays', function() { - var object = { 'a.b': 1, 'a': { 'b': 2 } }, - actual = omit(object, [['a.b']]); - - assert.deepStrictEqual(actual, { 'a': { 'b': 2 } }); - }); - - it('should omit a key over a path', function() { - var object = { 'a.b': 1, 'a': { 'b': 2 } }; - - lodashStable.each(['a.b', ['a.b']], function(path) { - assert.deepStrictEqual(omit(object, path), { 'a': { 'b': 2 } }); - }); - }); - - it('should coerce `paths` to strings', function() { - assert.deepStrictEqual(omit({ '0': 'a' }, 0), {}); - }); - - it('should return an empty object when `object` is nullish', function() { - lodashStable.each([null, undefined], function(value) { - objectProto.a = 1; - var actual = omit(value, 'valueOf'); - delete objectProto.a; - assert.deepStrictEqual(actual, {}); - }); - }); - - it('should work with a primitive `object`', function() { - stringProto.a = 1; - stringProto.b = 2; - - assert.deepStrictEqual(omit('', 'b'), { 'a': 1 }); - - delete stringProto.a; - delete stringProto.b; - }); - - it('should work with `arguments` object `paths`', function() { - assert.deepStrictEqual(omit(object, args), { 'b': 2, 'd': 4 }); - }); - - it('should not mutate `object`', function() { - lodashStable.each(['a', ['a'], 'a.b', ['a.b']], function(path) { - var object = { 'a': { 'b': 2 } }; - omit(object, path); - assert.deepStrictEqual(object, { 'a': { 'b': 2 } }); - }); - }); -}); diff --git a/test/omit.spec.ts b/test/omit.spec.ts new file mode 100644 index 000000000..9d8bd86a4 --- /dev/null +++ b/test/omit.spec.ts @@ -0,0 +1,69 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, toArgs, objectProto, stringProto } from './utils'; +import omit from '../src/omit'; + +describe('omit', () => { + const args = toArgs(['a', 'c']), + object = { a: 1, b: 2, c: 3, d: 4 }, + nested = { a: 1, b: { c: 2, d: 3 } }; + + it('should flatten `paths`', () => { + assert.deepStrictEqual(omit(object, 'a', 'c'), { b: 2, d: 4 }); + assert.deepStrictEqual(omit(object, ['a', 'd'], 'c'), { b: 2 }); + }); + + it('should support deep paths', () => { + assert.deepStrictEqual(omit(nested, 'b.c'), { a: 1, b: { d: 3 } }); + }); + + it('should support path arrays', () => { + const object = { 'a.b': 1, a: { b: 2 } }, + actual = omit(object, [['a.b']]); + + assert.deepStrictEqual(actual, { a: { b: 2 } }); + }); + + it('should omit a key over a path', () => { + const object = { 'a.b': 1, a: { b: 2 } }; + + lodashStable.each(['a.b', ['a.b']], (path) => { + assert.deepStrictEqual(omit(object, path), { a: { b: 2 } }); + }); + }); + + it('should coerce `paths` to strings', () => { + assert.deepStrictEqual(omit({ '0': 'a' }, 0), {}); + }); + + it('should return an empty object when `object` is nullish', () => { + lodashStable.each([null, undefined], (value) => { + objectProto.a = 1; + const actual = omit(value, 'valueOf'); + delete objectProto.a; + assert.deepStrictEqual(actual, {}); + }); + }); + + it('should work with a primitive `object`', () => { + stringProto.a = 1; + stringProto.b = 2; + + assert.deepStrictEqual(omit('', 'b'), { a: 1 }); + + delete stringProto.a; + delete stringProto.b; + }); + + it('should work with `arguments` object `paths`', () => { + assert.deepStrictEqual(omit(object, args), { b: 2, d: 4 }); + }); + + it('should not mutate `object`', () => { + lodashStable.each(['a', ['a'], 'a.b', ['a.b']], (path) => { + const object = { a: { b: 2 } }; + omit(object, path); + assert.deepStrictEqual(object, { a: { b: 2 } }); + }); + }); +}); diff --git a/test/omitBy.js b/test/omitBy.js deleted file mode 100644 index 28c6a9aff..000000000 --- a/test/omitBy.js +++ /dev/null @@ -1,14 +0,0 @@ -import assert from 'assert'; -import omitBy from '../omitBy.js'; - -describe('omitBy', function() { - it('should work with a predicate argument', function() { - var object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; - - var actual = omitBy(object, function(n) { - return n != 2 && n != 4; - }); - - assert.deepStrictEqual(actual, { 'b': 2, 'd': 4 }); - }); -}); diff --git a/test/omitBy.spec.ts b/test/omitBy.spec.ts new file mode 100644 index 000000000..f9d726dfd --- /dev/null +++ b/test/omitBy.spec.ts @@ -0,0 +1,12 @@ +import assert from 'node:assert'; +import omitBy from '../src/omitBy'; + +describe('omitBy', () => { + it('should work with a predicate argument', () => { + const object = { a: 1, b: 2, c: 3, d: 4 }; + + const actual = omitBy(object, (n) => n != 2 && n != 4); + + assert.deepStrictEqual(actual, { b: 2, d: 4 }); + }); +}); diff --git a/test/once.spec.ts b/test/once.spec.ts new file mode 100644 index 000000000..427b31fe1 --- /dev/null +++ b/test/once.spec.ts @@ -0,0 +1,36 @@ +import assert from 'node:assert'; +import { _ } from './utils'; + +describe('once', () => { + it('should invoke `func` once', () => { + let count = 0, + once = _.once(() => ++count); + + once(); + assert.strictEqual(once(), 1); + assert.strictEqual(count, 1); + }); + + it('should ignore recursive calls', () => { + let count = 0; + + var once = _.once(() => { + once(); + return ++count; + }); + + assert.strictEqual(once(), 1); + assert.strictEqual(count, 1); + }); + + it('should not throw more than once', () => { + const once = _.once(() => { + throw new Error(); + }); + + assert.throws(once); + + once(); + assert.ok(true); + }); +}); diff --git a/test/once.test.js b/test/once.test.js deleted file mode 100644 index 7279125e8..000000000 --- a/test/once.test.js +++ /dev/null @@ -1,36 +0,0 @@ -import assert from 'assert'; -import { _ } from './utils.js'; - -describe('once', function() { - it('should invoke `func` once', function() { - var count = 0, - once = _.once(function() { return ++count; }); - - once(); - assert.strictEqual(once(), 1); - assert.strictEqual(count, 1); - }); - - it('should ignore recursive calls', function() { - var count = 0; - - var once = _.once(function() { - once(); - return ++count; - }); - - assert.strictEqual(once(), 1); - assert.strictEqual(count, 1); - }); - - it('should not throw more than once', function() { - var once = _.once(function() { - throw new Error; - }); - - assert.throws(once); - - once(); - assert.ok(true); - }); -}); diff --git a/test/orderBy.js b/test/orderBy.js deleted file mode 100644 index 7aba5fe48..000000000 --- a/test/orderBy.js +++ /dev/null @@ -1,61 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey } from './utils.js'; -import orderBy from '../orderBy.js'; - -describe('orderBy', function() { - var objects = [ - { 'a': 'x', 'b': 3 }, - { 'a': 'y', 'b': 4 }, - { 'a': 'x', 'b': 1 }, - { 'a': 'y', 'b': 2 } - ]; - - var nestedObj = [ - { id: '4', address: { zipCode: 4, streetName: 'Beta' } }, - { id: '3', address: { zipCode: 3, streetName: 'Alpha' } }, - { id: '1', address: { zipCode: 1, streetName: 'Alpha' } }, - { id: '2', address: { zipCode: 2, streetName: 'Alpha' } }, - { id: '5', address: { zipCode: 4, streetName: 'Alpha' } }, - ]; - - - it('should sort by a single property by a specified order', function() { - var actual = orderBy(objects, 'a', 'desc'); - assert.deepStrictEqual(actual, [objects[1], objects[3], objects[0], objects[2]]); - }); - - it('should sort by nested key in array format', () => { - var actual = orderBy( - nestedObj, - [['address', 'zipCode'], ['address.streetName']], - ['asc', 'desc'], - ); - assert.deepStrictEqual(actual, [nestedObj[2], nestedObj[3], nestedObj[1], nestedObj[0], nestedObj[4]]); - }); - - it('should sort by multiple properties by specified orders', function() { - var actual = orderBy(objects, ['a', 'b'], ['desc', 'asc']); - assert.deepStrictEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); - }); - - it('should sort by a property in ascending order when its order is not specified', function() { - var expected = [objects[2], objects[0], objects[3], objects[1]], - actual = orderBy(objects, ['a', 'b']); - - assert.deepStrictEqual(actual, expected); - - expected = lodashStable.map(falsey, lodashStable.constant([objects[3], objects[1], objects[2], objects[0]])); - - actual = lodashStable.map(falsey, function(order, index) { - return orderBy(objects, ['a', 'b'], index ? ['desc', order] : ['desc']); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `orders` specified as string objects', function() { - var actual = orderBy(objects, ['a'], [Object('desc')]); - assert.deepStrictEqual(actual, [objects[1], objects[3], objects[0], objects[2]]); - }); -}); diff --git a/test/orderBy.spec.ts b/test/orderBy.spec.ts new file mode 100644 index 000000000..6e81f09fc --- /dev/null +++ b/test/orderBy.spec.ts @@ -0,0 +1,69 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey } from './utils'; +import orderBy from '../src/orderBy'; + +describe('orderBy', () => { + const objects = [ + { a: 'x', b: 3 }, + { a: 'y', b: 4 }, + { a: 'x', b: 1 }, + { a: 'y', b: 2 }, + ]; + + const nestedObj = [ + { id: '4', address: { zipCode: 4, streetName: 'Beta' } }, + { id: '3', address: { zipCode: 3, streetName: 'Alpha' } }, + { id: '1', address: { zipCode: 1, streetName: 'Alpha' } }, + { id: '2', address: { zipCode: 2, streetName: 'Alpha' } }, + { id: '5', address: { zipCode: 4, streetName: 'Alpha' } }, + ]; + + it('should sort by a single property by a specified order', () => { + const actual = orderBy(objects, 'a', 'desc'); + assert.deepStrictEqual(actual, [objects[1], objects[3], objects[0], objects[2]]); + }); + + it('should sort by nested key in array format', () => { + const actual = orderBy( + nestedObj, + [['address', 'zipCode'], ['address.streetName']], + ['asc', 'desc'], + ); + assert.deepStrictEqual(actual, [ + nestedObj[2], + nestedObj[3], + nestedObj[1], + nestedObj[0], + nestedObj[4], + ]); + }); + + it('should sort by multiple properties by specified orders', () => { + const actual = orderBy(objects, ['a', 'b'], ['desc', 'asc']); + assert.deepStrictEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); + }); + + it('should sort by a property in ascending order when its order is not specified', () => { + let expected = [objects[2], objects[0], objects[3], objects[1]], + actual = orderBy(objects, ['a', 'b']); + + assert.deepStrictEqual(actual, expected); + + expected = lodashStable.map( + falsey, + lodashStable.constant([objects[3], objects[1], objects[2], objects[0]]), + ); + + actual = lodashStable.map(falsey, (order, index) => + orderBy(objects, ['a', 'b'], index ? ['desc', order] : ['desc']), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `orders` specified as string objects', () => { + const actual = orderBy(objects, ['a'], [Object('desc')]); + assert.deepStrictEqual(actual, [objects[1], objects[3], objects[0], objects[2]]); + }); +}); diff --git a/test/over.js b/test/over.js deleted file mode 100644 index 93ce95186..000000000 --- a/test/over.js +++ /dev/null @@ -1,58 +0,0 @@ -import assert from 'assert'; -import { _, slice } from './utils.js'; - -describe('over', function() { - it('should create a function that invokes `iteratees`', function() { - var over = _.over(Math.max, Math.min); - assert.deepStrictEqual(over(1, 2, 3, 4), [4, 1]); - }); - - it('should use `_.identity` when a predicate is nullish', function() { - var over = _.over(undefined, null); - assert.deepStrictEqual(over('a', 'b', 'c'), ['a', 'a']); - }); - - it('should work with `_.property` shorthands', function() { - var over = _.over('b', 'a'); - assert.deepStrictEqual(over({ 'a': 1, 'b': 2 }), [2, 1]); - }); - - it('should work with `_.matches` shorthands', function() { - var over = _.over({ 'b': 1 }, { 'a': 1 }); - assert.deepStrictEqual(over({ 'a': 1, 'b': 2 }), [false, true]); - }); - - it('should work with `_.matchesProperty` shorthands', function() { - var over = _.over([['b', 2], ['a', 2]]); - - assert.deepStrictEqual(over({ 'a': 1, 'b': 2 }), [true, false]); - assert.deepStrictEqual(over({ 'a': 2, 'b': 1 }), [false, true]); - }); - - it('should differentiate between `_.property` and `_.matchesProperty` shorthands', function() { - var over = _.over(['a', 1]); - - assert.deepStrictEqual(over({ 'a': 1, '1': 2 }), [1, 2]); - assert.deepStrictEqual(over({ 'a': 2, '1': 1 }), [2, 1]); - - over = _.over([['a', 1]]); - - assert.deepStrictEqual(over({ 'a': 1 }), [true]); - assert.deepStrictEqual(over({ 'a': 2 }), [false]); - }); - - it('should provide arguments to predicates', function() { - var over = _.over(function() { - return slice.call(arguments); - }); - - assert.deepStrictEqual(over('a', 'b', 'c'), [['a', 'b', 'c']]); - }); - - it('should use `this` binding of function for `iteratees`', function() { - var over = _.over(function() { return this.b; }, function() { return this.a; }), - object = { 'over': over, 'a': 1, 'b': 2 }; - - assert.deepStrictEqual(object.over(), [2, 1]); - }); -}); diff --git a/test/over.spec.ts b/test/over.spec.ts new file mode 100644 index 000000000..de4e6cc16 --- /dev/null +++ b/test/over.spec.ts @@ -0,0 +1,68 @@ +import assert from 'node:assert'; +import { _, slice } from './utils'; + +describe('over', () => { + it('should create a function that invokes `iteratees`', () => { + const over = _.over(Math.max, Math.min); + assert.deepStrictEqual(over(1, 2, 3, 4), [4, 1]); + }); + + it('should use `_.identity` when a predicate is nullish', () => { + const over = _.over(undefined, null); + assert.deepStrictEqual(over('a', 'b', 'c'), ['a', 'a']); + }); + + it('should work with `_.property` shorthands', () => { + const over = _.over('b', 'a'); + assert.deepStrictEqual(over({ a: 1, b: 2 }), [2, 1]); + }); + + it('should work with `_.matches` shorthands', () => { + const over = _.over({ b: 1 }, { a: 1 }); + assert.deepStrictEqual(over({ a: 1, b: 2 }), [false, true]); + }); + + it('should work with `_.matchesProperty` shorthands', () => { + const over = _.over([ + ['b', 2], + ['a', 2], + ]); + + assert.deepStrictEqual(over({ a: 1, b: 2 }), [true, false]); + assert.deepStrictEqual(over({ a: 2, b: 1 }), [false, true]); + }); + + it('should differentiate between `_.property` and `_.matchesProperty` shorthands', () => { + let over = _.over(['a', 1]); + + assert.deepStrictEqual(over({ a: 1, '1': 2 }), [1, 2]); + assert.deepStrictEqual(over({ a: 2, '1': 1 }), [2, 1]); + + over = _.over([['a', 1]]); + + assert.deepStrictEqual(over({ a: 1 }), [true]); + assert.deepStrictEqual(over({ a: 2 }), [false]); + }); + + it('should provide arguments to predicates', () => { + const over = _.over(function () { + return slice.call(arguments); + }); + + assert.deepStrictEqual(over('a', 'b', 'c'), [['a', 'b', 'c']]); + }); + + it('should use `this` binding of function for `iteratees`', () => { + const over = _.over( + function () { + return this.b; + }, + function () { + return this.a; + }, + ), + object = { over: over, a: 1, b: 2 }; + + assert.deepStrictEqual(object.over(), [2, 1]); + }); +}); diff --git a/test/overArgs.js b/test/overArgs.js deleted file mode 100644 index f6e20db59..000000000 --- a/test/overArgs.js +++ /dev/null @@ -1,82 +0,0 @@ -import assert from 'assert'; -import { slice, doubled, square, identity, noop } from './utils.js'; -import overArgs from '../overArgs.js'; - -describe('overArgs', function() { - function fn() { - return slice.call(arguments); - } - - it('should transform each argument', function() { - var over = overArgs(fn, doubled, square); - assert.deepStrictEqual(over(5, 10), [10, 100]); - }); - - it('should use `_.identity` when a predicate is nullish', function() { - var over = overArgs(fn, undefined, null); - assert.deepStrictEqual(over('a', 'b'), ['a', 'b']); - }); - - it('should work with `_.property` shorthands', function() { - var over = overArgs(fn, 'b', 'a'); - assert.deepStrictEqual(over({ 'b': 2 }, { 'a': 1 }), [2, 1]); - }); - - it('should work with `_.matches` shorthands', function() { - var over = overArgs(fn, { 'b': 1 }, { 'a': 1 }); - assert.deepStrictEqual(over({ 'b': 2 }, { 'a': 1 }), [false, true]); - }); - - it('should work with `_.matchesProperty` shorthands', function() { - var over = overArgs(fn, [['b', 1], ['a', 1]]); - assert.deepStrictEqual(over({ 'b': 2 }, { 'a': 1 }), [false, true]); - }); - - it('should differentiate between `_.property` and `_.matchesProperty` shorthands', function() { - var over = overArgs(fn, ['a', 1]); - assert.deepStrictEqual(over({ 'a': 1 }, { '1': 2 }), [1, 2]); - - over = overArgs(fn, [['a', 1]]); - assert.deepStrictEqual(over({ 'a': 1 }), [true]); - }); - - it('should flatten `transforms`', function() { - var over = overArgs(fn, [doubled, square], String); - assert.deepStrictEqual(over(5, 10, 15), [10, 100, '15']); - }); - - it('should not transform any argument greater than the number of transforms', function() { - var over = overArgs(fn, doubled, square); - assert.deepStrictEqual(over(5, 10, 18), [10, 100, 18]); - }); - - it('should not transform any arguments if no transforms are given', function() { - var over = overArgs(fn); - assert.deepStrictEqual(over(5, 10, 18), [5, 10, 18]); - }); - - it('should not pass `undefined` if there are more transforms than arguments', function() { - var over = overArgs(fn, doubled, identity); - assert.deepStrictEqual(over(5), [10]); - }); - - it('should provide the correct argument to each transform', function() { - var argsList = [], - transform = function() { argsList.push(slice.call(arguments)); }, - over = overArgs(noop, transform, transform, transform); - - over('a', 'b'); - assert.deepStrictEqual(argsList, [['a'], ['b']]); - }); - - it('should use `this` binding of function for `transforms`', function() { - var over = overArgs(function(x) { - return this[x]; - }, function(x) { - return this === x; - }); - - var object = { 'over': over, 'true': 1 }; - assert.strictEqual(object.over(object), 1); - }); -}); diff --git a/test/overArgs.spec.ts b/test/overArgs.spec.ts new file mode 100644 index 000000000..5154bb11c --- /dev/null +++ b/test/overArgs.spec.ts @@ -0,0 +1,90 @@ +import assert from 'node:assert'; +import { slice, doubled, square, identity, noop } from './utils'; +import overArgs from '../src/overArgs'; + +describe('overArgs', () => { + function fn() { + return slice.call(arguments); + } + + it('should transform each argument', () => { + const over = overArgs(fn, doubled, square); + assert.deepStrictEqual(over(5, 10), [10, 100]); + }); + + it('should use `_.identity` when a predicate is nullish', () => { + const over = overArgs(fn, undefined, null); + assert.deepStrictEqual(over('a', 'b'), ['a', 'b']); + }); + + it('should work with `_.property` shorthands', () => { + const over = overArgs(fn, 'b', 'a'); + assert.deepStrictEqual(over({ b: 2 }, { a: 1 }), [2, 1]); + }); + + it('should work with `_.matches` shorthands', () => { + const over = overArgs(fn, { b: 1 }, { a: 1 }); + assert.deepStrictEqual(over({ b: 2 }, { a: 1 }), [false, true]); + }); + + it('should work with `_.matchesProperty` shorthands', () => { + const over = overArgs(fn, [ + ['b', 1], + ['a', 1], + ]); + assert.deepStrictEqual(over({ b: 2 }, { a: 1 }), [false, true]); + }); + + it('should differentiate between `_.property` and `_.matchesProperty` shorthands', () => { + let over = overArgs(fn, ['a', 1]); + assert.deepStrictEqual(over({ a: 1 }, { '1': 2 }), [1, 2]); + + over = overArgs(fn, [['a', 1]]); + assert.deepStrictEqual(over({ a: 1 }), [true]); + }); + + it('should flatten `transforms`', () => { + const over = overArgs(fn, [doubled, square], String); + assert.deepStrictEqual(over(5, 10, 15), [10, 100, '15']); + }); + + it('should not transform any argument greater than the number of transforms', () => { + const over = overArgs(fn, doubled, square); + assert.deepStrictEqual(over(5, 10, 18), [10, 100, 18]); + }); + + it('should not transform any arguments if no transforms are given', () => { + const over = overArgs(fn); + assert.deepStrictEqual(over(5, 10, 18), [5, 10, 18]); + }); + + it('should not pass `undefined` if there are more transforms than arguments', () => { + const over = overArgs(fn, doubled, identity); + assert.deepStrictEqual(over(5), [10]); + }); + + it('should provide the correct argument to each transform', () => { + const argsList = [], + transform = function () { + argsList.push(slice.call(arguments)); + }, + over = overArgs(noop, transform, transform, transform); + + over('a', 'b'); + assert.deepStrictEqual(argsList, [['a'], ['b']]); + }); + + it('should use `this` binding of function for `transforms`', () => { + const over = overArgs( + function (x) { + return this[x]; + }, + function (x) { + return this === x; + }, + ); + + const object = { over: over, true: 1 }; + assert.strictEqual(object.over(object), 1); + }); +}); diff --git a/test/overEvery.js b/test/overEvery.js deleted file mode 100644 index 7ce135cf9..000000000 --- a/test/overEvery.js +++ /dev/null @@ -1,87 +0,0 @@ -import assert from 'assert'; -import { stubTrue, stubOne, stubA, stubFalse, slice } from './utils.js'; -import overEvery from '../overEvery.js'; - -describe('overEvery', function() { - it('should create a function that returns `true` if all predicates return truthy', function() { - var over = overEvery(stubTrue, stubOne, stubA); - assert.strictEqual(over(), true); - }); - - it('should return `false` as soon as a predicate returns falsey', function() { - var count = 0, - countFalse = function() { count++; return false; }, - countTrue = function() { count++; return true; }, - over = overEvery(countTrue, countFalse, countTrue); - - assert.strictEqual(over(), false); - assert.strictEqual(count, 2); - }); - - it('should use `_.identity` when a predicate is nullish', function() { - var over = overEvery(undefined, null); - - assert.strictEqual(over(true), true); - assert.strictEqual(over(false), false); - }); - - it('should work with `_.property` shorthands', function() { - var over = overEvery('b', 'a'); - - assert.strictEqual(over({ 'a': 1, 'b': 1 }), true); - assert.strictEqual(over({ 'a': 0, 'b': 1 }), false); - }); - - it('should work with `_.matches` shorthands', function() { - var over = overEvery({ 'b': 2 }, { 'a': 1 }); - - assert.strictEqual(over({ 'a': 1, 'b': 2 }), true); - assert.strictEqual(over({ 'a': 0, 'b': 2 }), false); - }); - - it('should work with `_.matchesProperty` shorthands', function() { - var over = overEvery([['b', 2], ['a', 1]]); - - assert.strictEqual(over({ 'a': 1, 'b': 2 }), true); - assert.strictEqual(over({ 'a': 0, 'b': 2 }), false); - }); - - it('should differentiate between `_.property` and `_.matchesProperty` shorthands', function() { - var over = overEvery(['a', 1]); - - assert.strictEqual(over({ 'a': 1, '1': 1 }), true); - assert.strictEqual(over({ 'a': 1, '1': 0 }), false); - assert.strictEqual(over({ 'a': 0, '1': 1 }), false); - - over = overEvery([['a', 1]]); - - assert.strictEqual(over({ 'a': 1 }), true); - assert.strictEqual(over({ 'a': 2 }), false); - }); - - it('should flatten `predicates`', function() { - var over = overEvery(stubTrue, [stubFalse]); - assert.strictEqual(over(), false); - }); - - it('should provide arguments to predicates', function() { - var args; - - var over = overEvery(function() { - args = slice.call(arguments); - }); - - over('a', 'b', 'c'); - assert.deepStrictEqual(args, ['a', 'b', 'c']); - }); - - it('should use `this` binding of function for `predicates`', function() { - var over = overEvery(function() { return this.b; }, function() { return this.a; }), - object = { 'over': over, 'a': 1, 'b': 2 }; - - assert.strictEqual(object.over(), true); - - object.a = 0; - assert.strictEqual(object.over(), false); - }); -}); diff --git a/test/overEvery.spec.ts b/test/overEvery.spec.ts new file mode 100644 index 000000000..3ae2011bb --- /dev/null +++ b/test/overEvery.spec.ts @@ -0,0 +1,103 @@ +import assert from 'node:assert'; +import { stubTrue, stubOne, stubA, stubFalse, slice } from './utils'; +import overEvery from '../src/overEvery'; + +describe('overEvery', () => { + it('should create a function that returns `true` if all predicates return truthy', () => { + const over = overEvery(stubTrue, stubOne, stubA); + assert.strictEqual(over(), true); + }); + + it('should return `false` as soon as a predicate returns falsey', () => { + let count = 0, + countFalse = function () { + count++; + return false; + }, + countTrue = function () { + count++; + return true; + }, + over = overEvery(countTrue, countFalse, countTrue); + + assert.strictEqual(over(), false); + assert.strictEqual(count, 2); + }); + + it('should use `_.identity` when a predicate is nullish', () => { + const over = overEvery(undefined, null); + + assert.strictEqual(over(true), true); + assert.strictEqual(over(false), false); + }); + + it('should work with `_.property` shorthands', () => { + const over = overEvery('b', 'a'); + + assert.strictEqual(over({ a: 1, b: 1 }), true); + assert.strictEqual(over({ a: 0, b: 1 }), false); + }); + + it('should work with `_.matches` shorthands', () => { + const over = overEvery({ b: 2 }, { a: 1 }); + + assert.strictEqual(over({ a: 1, b: 2 }), true); + assert.strictEqual(over({ a: 0, b: 2 }), false); + }); + + it('should work with `_.matchesProperty` shorthands', () => { + const over = overEvery([ + ['b', 2], + ['a', 1], + ]); + + assert.strictEqual(over({ a: 1, b: 2 }), true); + assert.strictEqual(over({ a: 0, b: 2 }), false); + }); + + it('should differentiate between `_.property` and `_.matchesProperty` shorthands', () => { + let over = overEvery(['a', 1]); + + assert.strictEqual(over({ a: 1, '1': 1 }), true); + assert.strictEqual(over({ a: 1, '1': 0 }), false); + assert.strictEqual(over({ a: 0, '1': 1 }), false); + + over = overEvery([['a', 1]]); + + assert.strictEqual(over({ a: 1 }), true); + assert.strictEqual(over({ a: 2 }), false); + }); + + it('should flatten `predicates`', () => { + const over = overEvery(stubTrue, [stubFalse]); + assert.strictEqual(over(), false); + }); + + it('should provide arguments to predicates', () => { + let args; + + const over = overEvery(function () { + args = slice.call(arguments); + }); + + over('a', 'b', 'c'); + assert.deepStrictEqual(args, ['a', 'b', 'c']); + }); + + it('should use `this` binding of function for `predicates`', () => { + const over = overEvery( + function () { + return this.b; + }, + function () { + return this.a; + }, + ), + object = { over: over, a: 1, b: 2 }; + + assert.strictEqual(object.over(), true); + + object.a = 0; + assert.strictEqual(object.over(), false); + }); +}); diff --git a/test/overSome.js b/test/overSome.js deleted file mode 100644 index 07ecaa22c..000000000 --- a/test/overSome.js +++ /dev/null @@ -1,98 +0,0 @@ -import assert from 'assert'; -import { stubFalse, stubOne, stubString, stubNull, stubA, stubZero, stubTrue, slice } from './utils.js'; -import overSome from '../overSome.js'; - -describe('overSome', function() { - it('should create a function that returns `true` if any predicates return truthy', function() { - var over = overSome(stubFalse, stubOne, stubString); - assert.strictEqual(over(), true); - - over = overSome(stubNull, stubA, stubZero); - assert.strictEqual(over(), true); - }); - - it('should return `true` as soon as `predicate` returns truthy', function() { - var count = 0, - countFalse = function() { count++; return false; }, - countTrue = function() { count++; return true; }, - over = overSome(countFalse, countTrue, countFalse); - - assert.strictEqual(over(), true); - assert.strictEqual(count, 2); - }); - - it('should return `false` if all predicates return falsey', function() { - var over = overSome(stubFalse, stubFalse, stubFalse); - assert.strictEqual(over(), false); - - over = overSome(stubNull, stubZero, stubString); - assert.strictEqual(over(), false); - }); - - it('should use `_.identity` when a predicate is nullish', function() { - var over = overSome(undefined, null); - - assert.strictEqual(over(true), true); - assert.strictEqual(over(false), false); - }); - - it('should work with `_.property` shorthands', function() { - var over = overSome('b', 'a'); - - assert.strictEqual(over({ 'a': 1, 'b': 0 }), true); - assert.strictEqual(over({ 'a': 0, 'b': 0 }), false); - }); - - it('should work with `_.matches` shorthands', function() { - var over = overSome({ 'b': 2 }, { 'a': 1 }); - - assert.strictEqual(over({ 'a': 0, 'b': 2 }), true); - assert.strictEqual(over({ 'a': 0, 'b': 0 }), false); - }); - - it('should work with `_.matchesProperty` shorthands', function() { - var over = overSome([['b', 2], ['a', 1]]); - - assert.strictEqual(over({ 'a': 0, 'b': 2 }), true); - assert.strictEqual(over({ 'a': 0, 'b': 0 }), false); - }); - - it('should differentiate between `_.property` and `_.matchesProperty` shorthands', function() { - var over = overSome(['a', 1]); - - assert.strictEqual(over({ 'a': 0, '1': 0 }), false); - assert.strictEqual(over({ 'a': 1, '1': 0 }), true); - assert.strictEqual(over({ 'a': 0, '1': 1 }), true); - - over = overSome([['a', 1]]); - - assert.strictEqual(over({ 'a': 1 }), true); - assert.strictEqual(over({ 'a': 2 }), false); - }); - - it('should flatten `predicates`', function() { - var over = overSome(stubFalse, [stubTrue]); - assert.strictEqual(over(), true); - }); - - it('should provide arguments to predicates', function() { - var args; - - var over = overSome(function() { - args = slice.call(arguments); - }); - - over('a', 'b', 'c'); - assert.deepStrictEqual(args, ['a', 'b', 'c']); - }); - - it('should use `this` binding of function for `predicates`', function() { - var over = overSome(function() { return this.b; }, function() { return this.a; }), - object = { 'over': over, 'a': 1, 'b': 2 }; - - assert.strictEqual(object.over(), true); - - object.a = object.b = 0; - assert.strictEqual(object.over(), false); - }); -}); diff --git a/test/overSome.spec.ts b/test/overSome.spec.ts new file mode 100644 index 000000000..cbd0db367 --- /dev/null +++ b/test/overSome.spec.ts @@ -0,0 +1,123 @@ +import assert from 'node:assert'; +import { + stubFalse, + stubOne, + stubString, + stubNull, + stubA, + stubZero, + stubTrue, + slice, +} from './utils'; +import overSome from '../src/overSome'; + +describe('overSome', () => { + it('should create a function that returns `true` if any predicates return truthy', () => { + let over = overSome(stubFalse, stubOne, stubString); + assert.strictEqual(over(), true); + + over = overSome(stubNull, stubA, stubZero); + assert.strictEqual(over(), true); + }); + + it('should return `true` as soon as `predicate` returns truthy', () => { + let count = 0, + countFalse = function () { + count++; + return false; + }, + countTrue = function () { + count++; + return true; + }, + over = overSome(countFalse, countTrue, countFalse); + + assert.strictEqual(over(), true); + assert.strictEqual(count, 2); + }); + + it('should return `false` if all predicates return falsey', () => { + let over = overSome(stubFalse, stubFalse, stubFalse); + assert.strictEqual(over(), false); + + over = overSome(stubNull, stubZero, stubString); + assert.strictEqual(over(), false); + }); + + it('should use `_.identity` when a predicate is nullish', () => { + const over = overSome(undefined, null); + + assert.strictEqual(over(true), true); + assert.strictEqual(over(false), false); + }); + + it('should work with `_.property` shorthands', () => { + const over = overSome('b', 'a'); + + assert.strictEqual(over({ a: 1, b: 0 }), true); + assert.strictEqual(over({ a: 0, b: 0 }), false); + }); + + it('should work with `_.matches` shorthands', () => { + const over = overSome({ b: 2 }, { a: 1 }); + + assert.strictEqual(over({ a: 0, b: 2 }), true); + assert.strictEqual(over({ a: 0, b: 0 }), false); + }); + + it('should work with `_.matchesProperty` shorthands', () => { + const over = overSome([ + ['b', 2], + ['a', 1], + ]); + + assert.strictEqual(over({ a: 0, b: 2 }), true); + assert.strictEqual(over({ a: 0, b: 0 }), false); + }); + + it('should differentiate between `_.property` and `_.matchesProperty` shorthands', () => { + let over = overSome(['a', 1]); + + assert.strictEqual(over({ a: 0, '1': 0 }), false); + assert.strictEqual(over({ a: 1, '1': 0 }), true); + assert.strictEqual(over({ a: 0, '1': 1 }), true); + + over = overSome([['a', 1]]); + + assert.strictEqual(over({ a: 1 }), true); + assert.strictEqual(over({ a: 2 }), false); + }); + + it('should flatten `predicates`', () => { + const over = overSome(stubFalse, [stubTrue]); + assert.strictEqual(over(), true); + }); + + it('should provide arguments to predicates', () => { + let args; + + const over = overSome(function () { + args = slice.call(arguments); + }); + + over('a', 'b', 'c'); + assert.deepStrictEqual(args, ['a', 'b', 'c']); + }); + + it('should use `this` binding of function for `predicates`', () => { + const over = overSome( + function () { + return this.b; + }, + function () { + return this.a; + }, + ), + object = { over: over, a: 1, b: 2 }; + + assert.strictEqual(object.over(), true); + + object.a = object.b = 0; + assert.strictEqual(object.over(), false); + }); +}); diff --git a/test/pad-methods.js b/test/pad-methods.js deleted file mode 100644 index 8d2e61a04..000000000 --- a/test/pad-methods.js +++ /dev/null @@ -1,51 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; -import pad from '../pad.js'; - -describe('pad methods', function() { - lodashStable.each(['pad', 'padStart', 'padEnd'], function(methodName) { - var func = _[methodName], - isPad = methodName == 'pad', - isStart = methodName == 'padStart', - string = 'abc'; - - it('`_.' + methodName + '` should not pad if string is >= `length`', function() { - assert.strictEqual(func(string, 2), string); - assert.strictEqual(func(string, 3), string); - }); - - it('`_.' + methodName + '` should treat negative `length` as `0`', function() { - lodashStable.each([0, -2], function(length) { - assert.strictEqual(func(string, length), string); - }); - }); - - it('`_.' + methodName + '` should coerce `length` to a number', function() { - lodashStable.each(['', '4'], function(length) { - var actual = length ? (isStart ? ' abc' : 'abc ') : string; - assert.strictEqual(func(string, length), actual); - }); - }); - - it('`_.' + methodName + '` should treat nullish values as empty strings', function() { - lodashStable.each([undefined, '_-'], function(chars) { - var expected = chars ? (isPad ? '__' : chars) : ' '; - assert.strictEqual(func(null, 2, chars), expected); - assert.strictEqual(func(undefined, 2, chars), expected); - assert.strictEqual(func('', 2, chars), expected); - }); - }); - - it('`_.' + methodName + '` should return `string` when `chars` coerces to an empty string', function() { - var values = ['', Object('')], - expected = lodashStable.map(values, lodashStable.constant(string)); - - var actual = lodashStable.map(values, function(value) { - return pad(string, 6, value); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/pad-methods.spec.ts b/test/pad-methods.spec.ts new file mode 100644 index 000000000..1704cf84b --- /dev/null +++ b/test/pad-methods.spec.ts @@ -0,0 +1,49 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; +import pad from '../src/pad'; + +describe('pad methods', () => { + lodashStable.each(['pad', 'padStart', 'padEnd'], (methodName) => { + const func = _[methodName], + isPad = methodName == 'pad', + isStart = methodName == 'padStart', + string = 'abc'; + + it(`\`_.${methodName}\` should not pad if string is >= \`length\``, () => { + assert.strictEqual(func(string, 2), string); + assert.strictEqual(func(string, 3), string); + }); + + it(`\`_.${methodName}\` should treat negative \`length\` as \`0\``, () => { + lodashStable.each([0, -2], (length) => { + assert.strictEqual(func(string, length), string); + }); + }); + + it(`\`_.${methodName}\` should coerce \`length\` to a number`, () => { + lodashStable.each(['', '4'], (length) => { + const actual = length ? (isStart ? ' abc' : 'abc ') : string; + assert.strictEqual(func(string, length), actual); + }); + }); + + it(`\`_.${methodName}\` should treat nullish values as empty strings`, () => { + lodashStable.each([undefined, '_-'], (chars) => { + const expected = chars ? (isPad ? '__' : chars) : ' '; + assert.strictEqual(func(null, 2, chars), expected); + assert.strictEqual(func(undefined, 2, chars), expected); + assert.strictEqual(func('', 2, chars), expected); + }); + }); + + it(`\`_.${methodName}\` should return \`string\` when \`chars\` coerces to an empty string`, () => { + const values = ['', Object('')], + expected = lodashStable.map(values, lodashStable.constant(string)); + + const actual = lodashStable.map(values, (value) => pad(string, 6, value)); + + assert.deepStrictEqual(actual, expected); + }); + }); +}); diff --git a/test/pad.js b/test/pad.js deleted file mode 100644 index 8a62fe036..000000000 --- a/test/pad.js +++ /dev/null @@ -1,35 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubTrue } from './utils.js'; -import pad from '../pad.js'; - -describe('pad', function() { - var string = 'abc'; - - it('should pad a string to a given length', function() { - var values = [, undefined], - expected = lodashStable.map(values, lodashStable.constant(' abc ')); - - var actual = lodashStable.map(values, function(value, index) { - return index ? pad(string, 6, value) : pad(string, 6); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should truncate pad characters to fit the pad length', function() { - assert.strictEqual(pad(string, 8), ' abc '); - assert.strictEqual(pad(string, 8, '_-'), '_-abc_-_'); - }); - - it('should coerce `string` to a string', function() { - var values = [Object(string), { 'toString': lodashStable.constant(string) }], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value) { - return pad(value, 6) === ' abc '; - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/pad.spec.ts b/test/pad.spec.ts new file mode 100644 index 000000000..fa8cc3238 --- /dev/null +++ b/test/pad.spec.ts @@ -0,0 +1,33 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubTrue } from './utils'; +import pad from '../src/pad'; + +describe('pad', () => { + const string = 'abc'; + + it('should pad a string to a given length', () => { + const values = [, undefined], + expected = lodashStable.map(values, lodashStable.constant(' abc ')); + + const actual = lodashStable.map(values, (value, index) => + index ? pad(string, 6, value) : pad(string, 6), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should truncate pad characters to fit the pad length', () => { + assert.strictEqual(pad(string, 8), ' abc '); + assert.strictEqual(pad(string, 8, '_-'), '_-abc_-_'); + }); + + it('should coerce `string` to a string', () => { + const values = [Object(string), { toString: lodashStable.constant(string) }], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (value) => pad(value, 6) === ' abc '); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/padEnd.js b/test/padEnd.js deleted file mode 100644 index 6edb5232c..000000000 --- a/test/padEnd.js +++ /dev/null @@ -1,34 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubTrue } from './utils.js'; -import padEnd from '../padEnd.js'; - -describe('padEnd', function() { - var string = 'abc'; - - it('should pad a string to a given length', function() { - var values = [, undefined], - expected = lodashStable.map(values, lodashStable.constant('abc ')); - - var actual = lodashStable.map(values, function(value, index) { - return index ? padEnd(string, 6, value) : padEnd(string, 6); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should truncate pad characters to fit the pad length', function() { - assert.strictEqual(padEnd(string, 6, '_-'), 'abc_-_'); - }); - - it('should coerce `string` to a string', function() { - var values = [Object(string), { 'toString': lodashStable.constant(string) }], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value) { - return padEnd(value, 6) === 'abc '; - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/padEnd.spec.ts b/test/padEnd.spec.ts new file mode 100644 index 000000000..c36d8635c --- /dev/null +++ b/test/padEnd.spec.ts @@ -0,0 +1,32 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubTrue } from './utils'; +import padEnd from '../src/padEnd'; + +describe('padEnd', () => { + const string = 'abc'; + + it('should pad a string to a given length', () => { + const values = [, undefined], + expected = lodashStable.map(values, lodashStable.constant('abc ')); + + const actual = lodashStable.map(values, (value, index) => + index ? padEnd(string, 6, value) : padEnd(string, 6), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should truncate pad characters to fit the pad length', () => { + assert.strictEqual(padEnd(string, 6, '_-'), 'abc_-_'); + }); + + it('should coerce `string` to a string', () => { + const values = [Object(string), { toString: lodashStable.constant(string) }], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (value) => padEnd(value, 6) === 'abc '); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/padStart.js b/test/padStart.js deleted file mode 100644 index 9ec998858..000000000 --- a/test/padStart.js +++ /dev/null @@ -1,34 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubTrue } from './utils.js'; -import padStart from '../padStart.js'; - -describe('padStart', function() { - var string = 'abc'; - - it('should pad a string to a given length', function() { - var values = [, undefined], - expected = lodashStable.map(values, lodashStable.constant(' abc')); - - var actual = lodashStable.map(values, function(value, index) { - return index ? padStart(string, 6, value) : padStart(string, 6); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should truncate pad characters to fit the pad length', function() { - assert.strictEqual(padStart(string, 6, '_-'), '_-_abc'); - }); - - it('should coerce `string` to a string', function() { - var values = [Object(string), { 'toString': lodashStable.constant(string) }], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value) { - return padStart(value, 6) === ' abc'; - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/padStart.spec.ts b/test/padStart.spec.ts new file mode 100644 index 000000000..868043ea8 --- /dev/null +++ b/test/padStart.spec.ts @@ -0,0 +1,32 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubTrue } from './utils'; +import padStart from '../src/padStart'; + +describe('padStart', () => { + const string = 'abc'; + + it('should pad a string to a given length', () => { + const values = [, undefined], + expected = lodashStable.map(values, lodashStable.constant(' abc')); + + const actual = lodashStable.map(values, (value, index) => + index ? padStart(string, 6, value) : padStart(string, 6), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should truncate pad characters to fit the pad length', () => { + assert.strictEqual(padStart(string, 6, '_-'), '_-_abc'); + }); + + it('should coerce `string` to a string', () => { + const values = [Object(string), { toString: lodashStable.constant(string) }], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (value) => padStart(value, 6) === ' abc'); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/parseInt.js b/test/parseInt.js deleted file mode 100644 index d068cbfe4..000000000 --- a/test/parseInt.js +++ /dev/null @@ -1,81 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { lodashBizarro, whitespace, stubZero } from './utils.js'; -import parseInt from '../parseInt.js'; - -describe('parseInt', function() { - it('should accept a `radix`', function() { - var expected = lodashStable.range(2, 37); - - var actual = lodashStable.map(expected, function(radix) { - return parseInt('10', radix); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should use a radix of `10`, for non-hexadecimals, if `radix` is `undefined` or `0`', function() { - assert.strictEqual(parseInt('10'), 10); - assert.strictEqual(parseInt('10', 0), 10); - assert.strictEqual(parseInt('10', 10), 10); - assert.strictEqual(parseInt('10', undefined), 10); - }); - - it('should use a radix of `16`, for hexadecimals, if `radix` is `undefined` or `0`', function() { - lodashStable.each(['0x20', '0X20'], function(string) { - assert.strictEqual(parseInt(string), 32); - assert.strictEqual(parseInt(string, 0), 32); - assert.strictEqual(parseInt(string, 16), 32); - assert.strictEqual(parseInt(string, undefined), 32); - }); - }); - - it('should use a radix of `10` for string with leading zeros', function() { - assert.strictEqual(parseInt('08'), 8); - assert.strictEqual(parseInt('08', 10), 8); - }); - - it('should parse strings with leading whitespace', function() { - var expected = [8, 8, 10, 10, 32, 32, 32, 32]; - - lodashStable.times(2, function(index) { - var actual = [], - func = (index ? (lodashBizarro || {}) : _).parseInt; - - if (func) { - lodashStable.times(2, function(otherIndex) { - var string = otherIndex ? '10' : '08'; - actual.push( - func(whitespace + string, 10), - func(whitespace + string) - ); - }); - - lodashStable.each(['0x20', '0X20'], function(string) { - actual.push( - func(whitespace + string), - func(whitespace + string, 16) - ); - }); - - assert.deepStrictEqual(actual, expected); - } - }); - }); - - it('should coerce `radix` to a number', function() { - var object = { 'valueOf': stubZero }; - assert.strictEqual(parseInt('08', object), 8); - assert.strictEqual(parseInt('0x20', object), 32); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var strings = lodashStable.map(['6', '08', '10'], Object), - actual = lodashStable.map(strings, parseInt); - - assert.deepStrictEqual(actual, [6, 8, 10]); - - actual = lodashStable.map('123', parseInt); - assert.deepStrictEqual(actual, [1, 2, 3]); - }); -}); diff --git a/test/parseInt.spec.ts b/test/parseInt.spec.ts new file mode 100644 index 000000000..a3e1de513 --- /dev/null +++ b/test/parseInt.spec.ts @@ -0,0 +1,73 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { lodashBizarro, whitespace, stubZero } from './utils'; +import parseInt from '../src/parseInt'; + +describe('parseInt', () => { + it('should accept a `radix`', () => { + const expected = lodashStable.range(2, 37); + + const actual = lodashStable.map(expected, (radix) => parseInt('10', radix)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should use a radix of `10`, for non-hexadecimals, if `radix` is `undefined` or `0`', () => { + assert.strictEqual(parseInt('10'), 10); + assert.strictEqual(parseInt('10', 0), 10); + assert.strictEqual(parseInt('10', 10), 10); + assert.strictEqual(parseInt('10', undefined), 10); + }); + + it('should use a radix of `16`, for hexadecimals, if `radix` is `undefined` or `0`', () => { + lodashStable.each(['0x20', '0X20'], (string) => { + assert.strictEqual(parseInt(string), 32); + assert.strictEqual(parseInt(string, 0), 32); + assert.strictEqual(parseInt(string, 16), 32); + assert.strictEqual(parseInt(string, undefined), 32); + }); + }); + + it('should use a radix of `10` for string with leading zeros', () => { + assert.strictEqual(parseInt('08'), 8); + assert.strictEqual(parseInt('08', 10), 8); + }); + + it('should parse strings with leading whitespace', () => { + const expected = [8, 8, 10, 10, 32, 32, 32, 32]; + + lodashStable.times(2, (index) => { + const actual = [], + func = (index ? lodashBizarro || {} : _).parseInt; + + if (func) { + lodashStable.times(2, (otherIndex) => { + const string = otherIndex ? '10' : '08'; + actual.push(func(whitespace + string, 10), func(whitespace + string)); + }); + + lodashStable.each(['0x20', '0X20'], (string) => { + actual.push(func(whitespace + string), func(whitespace + string, 16)); + }); + + assert.deepStrictEqual(actual, expected); + } + }); + }); + + it('should coerce `radix` to a number', () => { + const object = { valueOf: stubZero }; + assert.strictEqual(parseInt('08', object), 8); + assert.strictEqual(parseInt('0x20', object), 32); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + let strings = lodashStable.map(['6', '08', '10'], Object), + actual = lodashStable.map(strings, parseInt); + + assert.deepStrictEqual(actual, [6, 8, 10]); + + actual = lodashStable.map('123', parseInt); + assert.deepStrictEqual(actual, [1, 2, 3]); + }); +}); diff --git a/test/partial-methods.js b/test/partial-methods.js deleted file mode 100644 index 4509c9916..000000000 --- a/test/partial-methods.js +++ /dev/null @@ -1,113 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, identity, slice } from './utils.js'; -import placeholder from '../placeholder.js'; -import curry from '../curry.js'; - -describe('partial methods', function() { - lodashStable.each(['partial', 'partialRight'], function(methodName) { - var func = _[methodName], - isPartial = methodName == 'partial', - ph = func.placeholder; - - it('`_.' + methodName + '` partially applies arguments', function() { - var par = func(identity, 'a'); - assert.strictEqual(par(), 'a'); - }); - - it('`_.' + methodName + '` creates a function that can be invoked with additional arguments', function() { - var fn = function(a, b) { return [a, b]; }, - par = func(fn, 'a'), - expected = isPartial ? ['a', 'b'] : ['b', 'a']; - - assert.deepStrictEqual(par('b'), expected); - }); - - it('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked without additional arguments', function() { - var fn = function() { return arguments.length; }, - par = func(fn); - - assert.strictEqual(par(), 0); - }); - - it('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked with additional arguments', function() { - var par = func(identity); - assert.strictEqual(par('a'), 'a'); - }); - - it('`_.' + methodName + '` should support placeholders', function() { - var fn = function() { return slice.call(arguments); }, - par = func(fn, ph, 'b', ph); - - assert.deepStrictEqual(par('a', 'c'), ['a', 'b', 'c']); - assert.deepStrictEqual(par('a'), ['a', 'b', undefined]); - assert.deepStrictEqual(par(), [undefined, 'b', undefined]); - - if (isPartial) { - assert.deepStrictEqual(par('a', 'c', 'd'), ['a', 'b', 'c', 'd']); - } else { - par = func(fn, ph, 'c', ph); - assert.deepStrictEqual(par('a', 'b', 'd'), ['a', 'b', 'c', 'd']); - } - }); - - it('`_.' + methodName + '` should use `_.placeholder` when set', function() { - var _ph = placeholder = {}, - fn = function() { return slice.call(arguments); }, - par = func(fn, _ph, 'b', ph), - expected = isPartial ? ['a', 'b', ph, 'c'] : ['a', 'c', 'b', ph]; - - assert.deepEqual(par('a', 'c'), expected); - delete placeholder; - }); - - it('`_.' + methodName + '` creates a function with a `length` of `0`', function() { - var fn = function(a, b, c) {}, - par = func(fn, 'a'); - - assert.strictEqual(par.length, 0); - }); - - it('`_.' + methodName + '` should ensure `new par` is an instance of `func`', function() { - function Foo(value) { - return value && object; - } - - var object = {}, - par = func(Foo); - - assert.ok(new par instanceof Foo); - assert.strictEqual(new par(true), object); - }); - - it('`_.' + methodName + '` should clone metadata for created functions', function() { - function greet(greeting, name) { - return greeting + ' ' + name; - } - - var par1 = func(greet, 'hi'), - par2 = func(par1, 'barney'), - par3 = func(par1, 'pebbles'); - - assert.strictEqual(par1('fred'), isPartial ? 'hi fred' : 'fred hi'); - assert.strictEqual(par2(), isPartial ? 'hi barney' : 'barney hi'); - assert.strictEqual(par3(), isPartial ? 'hi pebbles' : 'pebbles hi'); - }); - - it('`_.' + methodName + '` should work with curried functions', function() { - var fn = function(a, b, c) { return a + b + c; }, - curried = curry(func(fn, 1), 2); - - assert.strictEqual(curried(2, 3), 6); - assert.strictEqual(curried(2)(3), 6); - }); - - it('should work with placeholders and curried functions', function() { - var fn = function() { return slice.call(arguments); }, - curried = curry(fn), - par = func(curried, ph, 'b', ph, 'd'); - - assert.deepStrictEqual(par('a', 'c'), ['a', 'b', 'c', 'd']); - }); - }); -}); diff --git a/test/partial-methods.spec.ts b/test/partial-methods.spec.ts new file mode 100644 index 000000000..355c1d6eb --- /dev/null +++ b/test/partial-methods.spec.ts @@ -0,0 +1,125 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, identity, slice } from './utils'; +import placeholder from '../src/placeholder'; +import curry from '../src/curry'; + +describe('partial methods', () => { + lodashStable.each(['partial', 'partialRight'], (methodName) => { + const func = _[methodName], + isPartial = methodName == 'partial', + ph = func.placeholder; + + it(`\`_.${methodName}\` partially applies arguments`, () => { + const par = func(identity, 'a'); + assert.strictEqual(par(), 'a'); + }); + + it(`\`_.${methodName}\` creates a function that can be invoked with additional arguments`, () => { + const fn = function (a, b) { + return [a, b]; + }, + par = func(fn, 'a'), + expected = isPartial ? ['a', 'b'] : ['b', 'a']; + + assert.deepStrictEqual(par('b'), expected); + }); + + it(`\`_.${methodName}\` works when there are no partially applied arguments and the created function is invoked without additional arguments`, () => { + const fn = function () { + return arguments.length; + }, + par = func(fn); + + assert.strictEqual(par(), 0); + }); + + it(`\`_.${methodName}\` works when there are no partially applied arguments and the created function is invoked with additional arguments`, () => { + const par = func(identity); + assert.strictEqual(par('a'), 'a'); + }); + + it(`\`_.${methodName}\` should support placeholders`, () => { + let fn = function () { + return slice.call(arguments); + }, + par = func(fn, ph, 'b', ph); + + assert.deepStrictEqual(par('a', 'c'), ['a', 'b', 'c']); + assert.deepStrictEqual(par('a'), ['a', 'b', undefined]); + assert.deepStrictEqual(par(), [undefined, 'b', undefined]); + + if (isPartial) { + assert.deepStrictEqual(par('a', 'c', 'd'), ['a', 'b', 'c', 'd']); + } else { + par = func(fn, ph, 'c', ph); + assert.deepStrictEqual(par('a', 'b', 'd'), ['a', 'b', 'c', 'd']); + } + }); + + it(`\`_.${methodName}\` should use \`_.placeholder\` when set`, () => { + const _ph = (placeholder = {}), + fn = function () { + return slice.call(arguments); + }, + par = func(fn, _ph, 'b', ph), + expected = isPartial ? ['a', 'b', ph, 'c'] : ['a', 'c', 'b', ph]; + + assert.deepEqual(par('a', 'c'), expected); + delete placeholder; + }); + + it(`\`_.${methodName}\` creates a function with a \`length\` of \`0\``, () => { + const fn = function (a, b, c) {}, + par = func(fn, 'a'); + + assert.strictEqual(par.length, 0); + }); + + it(`\`_.${methodName}\` should ensure \`new par\` is an instance of \`func\``, () => { + function Foo(value) { + return value && object; + } + + var object = {}, + par = func(Foo); + + assert.ok(new par() instanceof Foo); + assert.strictEqual(new par(true), object); + }); + + it(`\`_.${methodName}\` should clone metadata for created functions`, () => { + function greet(greeting, name) { + return `${greeting} ${name}`; + } + + const par1 = func(greet, 'hi'), + par2 = func(par1, 'barney'), + par3 = func(par1, 'pebbles'); + + assert.strictEqual(par1('fred'), isPartial ? 'hi fred' : 'fred hi'); + assert.strictEqual(par2(), isPartial ? 'hi barney' : 'barney hi'); + assert.strictEqual(par3(), isPartial ? 'hi pebbles' : 'pebbles hi'); + }); + + it(`\`_.${methodName}\` should work with curried functions`, () => { + const fn = function (a, b, c) { + return a + b + c; + }, + curried = curry(func(fn, 1), 2); + + assert.strictEqual(curried(2, 3), 6); + assert.strictEqual(curried(2)(3), 6); + }); + + it('should work with placeholders and curried functions', () => { + const fn = function () { + return slice.call(arguments); + }, + curried = curry(fn), + par = func(curried, ph, 'b', ph, 'd'); + + assert.deepStrictEqual(par('a', 'c'), ['a', 'b', 'c', 'd']); + }); + }); +}); diff --git a/test/partialRight.js b/test/partialRight.js deleted file mode 100644 index 87d48e4cc..000000000 --- a/test/partialRight.js +++ /dev/null @@ -1,18 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import partialRight from '../partialRight.js'; -import mergeWith from '../mergeWith.js'; - -describe('partialRight', function() { - it('should work as a deep `_.defaults`', function() { - var object = { 'a': { 'b': 2 } }, - source = { 'a': { 'b': 3, 'c': 3 } }, - expected = { 'a': { 'b': 2, 'c': 3 } }; - - var defaultsDeep = partialRight(mergeWith, function deep(value, other) { - return lodashStable.isObject(value) ? mergeWith(value, other, deep) : value; - }); - - assert.deepStrictEqual(defaultsDeep(object, source), expected); - }); -}); diff --git a/test/partialRight.spec.ts b/test/partialRight.spec.ts new file mode 100644 index 000000000..2b62a6bb5 --- /dev/null +++ b/test/partialRight.spec.ts @@ -0,0 +1,18 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import partialRight from '../src/partialRight'; +import mergeWith from '../src/mergeWith'; + +describe('partialRight', () => { + it('should work as a deep `_.defaults`', () => { + const object = { a: { b: 2 } }, + source = { a: { b: 3, c: 3 } }, + expected = { a: { b: 2, c: 3 } }; + + const defaultsDeep = partialRight(mergeWith, function deep(value, other) { + return lodashStable.isObject(value) ? mergeWith(value, other, deep) : value; + }); + + assert.deepStrictEqual(defaultsDeep(object, source), expected); + }); +}); diff --git a/test/partition.js b/test/partition.js deleted file mode 100644 index 1767548a1..000000000 --- a/test/partition.js +++ /dev/null @@ -1,48 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { identity, stubTrue, stubFalse } from './utils.js'; -import partition from '../partition.js'; - -describe('partition', function() { - var array = [1, 0, 1]; - - it('should split elements into two groups by `predicate`', function() { - assert.deepStrictEqual(partition([], identity), [[], []]); - assert.deepStrictEqual(partition(array, stubTrue), [array, []]); - assert.deepStrictEqual(partition(array, stubFalse), [[], array]); - }); - - it('should use `_.identity` when `predicate` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant([[1, 1], [0]])); - - var actual = lodashStable.map(values, function(value, index) { - return index ? partition(array, value) : partition(array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `_.property` shorthands', function() { - var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }], - actual = partition(objects, 'a'); - - assert.deepStrictEqual(actual, [objects.slice(0, 2), objects.slice(2)]); - }); - - it('should work with a number for `predicate`', function() { - var array = [ - [1, 0], - [0, 1], - [1, 0] - ]; - - assert.deepStrictEqual(partition(array, 0), [[array[0], array[2]], [array[1]]]); - assert.deepStrictEqual(partition(array, 1), [[array[1]], [array[0], array[2]]]); - }); - - it('should work with an object for `collection`', function() { - var actual = partition({ 'a': 1.1, 'b': 0.2, 'c': 1.3 }, Math.floor); - assert.deepStrictEqual(actual, [[1.1, 1.3], [0.2]]); - }); -}); diff --git a/test/partition.spec.ts b/test/partition.spec.ts new file mode 100644 index 000000000..2d6771779 --- /dev/null +++ b/test/partition.spec.ts @@ -0,0 +1,48 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { identity, stubTrue, stubFalse } from './utils'; +import partition from '../src/partition'; + +describe('partition', () => { + const array = [1, 0, 1]; + + it('should split elements into two groups by `predicate`', () => { + assert.deepStrictEqual(partition([], identity), [[], []]); + assert.deepStrictEqual(partition(array, stubTrue), [array, []]); + assert.deepStrictEqual(partition(array, stubFalse), [[], array]); + }); + + it('should use `_.identity` when `predicate` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant([[1, 1], [0]])); + + const actual = lodashStable.map(values, (value, index) => + index ? partition(array, value) : partition(array), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `_.property` shorthands', () => { + const objects = [{ a: 1 }, { a: 1 }, { b: 2 }], + actual = partition(objects, 'a'); + + assert.deepStrictEqual(actual, [objects.slice(0, 2), objects.slice(2)]); + }); + + it('should work with a number for `predicate`', () => { + const array = [ + [1, 0], + [0, 1], + [1, 0], + ]; + + assert.deepStrictEqual(partition(array, 0), [[array[0], array[2]], [array[1]]]); + assert.deepStrictEqual(partition(array, 1), [[array[1]], [array[0], array[2]]]); + }); + + it('should work with an object for `collection`', () => { + const actual = partition({ a: 1.1, b: 0.2, c: 1.3 }, Math.floor); + assert.deepStrictEqual(actual, [[1.1, 1.3], [0.2]]); + }); +}); diff --git a/test/pick-methods.js b/test/pick-methods.js deleted file mode 100644 index 50eb1188d..000000000 --- a/test/pick-methods.js +++ /dev/null @@ -1,85 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, symbol, defineProperty } from './utils.js'; - -describe('pick methods', function() { - lodashStable.each(['pick', 'pickBy'], function(methodName) { - var expected = { 'a': 1, 'c': 3 }, - func = _[methodName], - isPick = methodName == 'pick', - object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, - resolve = lodashStable.nthArg(1); - - if (methodName == 'pickBy') { - resolve = function(object, props) { - props = lodashStable.castArray(props); - return function(value) { - return lodashStable.some(props, function(key) { - key = lodashStable.isSymbol(key) ? key : lodashStable.toString(key); - return object[key] === value; - }); - }; - }; - } - it('`_.' + methodName + '` should create an object of picked string keyed properties', function() { - assert.deepStrictEqual(func(object, resolve(object, 'a')), { 'a': 1 }); - assert.deepStrictEqual(func(object, resolve(object, ['a', 'c'])), expected); - }); - - it('`_.' + methodName + '` should pick inherited string keyed properties', function() { - function Foo() {} - Foo.prototype = object; - - var foo = new Foo; - assert.deepStrictEqual(func(foo, resolve(foo, ['a', 'c'])), expected); - }); - - it('`_.' + methodName + '` should preserve the sign of `0`', function() { - var object = { '-0': 'a', '0': 'b' }, - props = [-0, Object(-0), 0, Object(0)], - expected = [{ '-0': 'a' }, { '-0': 'a' }, { '0': 'b' }, { '0': 'b' }]; - - var actual = lodashStable.map(props, function(key) { - return func(object, resolve(object, key)); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should pick symbols', function() { - function Foo() { - this[symbol] = 1; - } - - if (Symbol) { - var symbol2 = Symbol('b'); - Foo.prototype[symbol2] = 2; - - var symbol3 = Symbol('c'); - defineProperty(Foo.prototype, symbol3, { - 'configurable': true, - 'enumerable': false, - 'writable': true, - 'value': 3 - }); - - var foo = new Foo, - actual = func(foo, resolve(foo, [symbol, symbol2, symbol3])); - - assert.strictEqual(actual[symbol], 1); - assert.strictEqual(actual[symbol2], 2); - - if (isPick) { - assert.strictEqual(actual[symbol3], 3); - } else { - assert.ok(!(symbol3 in actual)); - } - } - }); - - it('`_.' + methodName + '` should work with an array `object`', function() { - var array = [1, 2, 3]; - assert.deepStrictEqual(func(array, resolve(array, '1')), { '1': 2 }); - }); - }); -}); diff --git a/test/pick-methods.spec.ts b/test/pick-methods.spec.ts new file mode 100644 index 000000000..feb61d50d --- /dev/null +++ b/test/pick-methods.spec.ts @@ -0,0 +1,83 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, symbol, defineProperty } from './utils'; + +describe('pick methods', () => { + lodashStable.each(['pick', 'pickBy'], (methodName) => { + let expected = { a: 1, c: 3 }, + func = _[methodName], + isPick = methodName == 'pick', + object = { a: 1, b: 2, c: 3, d: 4 }, + resolve = lodashStable.nthArg(1); + + if (methodName == 'pickBy') { + resolve = function (object, props) { + props = lodashStable.castArray(props); + return function (value) { + return lodashStable.some(props, (key) => { + key = lodashStable.isSymbol(key) ? key : lodashStable.toString(key); + return object[key] === value; + }); + }; + }; + } + it(`\`_.${methodName}\` should create an object of picked string keyed properties`, () => { + assert.deepStrictEqual(func(object, resolve(object, 'a')), { a: 1 }); + assert.deepStrictEqual(func(object, resolve(object, ['a', 'c'])), expected); + }); + + it(`\`_.${methodName}\` should pick inherited string keyed properties`, () => { + function Foo() {} + Foo.prototype = object; + + const foo = new Foo(); + assert.deepStrictEqual(func(foo, resolve(foo, ['a', 'c'])), expected); + }); + + it(`\`_.${methodName}\` should preserve the sign of \`0\``, () => { + const object = { '-0': 'a', '0': 'b' }, + props = [-0, Object(-0), 0, Object(0)], + expected = [{ '-0': 'a' }, { '-0': 'a' }, { '0': 'b' }, { '0': 'b' }]; + + const actual = lodashStable.map(props, (key) => func(object, resolve(object, key))); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should pick symbols`, () => { + function Foo() { + this[symbol] = 1; + } + + if (Symbol) { + const symbol2 = Symbol('b'); + Foo.prototype[symbol2] = 2; + + const symbol3 = Symbol('c'); + defineProperty(Foo.prototype, symbol3, { + configurable: true, + enumerable: false, + writable: true, + value: 3, + }); + + const foo = new Foo(), + actual = func(foo, resolve(foo, [symbol, symbol2, symbol3])); + + assert.strictEqual(actual[symbol], 1); + assert.strictEqual(actual[symbol2], 2); + + if (isPick) { + assert.strictEqual(actual[symbol3], 3); + } else { + assert.ok(!(symbol3 in actual)); + } + } + }); + + it(`\`_.${methodName}\` should work with an array \`object\``, () => { + const array = [1, 2, 3]; + assert.deepStrictEqual(func(array, resolve(array, '1')), { '1': 2 }); + }); + }); +}); diff --git a/test/pick.js b/test/pick.js deleted file mode 100644 index 08d62911d..000000000 --- a/test/pick.js +++ /dev/null @@ -1,52 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args, toArgs } from './utils.js'; -import pick from '../pick.js'; - -describe('pick', function() { - var args = toArgs(['a', 'c']), - object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, - nested = { 'a': 1, 'b': { 'c': 2, 'd': 3 } }; - - it('should flatten `paths`', function() { - assert.deepStrictEqual(pick(object, 'a', 'c'), { 'a': 1, 'c': 3 }); - assert.deepStrictEqual(pick(object, ['a', 'd'], 'c'), { 'a': 1, 'c': 3, 'd': 4 }); - }); - - it('should support deep paths', function() { - assert.deepStrictEqual(pick(nested, 'b.c'), { 'b': { 'c': 2 } }); - }); - - it('should support path arrays', function() { - var object = { 'a.b': 1, 'a': { 'b': 2 } }, - actual = pick(object, [['a.b']]); - - assert.deepStrictEqual(actual, { 'a.b': 1 }); - }); - - it('should pick a key over a path', function() { - var object = { 'a.b': 1, 'a': { 'b': 2 } }; - - lodashStable.each(['a.b', ['a.b']], function(path) { - assert.deepStrictEqual(pick(object, path), { 'a.b': 1 }); - }); - }); - - it('should coerce `paths` to strings', function() { - assert.deepStrictEqual(pick({ '0': 'a', '1': 'b' }, 0), { '0': 'a' }); - }); - - it('should return an empty object when `object` is nullish', function() { - lodashStable.each([null, undefined], function(value) { - assert.deepStrictEqual(pick(value, 'valueOf'), {}); - }); - }); - - it('should work with a primitive `object`', function() { - assert.deepStrictEqual(pick('', 'slice'), { 'slice': ''.slice }); - }); - - it('should work with `arguments` object `paths`', function() { - assert.deepStrictEqual(pick(object, args), { 'a': 1, 'c': 3 }); - }); -}); diff --git a/test/pick.spec.ts b/test/pick.spec.ts new file mode 100644 index 000000000..5367c579d --- /dev/null +++ b/test/pick.spec.ts @@ -0,0 +1,52 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args, toArgs } from './utils'; +import pick from '../src/pick'; + +describe('pick', () => { + const args = toArgs(['a', 'c']), + object = { a: 1, b: 2, c: 3, d: 4 }, + nested = { a: 1, b: { c: 2, d: 3 } }; + + it('should flatten `paths`', () => { + assert.deepStrictEqual(pick(object, 'a', 'c'), { a: 1, c: 3 }); + assert.deepStrictEqual(pick(object, ['a', 'd'], 'c'), { a: 1, c: 3, d: 4 }); + }); + + it('should support deep paths', () => { + assert.deepStrictEqual(pick(nested, 'b.c'), { b: { c: 2 } }); + }); + + it('should support path arrays', () => { + const object = { 'a.b': 1, a: { b: 2 } }, + actual = pick(object, [['a.b']]); + + assert.deepStrictEqual(actual, { 'a.b': 1 }); + }); + + it('should pick a key over a path', () => { + const object = { 'a.b': 1, a: { b: 2 } }; + + lodashStable.each(['a.b', ['a.b']], (path) => { + assert.deepStrictEqual(pick(object, path), { 'a.b': 1 }); + }); + }); + + it('should coerce `paths` to strings', () => { + assert.deepStrictEqual(pick({ '0': 'a', '1': 'b' }, 0), { '0': 'a' }); + }); + + it('should return an empty object when `object` is nullish', () => { + lodashStable.each([null, undefined], (value) => { + assert.deepStrictEqual(pick(value, 'valueOf'), {}); + }); + }); + + it('should work with a primitive `object`', () => { + assert.deepStrictEqual(pick('', 'slice'), { slice: ''.slice }); + }); + + it('should work with `arguments` object `paths`', () => { + assert.deepStrictEqual(pick(object, args), { a: 1, c: 3 }); + }); +}); diff --git a/test/pickBy.spec.ts b/test/pickBy.spec.ts new file mode 100644 index 000000000..1d2321411 --- /dev/null +++ b/test/pickBy.spec.ts @@ -0,0 +1,20 @@ +import assert from 'node:assert'; +import { stubTrue } from './utils'; +import pickBy from '../src/pickBy'; + +describe('pickBy', () => { + it('should work with a predicate argument', () => { + const object = { a: 1, b: 2, c: 3, d: 4 }; + + const actual = pickBy(object, (n) => n == 1 || n == 3); + + assert.deepStrictEqual(actual, { a: 1, c: 3 }); + }); + + it('should not treat keys with dots as deep paths', () => { + const object = { 'a.b.c': 1 }, + actual = pickBy(object, stubTrue); + + assert.deepStrictEqual(actual, { 'a.b.c': 1 }); + }); +}); diff --git a/test/pickBy.test.js b/test/pickBy.test.js deleted file mode 100644 index aa074daee..000000000 --- a/test/pickBy.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; -import { stubTrue } from './utils.js'; -import pickBy from '../pickBy.js'; - -describe('pickBy', function() { - it('should work with a predicate argument', function() { - var object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; - - var actual = pickBy(object, function(n) { - return n == 1 || n == 3; - }); - - assert.deepStrictEqual(actual, { 'a': 1, 'c': 3 }); - }); - - it('should not treat keys with dots as deep paths', function() { - var object = { 'a.b.c': 1 }, - actual = pickBy(object, stubTrue); - - assert.deepStrictEqual(actual, { 'a.b.c': 1 }); - }); -}); diff --git a/test/property.spec.ts b/test/property.spec.ts new file mode 100644 index 000000000..583f4545a --- /dev/null +++ b/test/property.spec.ts @@ -0,0 +1,125 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { noop } from './utils'; +import property from '../src/property'; + +describe('property', () => { + it('should create a function that plucks a property value of a given object', () => { + const object = { a: 1 }; + + lodashStable.each(['a', ['a']], (path) => { + const prop = property(path); + assert.strictEqual(prop.length, 1); + assert.strictEqual(prop(object), 1); + }); + }); + + it('should pluck deep property values', () => { + const object = { a: { b: 2 } }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const prop = property(path); + assert.strictEqual(prop(object), 2); + }); + }); + + it('should pluck inherited property values', () => { + function Foo() {} + Foo.prototype.a = 1; + + lodashStable.each(['a', ['a']], (path) => { + const prop = property(path); + assert.strictEqual(prop(new Foo()), 1); + }); + }); + + it('should work with a non-string `path`', () => { + const array = [1, 2, 3]; + + lodashStable.each([1, [1]], (path) => { + const prop = property(path); + assert.strictEqual(prop(array), 2); + }); + }); + + it('should preserve the sign of `0`', () => { + const object = { '-0': 'a', '0': 'b' }, + props = [-0, Object(-0), 0, Object(0)]; + + const actual = lodashStable.map(props, (key) => { + const prop = property(key); + return prop(object); + }); + + assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']); + }); + + it('should coerce `path` to a string', () => { + function fn() {} + fn.toString = lodashStable.constant('fn'); + + const expected = [1, 2, 3, 4], + object = { null: 1, undefined: 2, fn: 3, '[object Object]': 4 }, + paths = [null, undefined, fn, {}]; + + lodashStable.times(2, (index) => { + const actual = lodashStable.map(paths, (path) => { + const prop = property(index ? [path] : path); + return prop(object); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should pluck a key over a path', () => { + const object = { 'a.b': 1, a: { b: 2 } }; + + lodashStable.each(['a.b', ['a.b']], (path) => { + const prop = property(path); + assert.strictEqual(prop(object), 1); + }); + }); + + it('should return `undefined` when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, noop); + + lodashStable.each(['constructor', ['constructor']], (path) => { + const prop = property(path); + + const actual = lodashStable.map(values, (value, index) => + index ? prop(value) : prop(), + ); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should return `undefined` for deep paths when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, noop); + + lodashStable.each( + ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], + (path) => { + const prop = property(path); + + const actual = lodashStable.map(values, (value, index) => + index ? prop(value) : prop(), + ); + + assert.deepStrictEqual(actual, expected); + }, + ); + }); + + it('should return `undefined` if parts of `path` are missing', () => { + const object = {}; + + lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], (path) => { + const prop = property(path); + assert.strictEqual(prop(object), undefined); + }); + }); +}); diff --git a/test/property.test.js b/test/property.test.js deleted file mode 100644 index a846e1e10..000000000 --- a/test/property.test.js +++ /dev/null @@ -1,122 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { noop } from './utils.js'; -import property from '../property.js'; - -describe('property', function() { - it('should create a function that plucks a property value of a given object', function() { - var object = { 'a': 1 }; - - lodashStable.each(['a', ['a']], function(path) { - var prop = property(path); - assert.strictEqual(prop.length, 1); - assert.strictEqual(prop(object), 1); - }); - }); - - it('should pluck deep property values', function() { - var object = { 'a': { 'b': 2 } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var prop = property(path); - assert.strictEqual(prop(object), 2); - }); - }); - - it('should pluck inherited property values', function() { - function Foo() {} - Foo.prototype.a = 1; - - lodashStable.each(['a', ['a']], function(path) { - var prop = property(path); - assert.strictEqual(prop(new Foo), 1); - }); - }); - - it('should work with a non-string `path`', function() { - var array = [1, 2, 3]; - - lodashStable.each([1, [1]], function(path) { - var prop = property(path); - assert.strictEqual(prop(array), 2); - }); - }); - - it('should preserve the sign of `0`', function() { - var object = { '-0': 'a', '0': 'b' }, - props = [-0, Object(-0), 0, Object(0)]; - - var actual = lodashStable.map(props, function(key) { - var prop = property(key); - return prop(object); - }); - - assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']); - }); - - it('should coerce `path` to a string', function() { - function fn() {} - fn.toString = lodashStable.constant('fn'); - - var expected = [1, 2, 3, 4], - object = { 'null': 1, 'undefined': 2, 'fn': 3, '[object Object]': 4 }, - paths = [null, undefined, fn, {}]; - - lodashStable.times(2, function(index) { - var actual = lodashStable.map(paths, function(path) { - var prop = property(index ? [path] : path); - return prop(object); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should pluck a key over a path', function() { - var object = { 'a.b': 1, 'a': { 'b': 2 } }; - - lodashStable.each(['a.b', ['a.b']], function(path) { - var prop = property(path); - assert.strictEqual(prop(object), 1); - }); - }); - - it('should return `undefined` when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, noop); - - lodashStable.each(['constructor', ['constructor']], function(path) { - var prop = property(path); - - var actual = lodashStable.map(values, function(value, index) { - return index ? prop(value) : prop(); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `undefined` for deep paths when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, noop); - - lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { - var prop = property(path); - - var actual = lodashStable.map(values, function(value, index) { - return index ? prop(value) : prop(); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `undefined` if parts of `path` are missing', function() { - var object = {}; - - lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { - var prop = property(path); - assert.strictEqual(prop(object), undefined); - }); - }); -}); diff --git a/test/propertyOf.spec.ts b/test/propertyOf.spec.ts new file mode 100644 index 000000000..06c137889 --- /dev/null +++ b/test/propertyOf.spec.ts @@ -0,0 +1,125 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { noop } from './utils'; +import propertyOf from '../src/propertyOf'; + +describe('propertyOf', () => { + it('should create a function that plucks a property value of a given key', () => { + const object = { a: 1 }, + propOf = propertyOf(object); + + assert.strictEqual(propOf.length, 1); + lodashStable.each(['a', ['a']], (path) => { + assert.strictEqual(propOf(path), 1); + }); + }); + + it('should pluck deep property values', () => { + const object = { a: { b: 2 } }, + propOf = propertyOf(object); + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.strictEqual(propOf(path), 2); + }); + }); + + it('should pluck inherited property values', () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const propOf = propertyOf(new Foo()); + + lodashStable.each(['b', ['b']], (path) => { + assert.strictEqual(propOf(path), 2); + }); + }); + + it('should work with a non-string `path`', () => { + const array = [1, 2, 3], + propOf = propertyOf(array); + + lodashStable.each([1, [1]], (path) => { + assert.strictEqual(propOf(path), 2); + }); + }); + + it('should preserve the sign of `0`', () => { + const object = { '-0': 'a', '0': 'b' }, + props = [-0, Object(-0), 0, Object(0)]; + + const actual = lodashStable.map(props, (key) => { + const propOf = propertyOf(object); + return propOf(key); + }); + + assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']); + }); + + it('should coerce `path` to a string', () => { + function fn() {} + fn.toString = lodashStable.constant('fn'); + + const expected = [1, 2, 3, 4], + object = { null: 1, undefined: 2, fn: 3, '[object Object]': 4 }, + paths = [null, undefined, fn, {}]; + + lodashStable.times(2, (index) => { + const actual = lodashStable.map(paths, (path) => { + const propOf = propertyOf(object); + return propOf(index ? [path] : path); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should pluck a key over a path', () => { + const object = { 'a.b': 1, a: { b: 2 } }, + propOf = propertyOf(object); + + lodashStable.each(['a.b', ['a.b']], (path) => { + assert.strictEqual(propOf(path), 1); + }); + }); + + it('should return `undefined` when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, noop); + + lodashStable.each(['constructor', ['constructor']], (path) => { + const actual = lodashStable.map(values, (value, index) => { + const propOf = index ? propertyOf(value) : propertyOf(); + return propOf(path); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should return `undefined` for deep paths when `object` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, noop); + + lodashStable.each( + ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], + (path) => { + const actual = lodashStable.map(values, (value, index) => { + const propOf = index ? propertyOf(value) : propertyOf(); + return propOf(path); + }); + + assert.deepStrictEqual(actual, expected); + }, + ); + }); + + it('should return `undefined` if parts of `path` are missing', () => { + const propOf = propertyOf({}); + + lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], (path) => { + assert.strictEqual(propOf(path), undefined); + }); + }); +}); diff --git a/test/propertyOf.test.js b/test/propertyOf.test.js deleted file mode 100644 index 0fe43b7b3..000000000 --- a/test/propertyOf.test.js +++ /dev/null @@ -1,122 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { noop } from './utils.js'; -import propertyOf from '../propertyOf.js'; - -describe('propertyOf', function() { - it('should create a function that plucks a property value of a given key', function() { - var object = { 'a': 1 }, - propOf = propertyOf(object); - - assert.strictEqual(propOf.length, 1); - lodashStable.each(['a', ['a']], function(path) { - assert.strictEqual(propOf(path), 1); - }); - }); - - it('should pluck deep property values', function() { - var object = { 'a': { 'b': 2 } }, - propOf = propertyOf(object); - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.strictEqual(propOf(path), 2); - }); - }); - - it('should pluck inherited property values', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var propOf = propertyOf(new Foo); - - lodashStable.each(['b', ['b']], function(path) { - assert.strictEqual(propOf(path), 2); - }); - }); - - it('should work with a non-string `path`', function() { - var array = [1, 2, 3], - propOf = propertyOf(array); - - lodashStable.each([1, [1]], function(path) { - assert.strictEqual(propOf(path), 2); - }); - }); - - it('should preserve the sign of `0`', function() { - var object = { '-0': 'a', '0': 'b' }, - props = [-0, Object(-0), 0, Object(0)]; - - var actual = lodashStable.map(props, function(key) { - var propOf = propertyOf(object); - return propOf(key); - }); - - assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']); - }); - - it('should coerce `path` to a string', function() { - function fn() {} - fn.toString = lodashStable.constant('fn'); - - var expected = [1, 2, 3, 4], - object = { 'null': 1, 'undefined': 2, 'fn': 3, '[object Object]': 4 }, - paths = [null, undefined, fn, {}]; - - lodashStable.times(2, function(index) { - var actual = lodashStable.map(paths, function(path) { - var propOf = propertyOf(object); - return propOf(index ? [path] : path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should pluck a key over a path', function() { - var object = { 'a.b': 1, 'a': { 'b': 2 } }, - propOf = propertyOf(object); - - lodashStable.each(['a.b', ['a.b']], function(path) { - assert.strictEqual(propOf(path), 1); - }); - }); - - it('should return `undefined` when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, noop); - - lodashStable.each(['constructor', ['constructor']], function(path) { - var actual = lodashStable.map(values, function(value, index) { - var propOf = index ? propertyOf(value) : propertyOf(); - return propOf(path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `undefined` for deep paths when `object` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, noop); - - lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { - var actual = lodashStable.map(values, function(value, index) { - var propOf = index ? propertyOf(value) : propertyOf(); - return propOf(path); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should return `undefined` if parts of `path` are missing', function() { - var propOf = propertyOf({}); - - lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { - assert.strictEqual(propOf(path), undefined); - }); - }); -}); diff --git a/test/pull-methods.js b/test/pull-methods.js deleted file mode 100644 index 4336b48e8..000000000 --- a/test/pull-methods.js +++ /dev/null @@ -1,49 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('pull methods', function() { - lodashStable.each(['pull', 'pullAll', 'pullAllWith'], function(methodName) { - var func = _[methodName], - isPull = methodName == 'pull'; - - function pull(array, values) { - return isPull - ? func.apply(undefined, [array].concat(values)) - : func(array, values); - } - - it('`_.' + methodName + '` should modify and return the array', function() { - var array = [1, 2, 3], - actual = pull(array, [1, 3]); - - assert.strictEqual(actual, array); - assert.deepStrictEqual(array, [2]); - }); - - it('`_.' + methodName + '` should preserve holes in arrays', function() { - var array = [1, 2, 3, 4]; - delete array[1]; - delete array[3]; - - pull(array, [1]); - assert.ok(!('0' in array)); - assert.ok(!('2' in array)); - }); - - it('`_.' + methodName + '` should treat holes as `undefined`', function() { - var array = [1, 2, 3]; - delete array[1]; - - pull(array, [undefined]); - assert.deepStrictEqual(array, [1, 3]); - }); - - it('`_.' + methodName + '` should match `NaN`', function() { - var array = [1, NaN, 3, NaN]; - - pull(array, [NaN]); - assert.deepStrictEqual(array, [1, 3]); - }); - }); -}); diff --git a/test/pull-methods.spec.ts b/test/pull-methods.spec.ts new file mode 100644 index 000000000..c1192d31b --- /dev/null +++ b/test/pull-methods.spec.ts @@ -0,0 +1,47 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('pull methods', () => { + lodashStable.each(['pull', 'pullAll', 'pullAllWith'], (methodName) => { + const func = _[methodName], + isPull = methodName == 'pull'; + + function pull(array, values) { + return isPull ? func.apply(undefined, [array].concat(values)) : func(array, values); + } + + it(`\`_.${methodName}\` should modify and return the array`, () => { + const array = [1, 2, 3], + actual = pull(array, [1, 3]); + + assert.strictEqual(actual, array); + assert.deepStrictEqual(array, [2]); + }); + + it(`\`_.${methodName}\` should preserve holes in arrays`, () => { + const array = [1, 2, 3, 4]; + delete array[1]; + delete array[3]; + + pull(array, [1]); + assert.ok(!('0' in array)); + assert.ok(!('2' in array)); + }); + + it(`\`_.${methodName}\` should treat holes as \`undefined\``, () => { + const array = [1, 2, 3]; + delete array[1]; + + pull(array, [undefined]); + assert.deepStrictEqual(array, [1, 3]); + }); + + it(`\`_.${methodName}\` should match \`NaN\``, () => { + const array = [1, NaN, 3, NaN]; + + pull(array, [NaN]); + assert.deepStrictEqual(array, [1, 3]); + }); + }); +}); diff --git a/test/pullAll.spec.ts b/test/pullAll.spec.ts new file mode 100644 index 000000000..98f718c6f --- /dev/null +++ b/test/pullAll.spec.ts @@ -0,0 +1,11 @@ +import assert from 'node:assert'; +import pullAll from '../src/pullAll'; + +describe('pullAll', () => { + it('should work with the same value for `array` and `values`', () => { + const array = [{ a: 1 }, { b: 2 }], + actual = pullAll(array, array); + + assert.deepStrictEqual(actual, []); + }); +}); diff --git a/test/pullAll.test.js b/test/pullAll.test.js deleted file mode 100644 index 7579e6a0f..000000000 --- a/test/pullAll.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import assert from 'assert'; -import pullAll from '../pullAll.js'; - -describe('pullAll', function() { - it('should work with the same value for `array` and `values`', function() { - var array = [{ 'a': 1 }, { 'b': 2 }], - actual = pullAll(array, array); - - assert.deepStrictEqual(actual, []); - }); -}); diff --git a/test/pullAllBy.spec.ts b/test/pullAllBy.spec.ts new file mode 100644 index 000000000..4f60246d6 --- /dev/null +++ b/test/pullAllBy.spec.ts @@ -0,0 +1,24 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import pullAllBy from '../src/pullAllBy'; + +describe('pullAllBy', () => { + it('should accept an `iteratee`', () => { + const array = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }]; + + const actual = pullAllBy(array, [{ x: 1 }, { x: 3 }], (object) => object.x); + + assert.deepStrictEqual(actual, [{ x: 2 }]); + }); + + it('should provide correct `iteratee` arguments', () => { + let args, + array = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }]; + + pullAllBy(array, [{ x: 1 }, { x: 3 }], function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [{ x: 1 }]); + }); +}); diff --git a/test/pullAllBy.test.js b/test/pullAllBy.test.js deleted file mode 100644 index a7fb64f61..000000000 --- a/test/pullAllBy.test.js +++ /dev/null @@ -1,26 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import pullAllBy from '../pullAllBy.js'; - -describe('pullAllBy', function() { - it('should accept an `iteratee`', function() { - var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; - - var actual = pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], function(object) { - return object.x; - }); - - assert.deepStrictEqual(actual, [{ 'x': 2 }]); - }); - - it('should provide correct `iteratee` arguments', function() { - var args, - array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; - - pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [{ 'x': 1 }]); - }); -}); diff --git a/test/pullAllWith.spec.ts b/test/pullAllWith.spec.ts new file mode 100644 index 000000000..793931464 --- /dev/null +++ b/test/pullAllWith.spec.ts @@ -0,0 +1,17 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import pullAllWith from '../src/pullAllWith'; + +describe('pullAllWith', () => { + it('should work with a `comparator`', () => { + const objects = [ + { x: 1, y: 1 }, + { x: 2, y: 2 }, + { x: 3, y: 3 }, + ], + expected = [objects[0], objects[2]], + actual = pullAllWith(objects, [{ x: 2, y: 2 }], lodashStable.isEqual); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/pullAllWith.test.js b/test/pullAllWith.test.js deleted file mode 100644 index 3a47ebaae..000000000 --- a/test/pullAllWith.test.js +++ /dev/null @@ -1,13 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import pullAllWith from '../pullAllWith.js'; - -describe('pullAllWith', function() { - it('should work with a `comparator`', function() { - var objects = [{ 'x': 1, 'y': 1 }, { 'x': 2, 'y': 2 }, { 'x': 3, 'y': 3 }], - expected = [objects[0], objects[2]], - actual = pullAllWith(objects, [{ 'x': 2, 'y': 2 }], lodashStable.isEqual); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/pullAt.js b/test/pullAt.js deleted file mode 100644 index c70020eb2..000000000 --- a/test/pullAt.js +++ /dev/null @@ -1,122 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { empties, stubOne, noop, falsey } from './utils.js'; -import pullAt from '../pullAt.js'; - -describe('pullAt', function() { - it('should modify the array and return removed elements', function() { - var array = [1, 2, 3], - actual = pullAt(array, [0, 1]); - - assert.deepStrictEqual(array, [3]); - assert.deepStrictEqual(actual, [1, 2]); - }); - - it('should work with unsorted indexes', function() { - var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], - actual = pullAt(array, [1, 3, 11, 7, 5, 9]); - - assert.deepStrictEqual(array, [1, 3, 5, 7, 9, 11]); - assert.deepStrictEqual(actual, [2, 4, 12, 8, 6, 10]); - }); - - it('should work with repeated indexes', function() { - var array = [1, 2, 3, 4], - actual = pullAt(array, [0, 2, 0, 1, 0, 2]); - - assert.deepStrictEqual(array, [4]); - assert.deepStrictEqual(actual, [1, 3, 1, 2, 1, 3]); - }); - - it('should use `undefined` for nonexistent indexes', function() { - var array = ['a', 'b', 'c'], - actual = pullAt(array, [2, 4, 0]); - - assert.deepStrictEqual(array, ['b']); - assert.deepStrictEqual(actual, ['c', undefined, 'a']); - }); - - it('should flatten `indexes`', function() { - var array = ['a', 'b', 'c']; - assert.deepStrictEqual(pullAt(array, 2, 0), ['c', 'a']); - assert.deepStrictEqual(array, ['b']); - - array = ['a', 'b', 'c', 'd']; - assert.deepStrictEqual(pullAt(array, [3, 0], 2), ['d', 'a', 'c']); - assert.deepStrictEqual(array, ['b']); - }); - - it('should return an empty array when no indexes are given', function() { - var array = ['a', 'b', 'c'], - actual = pullAt(array); - - assert.deepStrictEqual(array, ['a', 'b', 'c']); - assert.deepStrictEqual(actual, []); - - actual = pullAt(array, [], []); - - assert.deepStrictEqual(array, ['a', 'b', 'c']); - assert.deepStrictEqual(actual, []); - }); - - it('should work with non-index paths', function() { - var values = lodashStable.reject(empties, function(value) { - return (value === 0) || lodashStable.isArray(value); - }).concat(-1, 1.1); - - var array = lodashStable.transform(values, function(result, value) { - result[value] = 1; - }, []); - - var expected = lodashStable.map(values, stubOne), - actual = pullAt(array, values); - - assert.deepStrictEqual(actual, expected); - - expected = lodashStable.map(values, noop); - actual = lodashStable.at(array, values); - - assert.deepStrictEqual(actual, expected); - }); - - it('should preserve the sign of `0`', function() { - var props = [-0, Object(-0), 0, Object(0)]; - - var actual = lodashStable.map(props, function(key) { - var array = [-1]; - array['-0'] = -2; - return pullAt(array, key); - }); - - assert.deepStrictEqual(actual, [[-2], [-2], [-1], [-1]]); - }); - - it('should support deep paths', function() { - var array = []; - array.a = { 'b': 2 }; - - var actual = pullAt(array, 'a.b'); - - assert.deepStrictEqual(actual, [2]); - assert.deepStrictEqual(array.a, {}); - - try { - actual = pullAt(array, 'a.b.c'); - } catch (e) {} - - assert.deepStrictEqual(actual, [undefined]); - }); - - it('should work with a falsey `array` when keys are given', function() { - var values = falsey.slice(), - expected = lodashStable.map(values, lodashStable.constant(Array(4))); - - var actual = lodashStable.map(values, function(array) { - try { - return pullAt(array, 0, 1, 'pop', 'push'); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/pullAt.spec.ts b/test/pullAt.spec.ts new file mode 100644 index 000000000..2ce4126d0 --- /dev/null +++ b/test/pullAt.spec.ts @@ -0,0 +1,126 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { empties, stubOne, noop, falsey } from './utils'; +import pullAt from '../src/pullAt'; + +describe('pullAt', () => { + it('should modify the array and return removed elements', () => { + const array = [1, 2, 3], + actual = pullAt(array, [0, 1]); + + assert.deepStrictEqual(array, [3]); + assert.deepStrictEqual(actual, [1, 2]); + }); + + it('should work with unsorted indexes', () => { + const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + actual = pullAt(array, [1, 3, 11, 7, 5, 9]); + + assert.deepStrictEqual(array, [1, 3, 5, 7, 9, 11]); + assert.deepStrictEqual(actual, [2, 4, 12, 8, 6, 10]); + }); + + it('should work with repeated indexes', () => { + const array = [1, 2, 3, 4], + actual = pullAt(array, [0, 2, 0, 1, 0, 2]); + + assert.deepStrictEqual(array, [4]); + assert.deepStrictEqual(actual, [1, 3, 1, 2, 1, 3]); + }); + + it('should use `undefined` for nonexistent indexes', () => { + const array = ['a', 'b', 'c'], + actual = pullAt(array, [2, 4, 0]); + + assert.deepStrictEqual(array, ['b']); + assert.deepStrictEqual(actual, ['c', undefined, 'a']); + }); + + it('should flatten `indexes`', () => { + let array = ['a', 'b', 'c']; + assert.deepStrictEqual(pullAt(array, 2, 0), ['c', 'a']); + assert.deepStrictEqual(array, ['b']); + + array = ['a', 'b', 'c', 'd']; + assert.deepStrictEqual(pullAt(array, [3, 0], 2), ['d', 'a', 'c']); + assert.deepStrictEqual(array, ['b']); + }); + + it('should return an empty array when no indexes are given', () => { + let array = ['a', 'b', 'c'], + actual = pullAt(array); + + assert.deepStrictEqual(array, ['a', 'b', 'c']); + assert.deepStrictEqual(actual, []); + + actual = pullAt(array, [], []); + + assert.deepStrictEqual(array, ['a', 'b', 'c']); + assert.deepStrictEqual(actual, []); + }); + + it('should work with non-index paths', () => { + const values = lodashStable + .reject(empties, (value) => value === 0 || lodashStable.isArray(value)) + .concat(-1, 1.1); + + const array = lodashStable.transform( + values, + (result, value) => { + result[value] = 1; + }, + [], + ); + + let expected = lodashStable.map(values, stubOne), + actual = pullAt(array, values); + + assert.deepStrictEqual(actual, expected); + + expected = lodashStable.map(values, noop); + actual = lodashStable.at(array, values); + + assert.deepStrictEqual(actual, expected); + }); + + it('should preserve the sign of `0`', () => { + const props = [-0, Object(-0), 0, Object(0)]; + + const actual = lodashStable.map(props, (key) => { + const array = [-1]; + array['-0'] = -2; + return pullAt(array, key); + }); + + assert.deepStrictEqual(actual, [[-2], [-2], [-1], [-1]]); + }); + + it('should support deep paths', () => { + const array = []; + array.a = { b: 2 }; + + let actual = pullAt(array, 'a.b'); + + assert.deepStrictEqual(actual, [2]); + assert.deepStrictEqual(array.a, {}); + + try { + actual = pullAt(array, 'a.b.c'); + } catch (e) {} + + assert.deepStrictEqual(actual, [undefined]); + }); + + it('should work with a falsey `array` when keys are given', () => { + const values = falsey.slice(), + expected = lodashStable.map(values, lodashStable.constant(Array(4))); + + const actual = lodashStable.map(values, (array) => { + try { + return pullAt(array, 0, 1, 'pop', 'push'); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/random.js b/test/random.js deleted file mode 100644 index a111dc84f..000000000 --- a/test/random.js +++ /dev/null @@ -1,104 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { MAX_INTEGER, stubTrue } from './utils.js'; -import random from '../random.js'; - -describe('random', function() { - var array = Array(1000); - - it('should return `0` or `1` when no arguments are given', function() { - var actual = lodashStable.uniq(lodashStable.map(array, function() { - return random(); - })).sort(); - - assert.deepStrictEqual(actual, [0, 1]); - }); - - it('should support a `min` and `max`', function() { - var min = 5, - max = 10; - - assert.ok(lodashStable.some(array, function() { - var result = random(min, max); - return result >= min && result <= max; - })); - }); - - it('should support not providing a `max`', function() { - var min = 0, - max = 5; - - assert.ok(lodashStable.some(array, function() { - var result = random(max); - return result >= min && result <= max; - })); - }); - - it('should swap `min` and `max` when `min` > `max`', function() { - var min = 4, - max = 2, - expected = [2, 3, 4]; - - var actual = lodashStable.uniq(lodashStable.map(array, function() { - return random(min, max); - })).sort(); - - assert.deepStrictEqual(actual, expected); - }); - - it('should support large integer values', function() { - var min = Math.pow(2, 31), - max = Math.pow(2, 62); - - assert.ok(lodashStable.every(array, function() { - var result = random(min, max); - return result >= min && result <= max; - })); - - assert.ok(lodashStable.some(array, function() { - return random(MAX_INTEGER); - })); - }); - - it('should coerce arguments to finite numbers', function() { - var actual = [ - random(NaN, NaN), - random('1', '1'), - random(Infinity, Infinity) - ]; - - assert.deepStrictEqual(actual, [0, 1, MAX_INTEGER]); - }); - - it('should support floats', function() { - var min = 1.5, - max = 1.6, - actual = random(min, max); - - assert.ok(actual % 1); - assert.ok(actual >= min && actual <= max); - }); - - it('should support providing a `floating`', function() { - var actual = random(true); - assert.ok(actual % 1 && actual >= 0 && actual <= 1); - - actual = random(2, true); - assert.ok(actual % 1 && actual >= 0 && actual <= 2); - - actual = random(2, 4, true); - assert.ok(actual % 1 && actual >= 2 && actual <= 4); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [1, 2, 3], - expected = lodashStable.map(array, stubTrue), - randoms = lodashStable.map(array, random); - - var actual = lodashStable.map(randoms, function(result, index) { - return result >= 0 && result <= array[index] && (result % 1) == 0; - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/random.spec.ts b/test/random.spec.ts new file mode 100644 index 000000000..460314b45 --- /dev/null +++ b/test/random.spec.ts @@ -0,0 +1,101 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { MAX_INTEGER, stubTrue } from './utils'; +import random from '../src/random'; + +describe('random', () => { + const array = Array(1000); + + it('should return `0` or `1` when no arguments are given', () => { + const actual = lodashStable.uniq(lodashStable.map(array, () => random())).sort(); + + assert.deepStrictEqual(actual, [0, 1]); + }); + + it('should support a `min` and `max`', () => { + const min = 5, + max = 10; + + assert.ok( + lodashStable.some(array, () => { + const result = random(min, max); + return result >= min && result <= max; + }), + ); + }); + + it('should support not providing a `max`', () => { + const min = 0, + max = 5; + + assert.ok( + lodashStable.some(array, () => { + const result = random(max); + return result >= min && result <= max; + }), + ); + }); + + it('should swap `min` and `max` when `min` > `max`', () => { + const min = 4, + max = 2, + expected = [2, 3, 4]; + + const actual = lodashStable.uniq(lodashStable.map(array, () => random(min, max))).sort(); + + assert.deepStrictEqual(actual, expected); + }); + + it('should support large integer values', () => { + const min = 2 ** 31, + max = 2 ** 62; + + assert.ok( + lodashStable.every(array, () => { + const result = random(min, max); + return result >= min && result <= max; + }), + ); + + assert.ok(lodashStable.some(array, () => random(MAX_INTEGER))); + }); + + it('should coerce arguments to finite numbers', () => { + const actual = [random(NaN, NaN), random('1', '1'), random(Infinity, Infinity)]; + + assert.deepStrictEqual(actual, [0, 1, MAX_INTEGER]); + }); + + it('should support floats', () => { + const min = 1.5, + max = 1.6, + actual = random(min, max); + + assert.ok(actual % 1); + assert.ok(actual >= min && actual <= max); + }); + + it('should support providing a `floating`', () => { + let actual = random(true); + assert.ok(actual % 1 && actual >= 0 && actual <= 1); + + actual = random(2, true); + assert.ok(actual % 1 && actual >= 0 && actual <= 2); + + actual = random(2, 4, true); + assert.ok(actual % 1 && actual >= 2 && actual <= 4); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [1, 2, 3], + expected = lodashStable.map(array, stubTrue), + randoms = lodashStable.map(array, random); + + const actual = lodashStable.map( + randoms, + (result, index) => result >= 0 && result <= array[index] && result % 1 == 0, + ); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/range-methods.js b/test/range-methods.js deleted file mode 100644 index 7f011e9d0..000000000 --- a/test/range-methods.js +++ /dev/null @@ -1,82 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, falsey } from './utils.js'; - -describe('range methods', function() { - lodashStable.each(['range', 'rangeRight'], function(methodName) { - var func = _[methodName], - isRange = methodName == 'range'; - - function resolve(range) { - return isRange ? range : range.reverse(); - } - - it('`_.' + methodName + '` should infer the sign of `step` when only `end` is given', function() { - assert.deepStrictEqual(func(4), resolve([0, 1, 2, 3])); - assert.deepStrictEqual(func(-4), resolve([0, -1, -2, -3])); - }); - - it('`_.' + methodName + '` should infer the sign of `step` when only `start` and `end` are given', function() { - assert.deepStrictEqual(func(1, 5), resolve([1, 2, 3, 4])); - assert.deepStrictEqual(func(5, 1), resolve([5, 4, 3, 2])); - }); - - it('`_.' + methodName + '` should work with a `start`, `end`, and `step`', function() { - assert.deepStrictEqual(func(0, -4, -1), resolve([0, -1, -2, -3])); - assert.deepStrictEqual(func(5, 1, -1), resolve([5, 4, 3, 2])); - assert.deepStrictEqual(func(0, 20, 5), resolve([0, 5, 10, 15])); - }); - - it('`_.' + methodName + '` should support a `step` of `0`', function() { - assert.deepStrictEqual(func(1, 4, 0), [1, 1, 1]); - }); - - it('`_.' + methodName + '` should work with a `step` larger than `end`', function() { - assert.deepStrictEqual(func(1, 5, 20), [1]); - }); - - it('`_.' + methodName + '` should work with a negative `step`', function() { - assert.deepStrictEqual(func(0, -4, -1), resolve([0, -1, -2, -3])); - assert.deepStrictEqual(func(21, 10, -3), resolve([21, 18, 15, 12])); - }); - - it('`_.' + methodName + '` should support `start` of `-0`', function() { - var actual = func(-0, 1); - assert.strictEqual(1 / actual[0], -Infinity); - }); - - it('`_.' + methodName + '` should treat falsey `start` as `0`', function() { - lodashStable.each(falsey, function(value, index) { - if (index) { - assert.deepStrictEqual(func(value), []); - assert.deepStrictEqual(func(value, 1), [0]); - } else { - assert.deepStrictEqual(func(), []); - } - }); - }); - - it('`_.' + methodName + '` should coerce arguments to finite numbers', function() { - var actual = [ - func('1'), - func('0', 1), - func(0, 1, '1'), - func(NaN), - func(NaN, NaN) - ]; - - assert.deepStrictEqual(actual, [[0], [0], [0], [], []]); - }); - - it('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function() { - var array = [1, 2, 3], - object = { 'a': 1, 'b': 2, 'c': 3 }, - expected = lodashStable.map([[0], [0, 1], [0, 1, 2]], resolve); - - lodashStable.each([array, object], function(collection) { - var actual = lodashStable.map(collection, func); - assert.deepStrictEqual(actual, expected); - }); - }); - }); -}); diff --git a/test/range-methods.spec.ts b/test/range-methods.spec.ts new file mode 100644 index 000000000..3d85a5c9a --- /dev/null +++ b/test/range-methods.spec.ts @@ -0,0 +1,76 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, falsey } from './utils'; + +describe('range methods', () => { + lodashStable.each(['range', 'rangeRight'], (methodName) => { + const func = _[methodName], + isRange = methodName == 'range'; + + function resolve(range) { + return isRange ? range : range.reverse(); + } + + it(`\`_.${methodName}\` should infer the sign of \`step\` when only \`end\` is given`, () => { + assert.deepStrictEqual(func(4), resolve([0, 1, 2, 3])); + assert.deepStrictEqual(func(-4), resolve([0, -1, -2, -3])); + }); + + it(`\`_.${methodName}\` should infer the sign of \`step\` when only \`start\` and \`end\` are given`, () => { + assert.deepStrictEqual(func(1, 5), resolve([1, 2, 3, 4])); + assert.deepStrictEqual(func(5, 1), resolve([5, 4, 3, 2])); + }); + + it(`\`_.${methodName}\` should work with a \`start\`, \`end\`, and \`step\``, () => { + assert.deepStrictEqual(func(0, -4, -1), resolve([0, -1, -2, -3])); + assert.deepStrictEqual(func(5, 1, -1), resolve([5, 4, 3, 2])); + assert.deepStrictEqual(func(0, 20, 5), resolve([0, 5, 10, 15])); + }); + + it(`\`_.${methodName}\` should support a \`step\` of \`0\``, () => { + assert.deepStrictEqual(func(1, 4, 0), [1, 1, 1]); + }); + + it(`\`_.${methodName}\` should work with a \`step\` larger than \`end\``, () => { + assert.deepStrictEqual(func(1, 5, 20), [1]); + }); + + it(`\`_.${methodName}\` should work with a negative \`step\``, () => { + assert.deepStrictEqual(func(0, -4, -1), resolve([0, -1, -2, -3])); + assert.deepStrictEqual(func(21, 10, -3), resolve([21, 18, 15, 12])); + }); + + it(`\`_.${methodName}\` should support \`start\` of \`-0\``, () => { + const actual = func(-0, 1); + assert.strictEqual(1 / actual[0], -Infinity); + }); + + it(`\`_.${methodName}\` should treat falsey \`start\` as \`0\``, () => { + lodashStable.each(falsey, (value, index) => { + if (index) { + assert.deepStrictEqual(func(value), []); + assert.deepStrictEqual(func(value, 1), [0]); + } else { + assert.deepStrictEqual(func(), []); + } + }); + }); + + it(`\`_.${methodName}\` should coerce arguments to finite numbers`, () => { + const actual = [func('1'), func('0', 1), func(0, 1, '1'), func(NaN), func(NaN, NaN)]; + + assert.deepStrictEqual(actual, [[0], [0], [0], [], []]); + }); + + it(`\`_.${methodName}\` should work as an iteratee for methods like \`_.map\``, () => { + const array = [1, 2, 3], + object = { a: 1, b: 2, c: 3 }, + expected = lodashStable.map([[0], [0, 1], [0, 1, 2]], resolve); + + lodashStable.each([array, object], (collection) => { + const actual = lodashStable.map(collection, func); + assert.deepStrictEqual(actual, expected); + }); + }); + }); +}); diff --git a/test/rearg.js b/test/rearg.js deleted file mode 100644 index 1e76fdb51..000000000 --- a/test/rearg.js +++ /dev/null @@ -1,70 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, empties } from './utils.js'; -import rearg from '../rearg.js'; - -describe('rearg', function() { - function fn() { - return slice.call(arguments); - } - - it('should reorder arguments provided to `func`', function() { - var rearged = rearg(fn, [2, 0, 1]); - assert.deepStrictEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); - }); - - it('should work with repeated indexes', function() { - var rearged = rearg(fn, [1, 1, 1]); - assert.deepStrictEqual(rearged('c', 'a', 'b'), ['a', 'a', 'a']); - }); - - it('should use `undefined` for nonexistent indexes', function() { - var rearged = rearg(fn, [1, 4]); - assert.deepStrictEqual(rearged('b', 'a', 'c'), ['a', undefined, 'c']); - }); - - it('should use `undefined` for non-index values', function() { - var values = lodashStable.reject(empties, function(value) { - return (value === 0) || lodashStable.isArray(value); - }).concat(-1, 1.1); - - var expected = lodashStable.map(values, lodashStable.constant([undefined, 'b', 'c'])); - - var actual = lodashStable.map(values, function(value) { - var rearged = rearg(fn, [value]); - return rearged('a', 'b', 'c'); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should not rearrange arguments when no indexes are given', function() { - var rearged = rearg(fn); - assert.deepStrictEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); - - rearged = rearg(fn, [], []); - assert.deepStrictEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); - }); - - it('should accept multiple index arguments', function() { - var rearged = rearg(fn, 2, 0, 1); - assert.deepStrictEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); - }); - - it('should accept multiple arrays of indexes', function() { - var rearged = rearg(fn, [2], [0, 1]); - assert.deepStrictEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); - }); - - it('should work with fewer indexes than arguments', function() { - var rearged = rearg(fn, [1, 0]); - assert.deepStrictEqual(rearged('b', 'a', 'c'), ['a', 'b', 'c']); - }); - - it('should work on functions that have been rearged', function() { - var rearged1 = rearg(fn, 2, 1, 0), - rearged2 = rearg(rearged1, 1, 0, 2); - - assert.deepStrictEqual(rearged2('b', 'c', 'a'), ['a', 'b', 'c']); - }); -}); diff --git a/test/rearg.spec.ts b/test/rearg.spec.ts new file mode 100644 index 000000000..da14496a9 --- /dev/null +++ b/test/rearg.spec.ts @@ -0,0 +1,70 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, empties } from './utils'; +import rearg from '../src/rearg'; + +describe('rearg', () => { + function fn() { + return slice.call(arguments); + } + + it('should reorder arguments provided to `func`', () => { + const rearged = rearg(fn, [2, 0, 1]); + assert.deepStrictEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); + }); + + it('should work with repeated indexes', () => { + const rearged = rearg(fn, [1, 1, 1]); + assert.deepStrictEqual(rearged('c', 'a', 'b'), ['a', 'a', 'a']); + }); + + it('should use `undefined` for nonexistent indexes', () => { + const rearged = rearg(fn, [1, 4]); + assert.deepStrictEqual(rearged('b', 'a', 'c'), ['a', undefined, 'c']); + }); + + it('should use `undefined` for non-index values', () => { + const values = lodashStable + .reject(empties, (value) => value === 0 || lodashStable.isArray(value)) + .concat(-1, 1.1); + + const expected = lodashStable.map(values, lodashStable.constant([undefined, 'b', 'c'])); + + const actual = lodashStable.map(values, (value) => { + const rearged = rearg(fn, [value]); + return rearged('a', 'b', 'c'); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should not rearrange arguments when no indexes are given', () => { + let rearged = rearg(fn); + assert.deepStrictEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); + + rearged = rearg(fn, [], []); + assert.deepStrictEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); + }); + + it('should accept multiple index arguments', () => { + const rearged = rearg(fn, 2, 0, 1); + assert.deepStrictEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); + }); + + it('should accept multiple arrays of indexes', () => { + const rearged = rearg(fn, [2], [0, 1]); + assert.deepStrictEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); + }); + + it('should work with fewer indexes than arguments', () => { + const rearged = rearg(fn, [1, 0]); + assert.deepStrictEqual(rearged('b', 'a', 'c'), ['a', 'b', 'c']); + }); + + it('should work on functions that have been rearged', () => { + const rearged1 = rearg(fn, 2, 1, 0), + rearged2 = rearg(rearged1, 1, 0, 2); + + assert.deepStrictEqual(rearged2('b', 'c', 'a'), ['a', 'b', 'c']); + }); +}); diff --git a/test/reduce-methods.js b/test/reduce-methods.js deleted file mode 100644 index 34f4b34c3..000000000 --- a/test/reduce-methods.js +++ /dev/null @@ -1,68 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, empties, noop, add } from './utils.js'; - -describe('reduce methods', function() { - lodashStable.each(['reduce', 'reduceRight'], function(methodName) { - var func = _[methodName], - array = [1, 2, 3], - isReduce = methodName == 'reduce'; - - it('`_.' + methodName + '` should reduce a collection to a single value', function() { - var actual = func(['a', 'b', 'c'], function(accumulator, value) { - return accumulator + value; - }, ''); - - assert.strictEqual(actual, isReduce ? 'abc' : 'cba'); - }); - - it('`_.' + methodName + '` should support empty collections without an initial `accumulator` value', function() { - var actual = [], - expected = lodashStable.map(empties, noop); - - lodashStable.each(empties, function(value) { - try { - actual.push(func(value, noop)); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should support empty collections with an initial `accumulator` value', function() { - var expected = lodashStable.map(empties, lodashStable.constant('x')); - - var actual = lodashStable.map(empties, function(value) { - try { - return func(value, noop, 'x'); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should handle an initial `accumulator` value of `undefined`', function() { - var actual = func([], noop, undefined); - assert.strictEqual(actual, undefined); - }); - - it('`_.' + methodName + '` should return `undefined` for empty collections when no `accumulator` is given (test in IE > 9 and modern browsers)', function() { - var array = [], - object = { '0': 1, 'length': 0 }; - - if ('__proto__' in array) { - array.__proto__ = object; - assert.strictEqual(func(array, noop), undefined); - } - assert.strictEqual(func(object, noop), undefined); - }); - - it('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function() { - assert.strictEqual(_(array)[methodName](add), 6); - }); - - it('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function() { - assert.ok(_(array).chain()[methodName](add) instanceof _); - }); - }); -}); diff --git a/test/reduce-methods.spec.ts b/test/reduce-methods.spec.ts new file mode 100644 index 000000000..721eb2ba2 --- /dev/null +++ b/test/reduce-methods.spec.ts @@ -0,0 +1,66 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, empties, noop, add } from './utils'; + +describe('reduce methods', () => { + lodashStable.each(['reduce', 'reduceRight'], (methodName) => { + const func = _[methodName], + array = [1, 2, 3], + isReduce = methodName == 'reduce'; + + it(`\`_.${methodName}\` should reduce a collection to a single value`, () => { + const actual = func(['a', 'b', 'c'], (accumulator, value) => accumulator + value, ''); + + assert.strictEqual(actual, isReduce ? 'abc' : 'cba'); + }); + + it(`\`_.${methodName}\` should support empty collections without an initial \`accumulator\` value`, () => { + const actual = [], + expected = lodashStable.map(empties, noop); + + lodashStable.each(empties, (value) => { + try { + actual.push(func(value, noop)); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should support empty collections with an initial \`accumulator\` value`, () => { + const expected = lodashStable.map(empties, lodashStable.constant('x')); + + const actual = lodashStable.map(empties, (value) => { + try { + return func(value, noop, 'x'); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should handle an initial \`accumulator\` value of \`undefined\``, () => { + const actual = func([], noop, undefined); + assert.strictEqual(actual, undefined); + }); + + it(`\`_.${methodName}\` should return \`undefined\` for empty collections when no \`accumulator\` is given (test in IE > 9 and modern browsers)`, () => { + const array = [], + object = { '0': 1, length: 0 }; + + if ('__proto__' in array) { + array.__proto__ = object; + assert.strictEqual(func(array, noop), undefined); + } + assert.strictEqual(func(object, noop), undefined); + }); + + it(`\`_.${methodName}\` should return an unwrapped value when implicitly chaining`, () => { + assert.strictEqual(_(array)[methodName](add), 6); + }); + + it(`\`_.${methodName}\` should return a wrapped value when explicitly chaining`, () => { + assert.ok(_(array).chain()[methodName](add) instanceof _); + }); + }); +}); diff --git a/test/reduce.js b/test/reduce.js deleted file mode 100644 index bae164750..000000000 --- a/test/reduce.js +++ /dev/null @@ -1,57 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import reduce from '../reduce.js'; -import head from '../head.js'; -import keys from '../keys.js'; - -describe('reduce', function() { - var array = [1, 2, 3]; - - it('should use the first element of a collection as the default `accumulator`', function() { - assert.strictEqual(reduce(array), 1); - }); - - it('should provide correct `iteratee` arguments when iterating an array', function() { - var args; - - reduce(array, function() { - args || (args = slice.call(arguments)); - }, 0); - - assert.deepStrictEqual(args, [0, 1, 0, array]); - - args = undefined; - reduce(array, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [1, 2, 1, array]); - }); - - it('should provide correct `iteratee` arguments when iterating an object', function() { - var args, - object = { 'a': 1, 'b': 2 }, - firstKey = head(keys(object)); - - var expected = firstKey == 'a' - ? [0, 1, 'a', object] - : [0, 2, 'b', object]; - - reduce(object, function() { - args || (args = slice.call(arguments)); - }, 0); - - assert.deepStrictEqual(args, expected); - - args = undefined; - expected = firstKey == 'a' - ? [1, 2, 'b', object] - : [2, 1, 'a', object]; - - reduce(object, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, expected); - }); -}); diff --git a/test/reduce.spec.ts b/test/reduce.spec.ts new file mode 100644 index 000000000..332ebbb7f --- /dev/null +++ b/test/reduce.spec.ts @@ -0,0 +1,61 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import reduce from '../src/reduce'; +import head from '../src/head'; +import keys from '../src/keys'; + +describe('reduce', () => { + const array = [1, 2, 3]; + + it('should use the first element of a collection as the default `accumulator`', () => { + assert.strictEqual(reduce(array), 1); + }); + + it('should provide correct `iteratee` arguments when iterating an array', () => { + let args; + + reduce( + array, + function () { + args || (args = slice.call(arguments)); + }, + 0, + ); + + assert.deepStrictEqual(args, [0, 1, 0, array]); + + args = undefined; + reduce(array, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [1, 2, 1, array]); + }); + + it('should provide correct `iteratee` arguments when iterating an object', () => { + let args, + object = { a: 1, b: 2 }, + firstKey = head(keys(object)); + + let expected = firstKey == 'a' ? [0, 1, 'a', object] : [0, 2, 'b', object]; + + reduce( + object, + function () { + args || (args = slice.call(arguments)); + }, + 0, + ); + + assert.deepStrictEqual(args, expected); + + args = undefined; + expected = firstKey == 'a' ? [1, 2, 'b', object] : [2, 1, 'a', object]; + + reduce(object, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, expected); + }); +}); diff --git a/test/reduceRight.js b/test/reduceRight.js deleted file mode 100644 index ea2beae02..000000000 --- a/test/reduceRight.js +++ /dev/null @@ -1,56 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice } from './utils.js'; -import reduceRight from '../reduceRight.js'; - -describe('reduceRight', function() { - var array = [1, 2, 3]; - - it('should use the last element of a collection as the default `accumulator`', function() { - assert.strictEqual(reduceRight(array), 3); - }); - - it('should provide correct `iteratee` arguments when iterating an array', function() { - var args; - - reduceRight(array, function() { - args || (args = slice.call(arguments)); - }, 0); - - assert.deepStrictEqual(args, [0, 3, 2, array]); - - args = undefined; - reduceRight(array, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [3, 2, 1, array]); - }); - - it('should provide correct `iteratee` arguments when iterating an object', function() { - var args, - object = { 'a': 1, 'b': 2 }, - isFIFO = lodashStable.keys(object)[0] == 'a'; - - var expected = isFIFO - ? [0, 2, 'b', object] - : [0, 1, 'a', object]; - - reduceRight(object, function() { - args || (args = slice.call(arguments)); - }, 0); - - assert.deepStrictEqual(args, expected); - - args = undefined; - expected = isFIFO - ? [2, 1, 'a', object] - : [1, 2, 'b', object]; - - reduceRight(object, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, expected); - }); -}); diff --git a/test/reduceRight.spec.ts b/test/reduceRight.spec.ts new file mode 100644 index 000000000..38f83e3cd --- /dev/null +++ b/test/reduceRight.spec.ts @@ -0,0 +1,60 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice } from './utils'; +import reduceRight from '../src/reduceRight'; + +describe('reduceRight', () => { + const array = [1, 2, 3]; + + it('should use the last element of a collection as the default `accumulator`', () => { + assert.strictEqual(reduceRight(array), 3); + }); + + it('should provide correct `iteratee` arguments when iterating an array', () => { + let args; + + reduceRight( + array, + function () { + args || (args = slice.call(arguments)); + }, + 0, + ); + + assert.deepStrictEqual(args, [0, 3, 2, array]); + + args = undefined; + reduceRight(array, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [3, 2, 1, array]); + }); + + it('should provide correct `iteratee` arguments when iterating an object', () => { + let args, + object = { a: 1, b: 2 }, + isFIFO = lodashStable.keys(object)[0] == 'a'; + + let expected = isFIFO ? [0, 2, 'b', object] : [0, 1, 'a', object]; + + reduceRight( + object, + function () { + args || (args = slice.call(arguments)); + }, + 0, + ); + + assert.deepStrictEqual(args, expected); + + args = undefined; + expected = isFIFO ? [2, 1, 'a', object] : [1, 2, 'b', object]; + + reduceRight(object, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, expected); + }); +}); diff --git a/test/reject.spec.ts b/test/reject.spec.ts new file mode 100644 index 000000000..b1a9ee813 --- /dev/null +++ b/test/reject.spec.ts @@ -0,0 +1,11 @@ +import assert from 'node:assert'; +import { isEven } from './utils'; +import reject from '../src/reject'; + +describe('reject', () => { + const array = [1, 2, 3]; + + it('should return elements the `predicate` returns falsey for', () => { + assert.deepStrictEqual(reject(array, isEven), [1, 3]); + }); +}); diff --git a/test/reject.test.js b/test/reject.test.js deleted file mode 100644 index fcf305041..000000000 --- a/test/reject.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import assert from 'assert'; -import { isEven } from './utils.js'; -import reject from '../reject.js'; - -describe('reject', function() { - var array = [1, 2, 3]; - - it('should return elements the `predicate` returns falsey for', function() { - assert.deepStrictEqual(reject(array, isEven), [1, 3]); - }); -}); diff --git a/test/remove.js b/test/remove.js deleted file mode 100644 index 92b025151..000000000 --- a/test/remove.js +++ /dev/null @@ -1,80 +0,0 @@ -import assert from 'assert'; -import { isEven, slice } from './utils.js'; -import remove from '../remove.js'; - -describe('remove', function() { - it('should modify the array and return removed elements', function() { - var array = [1, 2, 3, 4], - actual = remove(array, isEven); - - assert.deepStrictEqual(array, [1, 3]); - assert.deepStrictEqual(actual, [2, 4]); - }); - - it('should provide correct `predicate` arguments', function() { - var argsList = [], - array = [1, 2, 3], - clone = array.slice(); - - remove(array, function(n, index) { - var args = slice.call(arguments); - args[2] = args[2].slice(); - argsList.push(args); - return isEven(index); - }); - - assert.deepStrictEqual(argsList, [[1, 0, clone], [2, 1, clone], [3, 2, clone]]); - }); - - it('should work with `_.matches` shorthands', function() { - var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; - remove(objects, { 'a': 1 }); - assert.deepStrictEqual(objects, [{ 'a': 0, 'b': 1 }]); - }); - - it('should work with `_.matchesProperty` shorthands', function() { - var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; - remove(objects, ['a', 1]); - assert.deepStrictEqual(objects, [{ 'a': 0, 'b': 1 }]); - }); - - it('should work with `_.property` shorthands', function() { - var objects = [{ 'a': 0 }, { 'a': 1 }]; - remove(objects, 'a'); - assert.deepStrictEqual(objects, [{ 'a': 0 }]); - }); - - it('should preserve holes in arrays', function() { - var array = [1, 2, 3, 4]; - delete array[1]; - delete array[3]; - - remove(array, function(n) { - return n === 1; - }); - - assert.ok(!('0' in array)); - assert.ok(!('2' in array)); - }); - - it('should treat holes as `undefined`', function() { - var array = [1, 2, 3]; - delete array[1]; - - remove(array, function(n) { - return n == null; - }); - - assert.deepStrictEqual(array, [1, 3]); - }); - - it('should not mutate the array until all elements to remove are determined', function() { - var array = [1, 2, 3]; - - remove(array, function(n, index) { - return isEven(index); - }); - - assert.deepStrictEqual(array, [2]); - }); -}); diff --git a/test/remove.spec.ts b/test/remove.spec.ts new file mode 100644 index 000000000..0c93a32db --- /dev/null +++ b/test/remove.spec.ts @@ -0,0 +1,84 @@ +import assert from 'node:assert'; +import { isEven, slice } from './utils'; +import remove from '../src/remove'; + +describe('remove', () => { + it('should modify the array and return removed elements', () => { + const array = [1, 2, 3, 4], + actual = remove(array, isEven); + + assert.deepStrictEqual(array, [1, 3]); + assert.deepStrictEqual(actual, [2, 4]); + }); + + it('should provide correct `predicate` arguments', () => { + const argsList = [], + array = [1, 2, 3], + clone = array.slice(); + + remove(array, function (n, index) { + const args = slice.call(arguments); + args[2] = args[2].slice(); + argsList.push(args); + return isEven(index); + }); + + assert.deepStrictEqual(argsList, [ + [1, 0, clone], + [2, 1, clone], + [3, 2, clone], + ]); + }); + + it('should work with `_.matches` shorthands', () => { + const objects = [ + { a: 0, b: 1 }, + { a: 1, b: 2 }, + ]; + remove(objects, { a: 1 }); + assert.deepStrictEqual(objects, [{ a: 0, b: 1 }]); + }); + + it('should work with `_.matchesProperty` shorthands', () => { + const objects = [ + { a: 0, b: 1 }, + { a: 1, b: 2 }, + ]; + remove(objects, ['a', 1]); + assert.deepStrictEqual(objects, [{ a: 0, b: 1 }]); + }); + + it('should work with `_.property` shorthands', () => { + const objects = [{ a: 0 }, { a: 1 }]; + remove(objects, 'a'); + assert.deepStrictEqual(objects, [{ a: 0 }]); + }); + + it('should preserve holes in arrays', () => { + const array = [1, 2, 3, 4]; + delete array[1]; + delete array[3]; + + remove(array, (n) => n === 1); + + assert.ok(!('0' in array)); + assert.ok(!('2' in array)); + }); + + it('should treat holes as `undefined`', () => { + const array = [1, 2, 3]; + delete array[1]; + + remove(array, (n) => n == null); + + assert.deepStrictEqual(array, [1, 3]); + }); + + it('should not mutate the array until all elements to remove are determined', () => { + const array = [1, 2, 3]; + + remove(array, (n, index) => isEven(index)); + + assert.deepStrictEqual(array, [2]); + }); +}); diff --git a/test/repeat.js b/test/repeat.js deleted file mode 100644 index caa4e2e60..000000000 --- a/test/repeat.js +++ /dev/null @@ -1,46 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubThree } from './utils.js'; -import repeat from '../repeat.js'; - -describe('repeat', function() { - var string = 'abc'; - - it('should repeat a string `n` times', function() { - assert.strictEqual(repeat('*', 3), '***'); - assert.strictEqual(repeat(string, 2), 'abcabc'); - }); - - it('should treat falsey `n` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? string : ''; - }); - - var actual = lodashStable.map(falsey, function(n, index) { - return index ? repeat(string, n) : repeat(string); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return an empty string if `n` is <= `0`', function() { - assert.strictEqual(repeat(string, 0), ''); - assert.strictEqual(repeat(string, -2), ''); - }); - - it('should coerce `n` to an integer', function() { - assert.strictEqual(repeat(string, '2'), 'abcabc'); - assert.strictEqual(repeat(string, 2.6), 'abcabc'); - assert.strictEqual(repeat('*', { 'valueOf': stubThree }), '***'); - }); - - it('should coerce `string` to a string', function() { - assert.strictEqual(repeat(Object(string), 2), 'abcabc'); - assert.strictEqual(repeat({ 'toString': lodashStable.constant('*') }, 3), '***'); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var actual = lodashStable.map(['a', 'b', 'c'], repeat); - assert.deepStrictEqual(actual, ['a', 'b', 'c']); - }); -}); diff --git a/test/repeat.spec.ts b/test/repeat.spec.ts new file mode 100644 index 000000000..5d6468f51 --- /dev/null +++ b/test/repeat.spec.ts @@ -0,0 +1,44 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubThree } from './utils'; +import repeat from '../src/repeat'; + +describe('repeat', () => { + const string = 'abc'; + + it('should repeat a string `n` times', () => { + assert.strictEqual(repeat('*', 3), '***'); + assert.strictEqual(repeat(string, 2), 'abcabc'); + }); + + it('should treat falsey `n` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, (value) => (value === undefined ? string : '')); + + const actual = lodashStable.map(falsey, (n, index) => + index ? repeat(string, n) : repeat(string), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return an empty string if `n` is <= `0`', () => { + assert.strictEqual(repeat(string, 0), ''); + assert.strictEqual(repeat(string, -2), ''); + }); + + it('should coerce `n` to an integer', () => { + assert.strictEqual(repeat(string, '2'), 'abcabc'); + assert.strictEqual(repeat(string, 2.6), 'abcabc'); + assert.strictEqual(repeat('*', { valueOf: stubThree }), '***'); + }); + + it('should coerce `string` to a string', () => { + assert.strictEqual(repeat(Object(string), 2), 'abcabc'); + assert.strictEqual(repeat({ toString: lodashStable.constant('*') }, 3), '***'); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const actual = lodashStable.map(['a', 'b', 'c'], repeat); + assert.deepStrictEqual(actual, ['a', 'b', 'c']); + }); +}); diff --git a/test/replace.spec.ts b/test/replace.spec.ts new file mode 100644 index 000000000..b8b64857b --- /dev/null +++ b/test/replace.spec.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert'; +import replace from '../src/replace'; + +describe('replace', () => { + it('should replace the matched pattern', () => { + const string = 'abcde'; + assert.strictEqual(replace(string, 'de', '123'), 'abc123'); + assert.strictEqual(replace(string, /[bd]/g, '-'), 'a-c-e'); + }); +}); diff --git a/test/replace.test.js b/test/replace.test.js deleted file mode 100644 index f28a9f03c..000000000 --- a/test/replace.test.js +++ /dev/null @@ -1,10 +0,0 @@ -import assert from 'assert'; -import replace from '../replace.js'; - -describe('replace', function() { - it('should replace the matched pattern', function() { - var string = 'abcde'; - assert.strictEqual(replace(string, 'de', '123'), 'abc123'); - assert.strictEqual(replace(string, /[bd]/g, '-'), 'a-c-e'); - }); -}); diff --git a/test/rest.js b/test/rest.js deleted file mode 100644 index d7b98de46..000000000 --- a/test/rest.js +++ /dev/null @@ -1,49 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, _ } from './utils.js'; - -describe('rest', function() { - function fn(a, b, c) { - return slice.call(arguments); - } - - it('should apply a rest parameter to `func`', function() { - var rest = _.rest(fn); - assert.deepStrictEqual(rest(1, 2, 3, 4), [1, 2, [3, 4]]); - }); - - it('should work with `start`', function() { - var rest = _.rest(fn, 1); - assert.deepStrictEqual(rest(1, 2, 3, 4), [1, [2, 3, 4]]); - }); - - it('should treat `start` as `0` for `NaN` or negative values', function() { - var values = [-1, NaN, 'a'], - expected = lodashStable.map(values, lodashStable.constant([[1, 2, 3, 4]])); - - var actual = lodashStable.map(values, function(value) { - var rest = _.rest(fn, value); - return rest(1, 2, 3, 4); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should coerce `start` to an integer', function() { - var rest = _.rest(fn, 1.6); - assert.deepStrictEqual(rest(1, 2, 3), [1, [2, 3]]); - }); - - it('should use an empty array when `start` is not reached', function() { - var rest = _.rest(fn); - assert.deepStrictEqual(rest(1), [1, undefined, []]); - }); - - it('should work on functions with more than three parameters', function() { - var rest = _.rest(function(a, b, c, d) { - return slice.call(arguments); - }); - - assert.deepStrictEqual(rest(1, 2, 3, 4, 5), [1, 2, 3, [4, 5]]); - }); -}); diff --git a/test/rest.spec.ts b/test/rest.spec.ts new file mode 100644 index 000000000..2fbb14e83 --- /dev/null +++ b/test/rest.spec.ts @@ -0,0 +1,49 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, _ } from './utils'; + +describe('rest', () => { + function fn(a, b, c) { + return slice.call(arguments); + } + + it('should apply a rest parameter to `func`', () => { + const rest = _.rest(fn); + assert.deepStrictEqual(rest(1, 2, 3, 4), [1, 2, [3, 4]]); + }); + + it('should work with `start`', () => { + const rest = _.rest(fn, 1); + assert.deepStrictEqual(rest(1, 2, 3, 4), [1, [2, 3, 4]]); + }); + + it('should treat `start` as `0` for `NaN` or negative values', () => { + const values = [-1, NaN, 'a'], + expected = lodashStable.map(values, lodashStable.constant([[1, 2, 3, 4]])); + + const actual = lodashStable.map(values, (value) => { + const rest = _.rest(fn, value); + return rest(1, 2, 3, 4); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should coerce `start` to an integer', () => { + const rest = _.rest(fn, 1.6); + assert.deepStrictEqual(rest(1, 2, 3), [1, [2, 3]]); + }); + + it('should use an empty array when `start` is not reached', () => { + const rest = _.rest(fn); + assert.deepStrictEqual(rest(1), [1, undefined, []]); + }); + + it('should work on functions with more than three parameters', () => { + const rest = _.rest(function (a, b, c, d) { + return slice.call(arguments); + }); + + assert.deepStrictEqual(rest(1, 2, 3, 4, 5), [1, 2, 3, [4, 5]]); + }); +}); diff --git a/test/result.spec.ts b/test/result.spec.ts new file mode 100644 index 000000000..63074a56a --- /dev/null +++ b/test/result.spec.ts @@ -0,0 +1,40 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubB } from './utils'; +import result from '../src/result'; + +describe('result', () => { + const object = { a: 1, b: stubB }; + + it('should invoke function values', () => { + assert.strictEqual(result(object, 'b'), 'b'); + }); + + it('should invoke default function values', () => { + const actual = result(object, 'c', object.b); + assert.strictEqual(actual, 'b'); + }); + + it('should invoke nested function values', () => { + const value = { a: lodashStable.constant({ b: stubB }) }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.strictEqual(result(value, path), 'b'); + }); + }); + + it('should invoke deep property methods with the correct `this` binding', () => { + const value = { + a: { + b: function () { + return this.c; + }, + c: 1, + }, + }; + + lodashStable.each(['a.b', ['a', 'b']], (path) => { + assert.strictEqual(result(value, path), 1); + }); + }); +}); diff --git a/test/result.test.js b/test/result.test.js deleted file mode 100644 index 3087ac0c6..000000000 --- a/test/result.test.js +++ /dev/null @@ -1,33 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubB } from './utils.js'; -import result from '../result.js'; - -describe('result', function() { - var object = { 'a': 1, 'b': stubB }; - - it('should invoke function values', function() { - assert.strictEqual(result(object, 'b'), 'b'); - }); - - it('should invoke default function values', function() { - var actual = result(object, 'c', object.b); - assert.strictEqual(actual, 'b'); - }); - - it('should invoke nested function values', function() { - var value = { 'a': lodashStable.constant({ 'b': stubB }) }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.strictEqual(result(value, path), 'b'); - }); - }); - - it('should invoke deep property methods with the correct `this` binding', function() { - var value = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; - - lodashStable.each(['a.b', ['a', 'b']], function(path) { - assert.strictEqual(result(value, path), 1); - }); - }); -}); diff --git a/test/reverse.js b/test/reverse.js deleted file mode 100644 index f6c80ca59..000000000 --- a/test/reverse.js +++ /dev/null @@ -1,94 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE, identity } from './utils.js'; -import reverse from '../reverse.js'; -import compact from '../compact.js'; -import head from '../head.js'; - -describe('reverse', function() { - var largeArray = lodashStable.range(LARGE_ARRAY_SIZE).concat(null), - smallArray = [0, 1, 2, null]; - - it('should reverse `array`', function() { - var array = [1, 2, 3], - actual = reverse(array); - - assert.strictEqual(actual, array); - assert.deepStrictEqual(array, [3, 2, 1]); - }); - - it('should return the wrapped reversed `array`', function() { - lodashStable.times(2, function(index) { - var array = (index ? largeArray : smallArray).slice(), - clone = array.slice(), - wrapped = _(array).reverse(), - actual = wrapped.value(); - - assert.ok(wrapped instanceof _); - assert.strictEqual(actual, array); - assert.deepStrictEqual(actual, clone.slice().reverse()); - }); - }); - - it('should work in a lazy sequence', function() { - lodashStable.times(2, function(index) { - var array = (index ? largeArray : smallArray).slice(), - expected = array.slice(), - actual = _(array).slice(1).reverse().value(); - - assert.deepStrictEqual(actual, expected.slice(1).reverse()); - assert.deepStrictEqual(array, expected); - }); - }); - - it('should be lazy when in a lazy sequence', function() { - var spy = { - 'toString': function() { - throw new Error('spy was revealed'); - } - }; - - var array = largeArray.concat(spy), - expected = array.slice(); - - try { - var wrapped = _(array).slice(1).map(String).reverse(), - actual = wrapped.last(); - } catch (e) {} - - assert.ok(wrapped instanceof _); - assert.strictEqual(actual, '1'); - assert.deepEqual(array, expected); - }); - - it('should work in a hybrid sequence', function() { - lodashStable.times(2, function(index) { - var clone = (index ? largeArray : smallArray).slice(); - - lodashStable.each(['map', 'filter'], function(methodName) { - var array = clone.slice(), - expected = clone.slice(1, -1).reverse(), - actual = _(array)[methodName](identity).thru(compact).reverse().value(); - - assert.deepStrictEqual(actual, expected); - - array = clone.slice(); - actual = _(array).thru(compact)[methodName](identity).pull(1).push(3).reverse().value(); - - assert.deepStrictEqual(actual, [3].concat(expected.slice(0, -1))); - }); - }); - }); - - it('should track the `__chain__` value of a wrapper', function() { - lodashStable.times(2, function(index) { - var array = (index ? largeArray : smallArray).slice(), - expected = array.slice().reverse(), - wrapped = _(array).chain().reverse().head(); - - assert.ok(wrapped instanceof _); - assert.strictEqual(wrapped.value(), head(expected)); - assert.deepStrictEqual(array, expected); - }); - }); -}); diff --git a/test/reverse.spec.ts b/test/reverse.spec.ts new file mode 100644 index 000000000..da425d44f --- /dev/null +++ b/test/reverse.spec.ts @@ -0,0 +1,100 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE, identity } from './utils'; +import reverse from '../src/reverse'; +import compact from '../src/compact'; +import head from '../src/head'; + +describe('reverse', () => { + const largeArray = lodashStable.range(LARGE_ARRAY_SIZE).concat(null), + smallArray = [0, 1, 2, null]; + + it('should reverse `array`', () => { + const array = [1, 2, 3], + actual = reverse(array); + + assert.strictEqual(actual, array); + assert.deepStrictEqual(array, [3, 2, 1]); + }); + + it('should return the wrapped reversed `array`', () => { + lodashStable.times(2, (index) => { + const array = (index ? largeArray : smallArray).slice(), + clone = array.slice(), + wrapped = _(array).reverse(), + actual = wrapped.value(); + + assert.ok(wrapped instanceof _); + assert.strictEqual(actual, array); + assert.deepStrictEqual(actual, clone.slice().reverse()); + }); + }); + + it('should work in a lazy sequence', () => { + lodashStable.times(2, (index) => { + const array = (index ? largeArray : smallArray).slice(), + expected = array.slice(), + actual = _(array).slice(1).reverse().value(); + + assert.deepStrictEqual(actual, expected.slice(1).reverse()); + assert.deepStrictEqual(array, expected); + }); + }); + + it('should be lazy when in a lazy sequence', () => { + const spy = { + toString: function () { + throw new Error('spy was revealed'); + }, + }; + + const array = largeArray.concat(spy), + expected = array.slice(); + + try { + var wrapped = _(array).slice(1).map(String).reverse(), + actual = wrapped.last(); + } catch (e) {} + + assert.ok(wrapped instanceof _); + assert.strictEqual(actual, '1'); + assert.deepEqual(array, expected); + }); + + it('should work in a hybrid sequence', () => { + lodashStable.times(2, (index) => { + const clone = (index ? largeArray : smallArray).slice(); + + lodashStable.each(['map', 'filter'], (methodName) => { + let array = clone.slice(), + expected = clone.slice(1, -1).reverse(), + actual = _(array)[methodName](identity).thru(compact).reverse().value(); + + assert.deepStrictEqual(actual, expected); + + array = clone.slice(); + actual = _(array) + .thru(compact) + [methodName](identity) + .pull(1) + .push(3) + .reverse() + .value(); + + assert.deepStrictEqual(actual, [3].concat(expected.slice(0, -1))); + }); + }); + }); + + it('should track the `__chain__` value of a wrapper', () => { + lodashStable.times(2, (index) => { + const array = (index ? largeArray : smallArray).slice(), + expected = array.slice().reverse(), + wrapped = _(array).chain().reverse().head(); + + assert.ok(wrapped instanceof _); + assert.strictEqual(wrapped.value(), head(expected)); + assert.deepStrictEqual(array, expected); + }); + }); +}); diff --git a/test/round-methods.js b/test/round-methods.js deleted file mode 100644 index be0a92498..000000000 --- a/test/round-methods.js +++ /dev/null @@ -1,82 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, MAX_SAFE_INTEGER, stubFalse } from './utils.js'; -import round from '../round.js'; - -describe('round methods', function() { - lodashStable.each(['ceil', 'floor', 'round'], function(methodName) { - var func = _[methodName], - isCeil = methodName == 'ceil', - isFloor = methodName == 'floor'; - - it('`_.' + methodName + '` should return a rounded number without a precision', function() { - var actual = func(4.006); - assert.strictEqual(actual, isCeil ? 5 : 4); - }); - - it('`_.' + methodName + '` should work with a precision of `0`', function() { - var actual = func(4.006, 0); - assert.strictEqual(actual, isCeil ? 5 : 4); - }); - - it('`_.' + methodName + '` should work with a positive precision', function() { - var actual = func(4.016, 2); - assert.strictEqual(actual, isFloor ? 4.01 : 4.02); - - actual = func(4.1, 2); - assert.strictEqual(actual, 4.1); - }); - - it('`_.' + methodName + '` should work with a negative precision', function() { - var actual = func(4160, -2); - assert.strictEqual(actual, isFloor ? 4100 : 4200); - }); - - it('`_.' + methodName + '` should coerce `precision` to an integer', function() { - var actual = func(4.006, NaN); - assert.strictEqual(actual, isCeil ? 5 : 4); - - var expected = isFloor ? 4.01 : 4.02; - - actual = func(4.016, 2.6); - assert.strictEqual(actual, expected); - - actual = func(4.016, '+2'); - assert.strictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with exponential notation and `precision`', function() { - var actual = func(5e1, 2); - assert.deepStrictEqual(actual, 50); - - actual = func('5e', 1); - assert.deepStrictEqual(actual, NaN); - - actual = func('5e1e1', 1); - assert.deepStrictEqual(actual, NaN); - }); - - it('`_.' + methodName + '` should preserve the sign of `0`', function() { - var values = [[0], [-0], ['0'], ['-0'], [0, 1], [-0, 1], ['0', 1], ['-0', 1]], - expected = [Infinity, -Infinity, Infinity, -Infinity, Infinity, -Infinity, Infinity, -Infinity]; - - var actual = lodashStable.map(values, function(args) { - return 1 / func.apply(undefined, args); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should not return `NaN` for large `precision` values', function() { - var results = [ - round(10.0000001, 1000), - round(MAX_SAFE_INTEGER, 293) - ]; - - var expected = lodashStable.map(results, stubFalse), - actual = lodashStable.map(results, lodashStable.isNaN); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/round-methods.spec.ts b/test/round-methods.spec.ts new file mode 100644 index 000000000..d76d1d928 --- /dev/null +++ b/test/round-methods.spec.ts @@ -0,0 +1,86 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, MAX_SAFE_INTEGER, stubFalse } from './utils'; +import round from '../src/round'; + +describe('round methods', () => { + lodashStable.each(['ceil', 'floor', 'round'], (methodName) => { + const func = _[methodName], + isCeil = methodName == 'ceil', + isFloor = methodName == 'floor'; + + it(`\`_.${methodName}\` should return a rounded number without a precision`, () => { + const actual = func(4.006); + assert.strictEqual(actual, isCeil ? 5 : 4); + }); + + it(`\`_.${methodName}\` should work with a precision of \`0\``, () => { + const actual = func(4.006, 0); + assert.strictEqual(actual, isCeil ? 5 : 4); + }); + + it(`\`_.${methodName}\` should work with a positive precision`, () => { + let actual = func(4.016, 2); + assert.strictEqual(actual, isFloor ? 4.01 : 4.02); + + actual = func(4.1, 2); + assert.strictEqual(actual, 4.1); + }); + + it(`\`_.${methodName}\` should work with a negative precision`, () => { + const actual = func(4160, -2); + assert.strictEqual(actual, isFloor ? 4100 : 4200); + }); + + it(`\`_.${methodName}\` should coerce \`precision\` to an integer`, () => { + let actual = func(4.006, NaN); + assert.strictEqual(actual, isCeil ? 5 : 4); + + const expected = isFloor ? 4.01 : 4.02; + + actual = func(4.016, 2.6); + assert.strictEqual(actual, expected); + + actual = func(4.016, '+2'); + assert.strictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with exponential notation and \`precision\``, () => { + let actual = func(5e1, 2); + assert.deepStrictEqual(actual, 50); + + actual = func('5e', 1); + assert.deepStrictEqual(actual, NaN); + + actual = func('5e1e1', 1); + assert.deepStrictEqual(actual, NaN); + }); + + it(`\`_.${methodName}\` should preserve the sign of \`0\``, () => { + const values = [[0], [-0], ['0'], ['-0'], [0, 1], [-0, 1], ['0', 1], ['-0', 1]], + expected = [ + Infinity, + -Infinity, + Infinity, + -Infinity, + Infinity, + -Infinity, + Infinity, + -Infinity, + ]; + + const actual = lodashStable.map(values, (args) => 1 / func.apply(undefined, args)); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should not return \`NaN\` for large \`precision\` values`, () => { + const results = [round(10.0000001, 1000), round(MAX_SAFE_INTEGER, 293)]; + + const expected = lodashStable.map(results, stubFalse), + actual = lodashStable.map(results, lodashStable.isNaN); + + assert.deepStrictEqual(actual, expected); + }); + }); +}); diff --git a/test/runInContext.js b/test/runInContext.js deleted file mode 100644 index 402ddac66..000000000 --- a/test/runInContext.js +++ /dev/null @@ -1,29 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import runInContext from '../runInContext.js'; -import uniqueId from '../uniqueId.js'; - -describe('runInContext', function() { - it('should not require a fully populated `context` object', function() { - var lodash = runInContext({ - 'setTimeout': function(func) { func(); } - }); - - var pass = false; - lodash.delay(function() { pass = true; }, 32); - assert.ok(pass); - }); - - it('should use a zeroed `_.uniqueId` counter', function() { - lodashStable.times(2, uniqueId); - - var oldId = Number(uniqueId()), - lodash = runInContext(); - - assert.ok(uniqueId() > oldId); - - var id = lodash.uniqueId(); - assert.strictEqual(id, '1'); - assert.ok(id < oldId); - }); -}); diff --git a/test/runInContext.spec.ts b/test/runInContext.spec.ts new file mode 100644 index 000000000..64a765167 --- /dev/null +++ b/test/runInContext.spec.ts @@ -0,0 +1,33 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import runInContext from '../src/runInContext'; +import uniqueId from '../src/uniqueId'; + +describe('runInContext', () => { + it('should not require a fully populated `context` object', () => { + const lodash = runInContext({ + setTimeout: function (func) { + func(); + }, + }); + + let pass = false; + lodash.delay(() => { + pass = true; + }, 32); + assert.ok(pass); + }); + + it('should use a zeroed `_.uniqueId` counter', () => { + lodashStable.times(2, uniqueId); + + const oldId = Number(uniqueId()), + lodash = runInContext(); + + assert.ok(uniqueId() > oldId); + + const id = lodash.uniqueId(); + assert.strictEqual(id, '1'); + assert.ok(id < oldId); + }); +}); diff --git a/test/sample.js b/test/sample.js deleted file mode 100644 index b29634a42..000000000 --- a/test/sample.js +++ /dev/null @@ -1,32 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { empties, noop } from './utils.js'; -import sample from '../sample.js'; - -describe('sample', function() { - var array = [1, 2, 3]; - - it('should return a random element', function() { - var actual = sample(array); - assert.ok(lodashStable.includes(array, actual)); - }); - - it('should return `undefined` when sampling empty collections', function() { - var expected = lodashStable.map(empties, noop); - - var actual = lodashStable.transform(empties, function(result, value) { - try { - result.push(sample(value)); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should sample an object', function() { - var object = { 'a': 1, 'b': 2, 'c': 3 }, - actual = sample(object); - - assert.ok(lodashStable.includes(array, actual)); - }); -}); diff --git a/test/sample.spec.ts b/test/sample.spec.ts new file mode 100644 index 000000000..e58e02b95 --- /dev/null +++ b/test/sample.spec.ts @@ -0,0 +1,32 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { empties, noop } from './utils'; +import sample from '../src/sample'; + +describe('sample', () => { + const array = [1, 2, 3]; + + it('should return a random element', () => { + const actual = sample(array); + assert.ok(lodashStable.includes(array, actual)); + }); + + it('should return `undefined` when sampling empty collections', () => { + const expected = lodashStable.map(empties, noop); + + const actual = lodashStable.transform(empties, (result, value) => { + try { + result.push(sample(value)); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should sample an object', () => { + const object = { a: 1, b: 2, c: 3 }, + actual = sample(object); + + assert.ok(lodashStable.includes(array, actual)); + }); +}); diff --git a/test/sampleSize.js b/test/sampleSize.js deleted file mode 100644 index e394c00c5..000000000 --- a/test/sampleSize.js +++ /dev/null @@ -1,76 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, empties, stubArray } from './utils.js'; -import sampleSize from '../sampleSize.js'; - -describe('sampleSize', function() { - var array = [1, 2, 3]; - - it('should return an array of random elements', function() { - var actual = sampleSize(array, 2); - - assert.strictEqual(actual.length, 2); - assert.deepStrictEqual(lodashStable.difference(actual, array), []); - }); - - it('should contain elements of the collection', function() { - var actual = sampleSize(array, array.length).sort(); - - assert.deepStrictEqual(actual, array); - }); - - it('should treat falsey `size` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? ['a'] : []; - }); - - var actual = lodashStable.map(falsey, function(size, index) { - return index ? sampleSize(['a'], size) : sampleSize(['a']); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return an empty array when `n` < `1` or `NaN`', function() { - lodashStable.each([0, -1, -Infinity], function(n) { - assert.deepStrictEqual(sampleSize(array, n), []); - }); - }); - - it('should return all elements when `n` >= `length`', function() { - lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - var actual = sampleSize(array, n).sort(); - assert.deepStrictEqual(actual, array); - }); - }); - - it('should coerce `n` to an integer', function() { - var actual = sampleSize(array, 1.6); - assert.strictEqual(actual.length, 1); - }); - - it('should return an empty array for empty collections', function() { - var expected = lodashStable.map(empties, stubArray); - - var actual = lodashStable.transform(empties, function(result, value) { - try { - result.push(sampleSize(value, 1)); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should sample an object', function() { - var object = { 'a': 1, 'b': 2, 'c': 3 }, - actual = sampleSize(object, 2); - - assert.strictEqual(actual.length, 2); - assert.deepStrictEqual(lodashStable.difference(actual, lodashStable.values(object)), []); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var actual = lodashStable.map([['a']], sampleSize); - assert.deepStrictEqual(actual, [['a']]); - }); -}); diff --git a/test/sampleSize.spec.ts b/test/sampleSize.spec.ts new file mode 100644 index 000000000..d80da5f0c --- /dev/null +++ b/test/sampleSize.spec.ts @@ -0,0 +1,74 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, empties, stubArray } from './utils'; +import sampleSize from '../src/sampleSize'; + +describe('sampleSize', () => { + const array = [1, 2, 3]; + + it('should return an array of random elements', () => { + const actual = sampleSize(array, 2); + + assert.strictEqual(actual.length, 2); + assert.deepStrictEqual(lodashStable.difference(actual, array), []); + }); + + it('should contain elements of the collection', () => { + const actual = sampleSize(array, array.length).sort(); + + assert.deepStrictEqual(actual, array); + }); + + it('should treat falsey `size` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, (value) => (value === undefined ? ['a'] : [])); + + const actual = lodashStable.map(falsey, (size, index) => + index ? sampleSize(['a'], size) : sampleSize(['a']), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return an empty array when `n` < `1` or `NaN`', () => { + lodashStable.each([0, -1, -Infinity], (n) => { + assert.deepStrictEqual(sampleSize(array, n), []); + }); + }); + + it('should return all elements when `n` >= `length`', () => { + lodashStable.each([3, 4, 2 ** 32, Infinity], (n) => { + const actual = sampleSize(array, n).sort(); + assert.deepStrictEqual(actual, array); + }); + }); + + it('should coerce `n` to an integer', () => { + const actual = sampleSize(array, 1.6); + assert.strictEqual(actual.length, 1); + }); + + it('should return an empty array for empty collections', () => { + const expected = lodashStable.map(empties, stubArray); + + const actual = lodashStable.transform(empties, (result, value) => { + try { + result.push(sampleSize(value, 1)); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should sample an object', () => { + const object = { a: 1, b: 2, c: 3 }, + actual = sampleSize(object, 2); + + assert.strictEqual(actual.length, 2); + assert.deepStrictEqual(lodashStable.difference(actual, lodashStable.values(object)), []); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const actual = lodashStable.map([['a']], sampleSize); + assert.deepStrictEqual(actual, [['a']]); + }); +}); diff --git a/test/set-methods.js b/test/set-methods.js deleted file mode 100644 index c7c69a349..000000000 --- a/test/set-methods.js +++ /dev/null @@ -1,172 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, symbol, defineProperty } from './utils.js'; -import unset from '../unset.js'; - -describe('set methods', function() { - lodashStable.each(['update', 'updateWith', 'set', 'setWith'], function(methodName) { - var func = _[methodName], - isUpdate = /^update/.test(methodName); - - var oldValue = 1, - value = 2, - updater = isUpdate ? lodashStable.constant(value) : value; - - it('`_.' + methodName + '` should set property values', function() { - lodashStable.each(['a', ['a']], function(path) { - var object = { 'a': oldValue }, - actual = func(object, path, updater); - - assert.strictEqual(actual, object); - assert.strictEqual(object.a, value); - }); - }); - - it('`_.' + methodName + '` should preserve the sign of `0`', function() { - var props = [-0, Object(-0), 0, Object(0)], - expected = lodashStable.map(props, lodashStable.constant(value)); - - var actual = lodashStable.map(props, function(key) { - var object = { '-0': 'a', '0': 'b' }; - func(object, key, updater); - return object[lodashStable.toString(key)]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should unset symbol keyed property values', function() { - if (Symbol) { - var object = {}; - object[symbol] = 1; - - assert.strictEqual(unset(object, symbol), true); - assert.ok(!(symbol in object)); - } - }); - - it('`_.' + methodName + '` should set deep property values', function() { - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var object = { 'a': { 'b': oldValue } }, - actual = func(object, path, updater); - - assert.strictEqual(actual, object); - assert.strictEqual(object.a.b, value); - }); - }); - - it('`_.' + methodName + '` should set a key over a path', function() { - lodashStable.each(['a.b', ['a.b']], function(path) { - var object = { 'a.b': oldValue }, - actual = func(object, path, updater); - - assert.strictEqual(actual, object); - assert.deepStrictEqual(object, { 'a.b': value }); - }); - }); - - it('`_.' + methodName + '` should not coerce array paths to strings', function() { - var object = { 'a,b,c': 1, 'a': { 'b': { 'c': 1 } } }; - - func(object, ['a', 'b', 'c'], updater); - assert.strictEqual(object.a.b.c, value); - }); - - it('`_.' + methodName + '` should not ignore empty brackets', function() { - var object = {}; - - func(object, 'a[]', updater); - assert.deepStrictEqual(object, { 'a': { '': value } }); - }); - - it('`_.' + methodName + '` should handle empty paths', function() { - lodashStable.each([['', ''], [[], ['']]], function(pair, index) { - var object = {}; - - func(object, pair[0], updater); - assert.deepStrictEqual(object, index ? {} : { '': value }); - - func(object, pair[1], updater); - assert.deepStrictEqual(object, { '': value }); - }); - }); - - it('`_.' + methodName + '` should handle complex paths', function() { - var object = { 'a': { '1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': oldValue } } } } } } } }; - - var paths = [ - 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', - ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'] - ]; - - lodashStable.each(paths, function(path) { - func(object, path, updater); - assert.strictEqual(object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f.g, value); - object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f.g = oldValue; - }); - }); - - it('`_.' + methodName + '` should create parts of `path` that are missing', function() { - var object = {}; - - lodashStable.each(['a[1].b.c', ['a', '1', 'b', 'c']], function(path) { - var actual = func(object, path, updater); - - assert.strictEqual(actual, object); - assert.deepStrictEqual(actual, { 'a': [undefined, { 'b': { 'c': value } }] }); - assert.ok(!('0' in object.a)); - - delete object.a; - }); - }); - - it('`_.' + methodName + '` should not error when `object` is nullish', function() { - var values = [null, undefined], - expected = [[null, null], [undefined, undefined]]; - - var actual = lodashStable.map(values, function(value) { - try { - return [func(value, 'a.b', updater), func(value, ['a', 'b'], updater)]; - } catch (e) { - return e.message; - } - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should overwrite primitives in the path', function() { - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var object = { 'a': '' }; - - func(object, path, updater); - assert.deepStrictEqual(object, { 'a': { 'b': 2 } }); - }); - }); - - it('`_.' + methodName + '` should not create an array for missing non-index property names that start with numbers', function() { - var object = {}; - - func(object, ['1a', '2b', '3c'], updater); - assert.deepStrictEqual(object, { '1a': { '2b': { '3c': value } } }); - }); - - it('`_.' + methodName + '` should not assign values that are the same as their destinations', function() { - lodashStable.each(['a', ['a'], { 'a': 1 }, NaN], function(value) { - var object = {}, - pass = true, - updater = isUpdate ? lodashStable.constant(value) : value; - - defineProperty(object, 'a', { - 'configurable': true, - 'enumerable': true, - 'get': lodashStable.constant(value), - 'set': function() { pass = false; } - }); - - func(object, 'a', updater); - assert.ok(pass); - }); - }); - }); -}); diff --git a/test/set-methods.spec.ts b/test/set-methods.spec.ts new file mode 100644 index 000000000..f29c57d77 --- /dev/null +++ b/test/set-methods.spec.ts @@ -0,0 +1,185 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, symbol, defineProperty } from './utils'; +import unset from '../src/unset'; + +describe('set methods', () => { + lodashStable.each(['update', 'updateWith', 'set', 'setWith'], (methodName) => { + const func = _[methodName], + isUpdate = /^update/.test(methodName); + + const oldValue = 1, + value = 2, + updater = isUpdate ? lodashStable.constant(value) : value; + + it(`\`_.${methodName}\` should set property values`, () => { + lodashStable.each(['a', ['a']], (path) => { + const object = { a: oldValue }, + actual = func(object, path, updater); + + assert.strictEqual(actual, object); + assert.strictEqual(object.a, value); + }); + }); + + it(`\`_.${methodName}\` should preserve the sign of \`0\``, () => { + const props = [-0, Object(-0), 0, Object(0)], + expected = lodashStable.map(props, lodashStable.constant(value)); + + const actual = lodashStable.map(props, (key) => { + const object = { '-0': 'a', '0': 'b' }; + func(object, key, updater); + return object[lodashStable.toString(key)]; + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should unset symbol keyed property values`, () => { + if (Symbol) { + const object = {}; + object[symbol] = 1; + + assert.strictEqual(unset(object, symbol), true); + assert.ok(!(symbol in object)); + } + }); + + it(`\`_.${methodName}\` should set deep property values`, () => { + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const object = { a: { b: oldValue } }, + actual = func(object, path, updater); + + assert.strictEqual(actual, object); + assert.strictEqual(object.a.b, value); + }); + }); + + it(`\`_.${methodName}\` should set a key over a path`, () => { + lodashStable.each(['a.b', ['a.b']], (path) => { + const object = { 'a.b': oldValue }, + actual = func(object, path, updater); + + assert.strictEqual(actual, object); + assert.deepStrictEqual(object, { 'a.b': value }); + }); + }); + + it(`\`_.${methodName}\` should not coerce array paths to strings`, () => { + const object = { 'a,b,c': 1, a: { b: { c: 1 } } }; + + func(object, ['a', 'b', 'c'], updater); + assert.strictEqual(object.a.b.c, value); + }); + + it(`\`_.${methodName}\` should not ignore empty brackets`, () => { + const object = {}; + + func(object, 'a[]', updater); + assert.deepStrictEqual(object, { a: { '': value } }); + }); + + it(`\`_.${methodName}\` should handle empty paths`, () => { + lodashStable.each( + [ + ['', ''], + [[], ['']], + ], + (pair, index) => { + const object = {}; + + func(object, pair[0], updater); + assert.deepStrictEqual(object, index ? {} : { '': value }); + + func(object, pair[1], updater); + assert.deepStrictEqual(object, { '': value }); + }, + ); + }); + + it(`\`_.${methodName}\` should handle complex paths`, () => { + const object = { + a: { '1.23': { '["b"]': { c: { "['d']": { '\ne\n': { f: { g: oldValue } } } } } } }, + }; + + const paths = [ + 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', + ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'], + ]; + + lodashStable.each(paths, (path) => { + func(object, path, updater); + assert.strictEqual(object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f.g, value); + object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f.g = oldValue; + }); + }); + + it(`\`_.${methodName}\` should create parts of \`path\` that are missing`, () => { + const object = {}; + + lodashStable.each(['a[1].b.c', ['a', '1', 'b', 'c']], (path) => { + const actual = func(object, path, updater); + + assert.strictEqual(actual, object); + assert.deepStrictEqual(actual, { a: [undefined, { b: { c: value } }] }); + assert.ok(!('0' in object.a)); + + delete object.a; + }); + }); + + it(`\`_.${methodName}\` should not error when \`object\` is nullish`, () => { + const values = [null, undefined], + expected = [ + [null, null], + [undefined, undefined], + ]; + + const actual = lodashStable.map(values, (value) => { + try { + return [func(value, 'a.b', updater), func(value, ['a', 'b'], updater)]; + } catch (e) { + return e.message; + } + }); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should overwrite primitives in the path`, () => { + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const object = { a: '' }; + + func(object, path, updater); + assert.deepStrictEqual(object, { a: { b: 2 } }); + }); + }); + + it(`\`_.${methodName}\` should not create an array for missing non-index property names that start with numbers`, () => { + const object = {}; + + func(object, ['1a', '2b', '3c'], updater); + assert.deepStrictEqual(object, { '1a': { '2b': { '3c': value } } }); + }); + + it(`\`_.${methodName}\` should not assign values that are the same as their destinations`, () => { + lodashStable.each(['a', ['a'], { a: 1 }, NaN], (value) => { + let object = {}, + pass = true, + updater = isUpdate ? lodashStable.constant(value) : value; + + defineProperty(object, 'a', { + configurable: true, + enumerable: true, + get: lodashStable.constant(value), + set: function () { + pass = false; + }, + }); + + func(object, 'a', updater); + assert.ok(pass); + }); + }); + }); +}); diff --git a/test/setWith.js b/test/setWith.js deleted file mode 100644 index 87cc2a2a1..000000000 --- a/test/setWith.js +++ /dev/null @@ -1,19 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { noop } from './utils.js'; -import setWith from '../setWith.js'; - -describe('setWith', function() { - it('should work with a `customizer` callback', function() { - var actual = setWith({ '0': {} }, '[0][1][2]', 3, function(value) { - return lodashStable.isObject(value) ? undefined : {}; - }); - - assert.deepStrictEqual(actual, { '0': { '1': { '2': 3 } } }); - }); - - it('should work with a `customizer` that returns `undefined`', function() { - var actual = setWith({}, 'a[0].b.c', 4, noop); - assert.deepStrictEqual(actual, { 'a': [{ 'b': { 'c': 4 } }] }); - }); -}); diff --git a/test/setWith.spec.ts b/test/setWith.spec.ts new file mode 100644 index 000000000..6ad9400c9 --- /dev/null +++ b/test/setWith.spec.ts @@ -0,0 +1,19 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { noop } from './utils'; +import setWith from '../src/setWith'; + +describe('setWith', () => { + it('should work with a `customizer` callback', () => { + const actual = setWith({ '0': {} }, '[0][1][2]', 3, (value) => + lodashStable.isObject(value) ? undefined : {}, + ); + + assert.deepStrictEqual(actual, { '0': { '1': { '2': 3 } } }); + }); + + it('should work with a `customizer` that returns `undefined`', () => { + const actual = setWith({}, 'a[0].b.c', 4, noop); + assert.deepStrictEqual(actual, { a: [{ b: { c: 4 } }] }); + }); +}); diff --git a/test/shuffle.js b/test/shuffle.js deleted file mode 100644 index fb86b89fd..000000000 --- a/test/shuffle.js +++ /dev/null @@ -1,29 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import shuffle from '../shuffle.js'; - -describe('shuffle', function() { - var array = [1, 2, 3], - object = { 'a': 1, 'b': 2, 'c': 3 }; - - it('should return a new array', function() { - assert.notStrictEqual(shuffle(array), array); - }); - - it('should contain the same elements after a collection is shuffled', function() { - assert.deepStrictEqual(shuffle(array).sort(), array); - assert.deepStrictEqual(shuffle(object).sort(), array); - }); - - it('should shuffle small collections', function() { - var actual = lodashStable.times(1000, function() { - return shuffle([1, 2]); - }); - - assert.deepStrictEqual(lodashStable.sortBy(lodashStable.uniqBy(actual, String), '0'), [[1, 2], [2, 1]]); - }); - - it('should treat number values for `collection` as empty', function() { - assert.deepStrictEqual(shuffle(1), []); - }); -}); diff --git a/test/shuffle.spec.ts b/test/shuffle.spec.ts new file mode 100644 index 000000000..79c6270a7 --- /dev/null +++ b/test/shuffle.spec.ts @@ -0,0 +1,30 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import shuffle from '../src/shuffle'; + +describe('shuffle', () => { + const array = [1, 2, 3], + object = { a: 1, b: 2, c: 3 }; + + it('should return a new array', () => { + assert.notStrictEqual(shuffle(array), array); + }); + + it('should contain the same elements after a collection is shuffled', () => { + assert.deepStrictEqual(shuffle(array).sort(), array); + assert.deepStrictEqual(shuffle(object).sort(), array); + }); + + it('should shuffle small collections', () => { + const actual = lodashStable.times(1000, () => shuffle([1, 2])); + + assert.deepStrictEqual(lodashStable.sortBy(lodashStable.uniqBy(actual, String), '0'), [ + [1, 2], + [2, 1], + ]); + }); + + it('should treat number values for `collection` as empty', () => { + assert.deepStrictEqual(shuffle(1), []); + }); +}); diff --git a/test/size.spec.ts b/test/size.spec.ts new file mode 100644 index 000000000..c1e5a6a2a --- /dev/null +++ b/test/size.spec.ts @@ -0,0 +1,75 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubZero, args, push, arrayProto, realm, MAX_SAFE_INTEGER } from './utils'; +import size from '../src/size'; + +describe('size', () => { + const array = [1, 2, 3]; + + it('should return the number of own enumerable string keyed properties of an object', () => { + assert.strictEqual(size({ one: 1, two: 2, three: 3 }), 3); + }); + + it('should return the length of an array', () => { + assert.strictEqual(size(array), 3); + }); + + it('should accept a falsey `object`', () => { + const expected = lodashStable.map(falsey, stubZero); + + const actual = lodashStable.map(falsey, (object, index) => { + try { + return index ? size(object) : size(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `arguments` objects', () => { + assert.strictEqual(size(args), 3); + }); + + it('should work with jQuery/MooTools DOM query collections', () => { + function Foo(elements) { + push.apply(this, elements); + } + Foo.prototype = { length: 0, splice: arrayProto.splice }; + + assert.strictEqual(size(new Foo(array)), 3); + }); + + it('should work with maps', () => { + if (Map) { + lodashStable.each([new Map(), realm.map], (map) => { + map.set('a', 1); + map.set('b', 2); + assert.strictEqual(size(map), 2); + map.clear(); + }); + } + }); + + it('should work with sets', () => { + if (Set) { + lodashStable.each([new Set(), realm.set], (set) => { + set.add(1); + set.add(2); + assert.strictEqual(size(set), 2); + set.clear(); + }); + } + }); + + it('should not treat objects with negative lengths as array-like', () => { + assert.strictEqual(size({ length: -1 }), 1); + }); + + it('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', () => { + assert.strictEqual(size({ length: MAX_SAFE_INTEGER + 1 }), 1); + }); + + it('should not treat objects with non-number lengths as array-like', () => { + assert.strictEqual(size({ length: '0' }), 1); + }); +}); diff --git a/test/size.test.js b/test/size.test.js deleted file mode 100644 index 286173453..000000000 --- a/test/size.test.js +++ /dev/null @@ -1,75 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubZero, args, push, arrayProto, realm, MAX_SAFE_INTEGER } from './utils.js'; -import size from '../size.js'; - -describe('size', function() { - var array = [1, 2, 3]; - - it('should return the number of own enumerable string keyed properties of an object', function() { - assert.strictEqual(size({ 'one': 1, 'two': 2, 'three': 3 }), 3); - }); - - it('should return the length of an array', function() { - assert.strictEqual(size(array), 3); - }); - - it('should accept a falsey `object`', function() { - var expected = lodashStable.map(falsey, stubZero); - - var actual = lodashStable.map(falsey, function(object, index) { - try { - return index ? size(object) : size(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `arguments` objects', function() { - assert.strictEqual(size(args), 3); - }); - - it('should work with jQuery/MooTools DOM query collections', function() { - function Foo(elements) { - push.apply(this, elements); - } - Foo.prototype = { 'length': 0, 'splice': arrayProto.splice }; - - assert.strictEqual(size(new Foo(array)), 3); - }); - - it('should work with maps', function() { - if (Map) { - lodashStable.each([new Map, realm.map], function(map) { - map.set('a', 1); - map.set('b', 2); - assert.strictEqual(size(map), 2); - map.clear(); - }); - } - }); - - it('should work with sets', function() { - if (Set) { - lodashStable.each([new Set, realm.set], function(set) { - set.add(1); - set.add(2); - assert.strictEqual(size(set), 2); - set.clear(); - }); - } - }); - - it('should not treat objects with negative lengths as array-like', function() { - assert.strictEqual(size({ 'length': -1 }), 1); - }); - - it('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', function() { - assert.strictEqual(size({ 'length': MAX_SAFE_INTEGER + 1 }), 1); - }); - - it('should not treat objects with non-number lengths as array-like', function() { - assert.strictEqual(size({ 'length': '0' }), 1); - }); -}); diff --git a/test/slice-and-toArray.js b/test/slice-and-toArray.js deleted file mode 100644 index 7c8607015..000000000 --- a/test/slice-and-toArray.js +++ /dev/null @@ -1,43 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, args, document, body } from './utils.js'; - -describe('slice and toArray', function() { - lodashStable.each(['slice', 'toArray'], function(methodName) { - var array = [1, 2, 3], - func = _[methodName]; - - it('`_.' + methodName + '` should return a dense array', function() { - var sparse = Array(3); - sparse[1] = 2; - - var actual = func(sparse); - - assert.ok('0' in actual); - assert.ok('2' in actual); - assert.deepStrictEqual(actual, sparse); - }); - - it('`_.' + methodName + '` should treat array-like objects like arrays', function() { - var object = { '0': 'a', 'length': 1 }; - assert.deepStrictEqual(func(object), ['a']); - assert.deepStrictEqual(func(args), array); - }); - - it('`_.' + methodName + '` should return a shallow clone of arrays', function() { - var actual = func(array); - assert.deepStrictEqual(actual, array); - assert.notStrictEqual(actual, array); - }); - - it('`_.' + methodName + '` should work with a node list for `collection`', function() { - if (document) { - try { - var actual = func(document.getElementsByTagName('body')); - } catch (e) {} - - assert.deepStrictEqual(actual, [body]); - } - }); - }); -}); diff --git a/test/slice-and-toArray.spec.ts b/test/slice-and-toArray.spec.ts new file mode 100644 index 000000000..ce08f64ec --- /dev/null +++ b/test/slice-and-toArray.spec.ts @@ -0,0 +1,43 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, args, document, body } from './utils'; + +describe('slice and toArray', () => { + lodashStable.each(['slice', 'toArray'], (methodName) => { + const array = [1, 2, 3], + func = _[methodName]; + + it(`\`_.${methodName}\` should return a dense array`, () => { + const sparse = Array(3); + sparse[1] = 2; + + const actual = func(sparse); + + assert.ok('0' in actual); + assert.ok('2' in actual); + assert.deepStrictEqual(actual, sparse); + }); + + it(`\`_.${methodName}\` should treat array-like objects like arrays`, () => { + const object = { '0': 'a', length: 1 }; + assert.deepStrictEqual(func(object), ['a']); + assert.deepStrictEqual(func(args), array); + }); + + it(`\`_.${methodName}\` should return a shallow clone of arrays`, () => { + const actual = func(array); + assert.deepStrictEqual(actual, array); + assert.notStrictEqual(actual, array); + }); + + it(`\`_.${methodName}\` should work with a node list for \`collection\``, () => { + if (document) { + try { + var actual = func(document.getElementsByTagName('body')); + } catch (e) {} + + assert.deepStrictEqual(actual, [body]); + } + }); + }); +}); diff --git a/test/slice.js b/test/slice.js deleted file mode 100644 index 1e47e1283..000000000 --- a/test/slice.js +++ /dev/null @@ -1,133 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, LARGE_ARRAY_SIZE } from './utils.js'; -import slice from '../slice.js'; - -describe('slice', function() { - var array = [1, 2, 3]; - - it('should use a default `start` of `0` and a default `end` of `length`', function() { - var actual = slice(array); - assert.deepStrictEqual(actual, array); - assert.notStrictEqual(actual, array); - }); - - it('should work with a positive `start`', function() { - assert.deepStrictEqual(slice(array, 1), [2, 3]); - assert.deepStrictEqual(slice(array, 1, 3), [2, 3]); - }); - - it('should work with a `start` >= `length`', function() { - lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(start) { - assert.deepStrictEqual(slice(array, start), []); - }); - }); - - it('should treat falsey `start` values as `0`', function() { - var expected = lodashStable.map(falsey, lodashStable.constant(array)); - - var actual = lodashStable.map(falsey, function(start) { - return slice(array, start); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with a negative `start`', function() { - assert.deepStrictEqual(slice(array, -1), [3]); - }); - - it('should work with a negative `start` <= negative `length`', function() { - lodashStable.each([-3, -4, -Infinity], function(start) { - assert.deepStrictEqual(slice(array, start), array); - }); - }); - - it('should work with `start` >= `end`', function() { - lodashStable.each([2, 3], function(start) { - assert.deepStrictEqual(slice(array, start, 2), []); - }); - }); - - it('should work with a positive `end`', function() { - assert.deepStrictEqual(slice(array, 0, 1), [1]); - }); - - it('should work with a `end` >= `length`', function() { - lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(end) { - assert.deepStrictEqual(slice(array, 0, end), array); - }); - }); - - it('should treat falsey `end` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? array : []; - }); - - var actual = lodashStable.map(falsey, function(end, index) { - return index ? slice(array, 0, end) : slice(array, 0); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with a negative `end`', function() { - assert.deepStrictEqual(slice(array, 0, -1), [1, 2]); - }); - - it('should work with a negative `end` <= negative `length`', function() { - lodashStable.each([-3, -4, -Infinity], function(end) { - assert.deepStrictEqual(slice(array, 0, end), []); - }); - }); - - it('should coerce `start` and `end` to integers', function() { - var positions = [[0.1, 1.6], ['0', 1], [0, '1'], ['1'], [NaN, 1], [1, NaN]]; - - var actual = lodashStable.map(positions, function(pos) { - return slice.apply(_, [array].concat(pos)); - }); - - assert.deepStrictEqual(actual, [[1], [1], [1], [2, 3], [1], []]); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [[1], [2, 3]], - actual = lodashStable.map(array, slice); - - assert.deepStrictEqual(actual, array); - assert.notStrictEqual(actual, array); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), - length = array.length, - wrapped = _(array); - - lodashStable.each(['map', 'filter'], function(methodName) { - assert.deepEqual(wrapped[methodName]().slice(0, -1).value(), array.slice(0, -1)); - assert.deepEqual(wrapped[methodName]().slice(1).value(), array.slice(1)); - assert.deepEqual(wrapped[methodName]().slice(1, 3).value(), array.slice(1, 3)); - assert.deepEqual(wrapped[methodName]().slice(-1).value(), array.slice(-1)); - - assert.deepEqual(wrapped[methodName]().slice(length).value(), array.slice(length)); - assert.deepEqual(wrapped[methodName]().slice(3, 2).value(), array.slice(3, 2)); - assert.deepEqual(wrapped[methodName]().slice(0, -length).value(), array.slice(0, -length)); - assert.deepEqual(wrapped[methodName]().slice(0, null).value(), array.slice(0, null)); - - assert.deepEqual(wrapped[methodName]().slice(0, length).value(), array.slice(0, length)); - assert.deepEqual(wrapped[methodName]().slice(-length).value(), array.slice(-length)); - assert.deepEqual(wrapped[methodName]().slice(null).value(), array.slice(null)); - - assert.deepEqual(wrapped[methodName]().slice(0, 1).value(), array.slice(0, 1)); - assert.deepEqual(wrapped[methodName]().slice(NaN, '1').value(), array.slice(NaN, '1')); - - assert.deepEqual(wrapped[methodName]().slice(0.1, 1.1).value(), array.slice(0.1, 1.1)); - assert.deepEqual(wrapped[methodName]().slice('0', 1).value(), array.slice('0', 1)); - assert.deepEqual(wrapped[methodName]().slice(0, '1').value(), array.slice(0, '1')); - assert.deepEqual(wrapped[methodName]().slice('1').value(), array.slice('1')); - assert.deepEqual(wrapped[methodName]().slice(NaN, 1).value(), array.slice(NaN, 1)); - assert.deepEqual(wrapped[methodName]().slice(1, NaN).value(), array.slice(1, NaN)); - }); - }); -}); diff --git a/test/slice.spec.ts b/test/slice.spec.ts new file mode 100644 index 000000000..727b61bba --- /dev/null +++ b/test/slice.spec.ts @@ -0,0 +1,133 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, LARGE_ARRAY_SIZE } from './utils'; +import slice from '../src/slice'; + +describe('slice', () => { + const array = [1, 2, 3]; + + it('should use a default `start` of `0` and a default `end` of `length`', () => { + const actual = slice(array); + assert.deepStrictEqual(actual, array); + assert.notStrictEqual(actual, array); + }); + + it('should work with a positive `start`', () => { + assert.deepStrictEqual(slice(array, 1), [2, 3]); + assert.deepStrictEqual(slice(array, 1, 3), [2, 3]); + }); + + it('should work with a `start` >= `length`', () => { + lodashStable.each([3, 4, 2 ** 32, Infinity], (start) => { + assert.deepStrictEqual(slice(array, start), []); + }); + }); + + it('should treat falsey `start` values as `0`', () => { + const expected = lodashStable.map(falsey, lodashStable.constant(array)); + + const actual = lodashStable.map(falsey, (start) => slice(array, start)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with a negative `start`', () => { + assert.deepStrictEqual(slice(array, -1), [3]); + }); + + it('should work with a negative `start` <= negative `length`', () => { + lodashStable.each([-3, -4, -Infinity], (start) => { + assert.deepStrictEqual(slice(array, start), array); + }); + }); + + it('should work with `start` >= `end`', () => { + lodashStable.each([2, 3], (start) => { + assert.deepStrictEqual(slice(array, start, 2), []); + }); + }); + + it('should work with a positive `end`', () => { + assert.deepStrictEqual(slice(array, 0, 1), [1]); + }); + + it('should work with a `end` >= `length`', () => { + lodashStable.each([3, 4, 2 ** 32, Infinity], (end) => { + assert.deepStrictEqual(slice(array, 0, end), array); + }); + }); + + it('should treat falsey `end` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, (value) => (value === undefined ? array : [])); + + const actual = lodashStable.map(falsey, (end, index) => + index ? slice(array, 0, end) : slice(array, 0), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with a negative `end`', () => { + assert.deepStrictEqual(slice(array, 0, -1), [1, 2]); + }); + + it('should work with a negative `end` <= negative `length`', () => { + lodashStable.each([-3, -4, -Infinity], (end) => { + assert.deepStrictEqual(slice(array, 0, end), []); + }); + }); + + it('should coerce `start` and `end` to integers', () => { + const positions = [[0.1, 1.6], ['0', 1], [0, '1'], ['1'], [NaN, 1], [1, NaN]]; + + const actual = lodashStable.map(positions, (pos) => slice.apply(_, [array].concat(pos))); + + assert.deepStrictEqual(actual, [[1], [1], [1], [2, 3], [1], []]); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [[1], [2, 3]], + actual = lodashStable.map(array, slice); + + assert.deepStrictEqual(actual, array); + assert.notStrictEqual(actual, array); + }); + + it('should work in a lazy sequence', () => { + const array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), + length = array.length, + wrapped = _(array); + + lodashStable.each(['map', 'filter'], (methodName) => { + assert.deepEqual(wrapped[methodName]().slice(0, -1).value(), array.slice(0, -1)); + assert.deepEqual(wrapped[methodName]().slice(1).value(), array.slice(1)); + assert.deepEqual(wrapped[methodName]().slice(1, 3).value(), array.slice(1, 3)); + assert.deepEqual(wrapped[methodName]().slice(-1).value(), array.slice(-1)); + + assert.deepEqual(wrapped[methodName]().slice(length).value(), array.slice(length)); + assert.deepEqual(wrapped[methodName]().slice(3, 2).value(), array.slice(3, 2)); + assert.deepEqual( + wrapped[methodName]().slice(0, -length).value(), + array.slice(0, -length), + ); + assert.deepEqual(wrapped[methodName]().slice(0, null).value(), array.slice(0, null)); + + assert.deepEqual( + wrapped[methodName]().slice(0, length).value(), + array.slice(0, length), + ); + assert.deepEqual(wrapped[methodName]().slice(-length).value(), array.slice(-length)); + assert.deepEqual(wrapped[methodName]().slice(null).value(), array.slice(null)); + + assert.deepEqual(wrapped[methodName]().slice(0, 1).value(), array.slice(0, 1)); + assert.deepEqual(wrapped[methodName]().slice(NaN, '1').value(), array.slice(NaN, '1')); + + assert.deepEqual(wrapped[methodName]().slice(0.1, 1.1).value(), array.slice(0.1, 1.1)); + assert.deepEqual(wrapped[methodName]().slice('0', 1).value(), array.slice('0', 1)); + assert.deepEqual(wrapped[methodName]().slice(0, '1').value(), array.slice(0, '1')); + assert.deepEqual(wrapped[methodName]().slice('1').value(), array.slice('1')); + assert.deepEqual(wrapped[methodName]().slice(NaN, 1).value(), array.slice(NaN, 1)); + assert.deepEqual(wrapped[methodName]().slice(1, NaN).value(), array.slice(1, NaN)); + }); + }); +}); diff --git a/test/some.js b/test/some.js deleted file mode 100644 index 5f93f4145..000000000 --- a/test/some.js +++ /dev/null @@ -1,76 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { identity, empties, stubFalse, stubTrue } from './utils.js'; -import some from '../some.js'; - -describe('some', function() { - it('should return `true` if `predicate` returns truthy for any element', function() { - assert.strictEqual(some([false, 1, ''], identity), true); - assert.strictEqual(some([null, 'a', 0], identity), true); - }); - - it('should return `false` for empty collections', function() { - var expected = lodashStable.map(empties, stubFalse); - - var actual = lodashStable.map(empties, function(value) { - try { - return some(value, identity); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return `true` as soon as `predicate` returns truthy', function() { - var count = 0; - - assert.strictEqual(some([null, true, null], function(value) { - count++; - return value; - }), true); - - assert.strictEqual(count, 2); - }); - - it('should return `false` if `predicate` returns falsey for all elements', function() { - assert.strictEqual(some([false, false, false], identity), false); - assert.strictEqual(some([null, 0, ''], identity), false); - }); - - it('should use `_.identity` when `predicate` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value, index) { - var array = [0, 0]; - return index ? some(array, value) : some(array); - }); - - assert.deepStrictEqual(actual, expected); - - expected = lodashStable.map(values, stubTrue); - actual = lodashStable.map(values, function(value, index) { - var array = [0, 1]; - return index ? some(array, value) : some(array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `_.property` shorthands', function() { - var objects = [{ 'a': 0, 'b': 0 }, { 'a': 0, 'b': 1 }]; - assert.strictEqual(some(objects, 'a'), false); - assert.strictEqual(some(objects, 'b'), true); - }); - - it('should work with `_.matches` shorthands', function() { - var objects = [{ 'a': 0, 'b': 0 }, { 'a': 1, 'b': 1}]; - assert.strictEqual(some(objects, { 'a': 0 }), true); - assert.strictEqual(some(objects, { 'b': 2 }), false); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var actual = lodashStable.map([[1]], some); - assert.deepStrictEqual(actual, [true]); - }); -}); diff --git a/test/some.spec.ts b/test/some.spec.ts new file mode 100644 index 000000000..cdd267ffd --- /dev/null +++ b/test/some.spec.ts @@ -0,0 +1,85 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { identity, empties, stubFalse, stubTrue } from './utils'; +import some from '../src/some'; + +describe('some', () => { + it('should return `true` if `predicate` returns truthy for any element', () => { + assert.strictEqual(some([false, 1, ''], identity), true); + assert.strictEqual(some([null, 'a', 0], identity), true); + }); + + it('should return `false` for empty collections', () => { + const expected = lodashStable.map(empties, stubFalse); + + const actual = lodashStable.map(empties, (value) => { + try { + return some(value, identity); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return `true` as soon as `predicate` returns truthy', () => { + let count = 0; + + assert.strictEqual( + some([null, true, null], (value) => { + count++; + return value; + }), + true, + ); + + assert.strictEqual(count, 2); + }); + + it('should return `false` if `predicate` returns falsey for all elements', () => { + assert.strictEqual(some([false, false, false], identity), false); + assert.strictEqual(some([null, 0, ''], identity), false); + }); + + it('should use `_.identity` when `predicate` is nullish', () => { + let values = [, null, undefined], + expected = lodashStable.map(values, stubFalse); + + let actual = lodashStable.map(values, (value, index) => { + const array = [0, 0]; + return index ? some(array, value) : some(array); + }); + + assert.deepStrictEqual(actual, expected); + + expected = lodashStable.map(values, stubTrue); + actual = lodashStable.map(values, (value, index) => { + const array = [0, 1]; + return index ? some(array, value) : some(array); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `_.property` shorthands', () => { + const objects = [ + { a: 0, b: 0 }, + { a: 0, b: 1 }, + ]; + assert.strictEqual(some(objects, 'a'), false); + assert.strictEqual(some(objects, 'b'), true); + }); + + it('should work with `_.matches` shorthands', () => { + const objects = [ + { a: 0, b: 0 }, + { a: 1, b: 1 }, + ]; + assert.strictEqual(some(objects, { a: 0 }), true); + assert.strictEqual(some(objects, { b: 2 }), false); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const actual = lodashStable.map([[1]], some); + assert.deepStrictEqual(actual, [true]); + }); +}); diff --git a/test/sortBy-methods.js b/test/sortBy-methods.js deleted file mode 100644 index fb4748d0f..000000000 --- a/test/sortBy-methods.js +++ /dev/null @@ -1,87 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('sortBy methods', function() { - lodashStable.each(['orderBy', 'sortBy'], function(methodName) { - var func = _[methodName]; - - function Pair(a, b, c) { - this.a = a; - this.b = b; - this.c = c; - } - - var objects = [ - { 'a': 'x', 'b': 3 }, - { 'a': 'y', 'b': 4 }, - { 'a': 'x', 'b': 1 }, - { 'a': 'y', 'b': 2 } - ]; - - var stableArray = [ - new Pair(1, 1, 1), new Pair(1, 2, 1), - new Pair(1, 1, 1), new Pair(1, 2, 1), - new Pair(1, 3, 1), new Pair(1, 4, 1), - new Pair(1, 5, 1), new Pair(1, 6, 1), - new Pair(2, 1, 2), new Pair(2, 2, 2), - new Pair(2, 3, 2), new Pair(2, 4, 2), - new Pair(2, 5, 2), new Pair(2, 6, 2), - new Pair(undefined, 1, 1), new Pair(undefined, 2, 1), - new Pair(undefined, 3, 1), new Pair(undefined, 4, 1), - new Pair(undefined, 5, 1), new Pair(undefined, 6, 1) - ]; - - var stableObject = lodashStable.zipObject('abcdefghijklmnopqrst'.split(''), stableArray); - - it('`_.' + methodName + '` should sort multiple properties in ascending order', function() { - var actual = func(objects, ['a', 'b']); - assert.deepStrictEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); - }); - - it('`_.' + methodName + '` should support iteratees', function() { - var actual = func(objects, ['a', function(object) { return object.b; }]); - assert.deepStrictEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); - }); - - it('`_.' + methodName + '` should perform a stable sort (test in IE > 8 and V8)', function() { - lodashStable.each([stableArray, stableObject], function(value, index) { - var actual = func(value, ['a', 'c']); - assert.deepStrictEqual(actual, stableArray, index ? 'object' : 'array'); - }); - }); - - it('`_.' + methodName + '` should not error on nullish elements', function() { - try { - var actual = func(objects.concat(null, undefined), ['a', 'b']); - } catch (e) {} - - assert.deepStrictEqual(actual, [objects[2], objects[0], objects[3], objects[1], null, undefined]); - }); - - it('`_.' + methodName + '` should work as an iteratee for methods like `_.reduce`', function() { - var objects = [ - { 'a': 'x', '0': 3 }, - { 'a': 'y', '0': 4 }, - { 'a': 'x', '0': 1 }, - { 'a': 'y', '0': 2 } - ]; - - var funcs = [func, lodashStable.partialRight(func, 'bogus')]; - - lodashStable.each(['a', 0, [0]], function(props, index) { - var expected = lodashStable.map(funcs, lodashStable.constant( - index - ? [objects[2], objects[3], objects[0], objects[1]] - : [objects[0], objects[2], objects[1], objects[3]] - )); - - var actual = lodashStable.map(funcs, function(func) { - return lodashStable.reduce([props], func, objects); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - }); -}); diff --git a/test/sortBy-methods.spec.ts b/test/sortBy-methods.spec.ts new file mode 100644 index 000000000..05f3e8f4e --- /dev/null +++ b/test/sortBy-methods.spec.ts @@ -0,0 +1,112 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('sortBy methods', () => { + lodashStable.each(['orderBy', 'sortBy'], (methodName) => { + const func = _[methodName]; + + function Pair(a, b, c) { + this.a = a; + this.b = b; + this.c = c; + } + + const objects = [ + { a: 'x', b: 3 }, + { a: 'y', b: 4 }, + { a: 'x', b: 1 }, + { a: 'y', b: 2 }, + ]; + + const stableArray = [ + new Pair(1, 1, 1), + new Pair(1, 2, 1), + new Pair(1, 1, 1), + new Pair(1, 2, 1), + new Pair(1, 3, 1), + new Pair(1, 4, 1), + new Pair(1, 5, 1), + new Pair(1, 6, 1), + new Pair(2, 1, 2), + new Pair(2, 2, 2), + new Pair(2, 3, 2), + new Pair(2, 4, 2), + new Pair(2, 5, 2), + new Pair(2, 6, 2), + new Pair(undefined, 1, 1), + new Pair(undefined, 2, 1), + new Pair(undefined, 3, 1), + new Pair(undefined, 4, 1), + new Pair(undefined, 5, 1), + new Pair(undefined, 6, 1), + ]; + + const stableObject = lodashStable.zipObject('abcdefghijklmnopqrst'.split(''), stableArray); + + it(`\`_.${methodName}\` should sort multiple properties in ascending order`, () => { + const actual = func(objects, ['a', 'b']); + assert.deepStrictEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); + }); + + it(`\`_.${methodName}\` should support iteratees`, () => { + const actual = func(objects, [ + 'a', + function (object) { + return object.b; + }, + ]); + assert.deepStrictEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); + }); + + it(`\`_.${methodName}\` should perform a stable sort (test in IE > 8 and V8)`, () => { + lodashStable.each([stableArray, stableObject], (value, index) => { + const actual = func(value, ['a', 'c']); + assert.deepStrictEqual(actual, stableArray, index ? 'object' : 'array'); + }); + }); + + it(`\`_.${methodName}\` should not error on nullish elements`, () => { + try { + var actual = func(objects.concat(null, undefined), ['a', 'b']); + } catch (e) {} + + assert.deepStrictEqual(actual, [ + objects[2], + objects[0], + objects[3], + objects[1], + null, + undefined, + ]); + }); + + it(`\`_.${methodName}\` should work as an iteratee for methods like \`_.reduce\``, () => { + const objects = [ + { a: 'x', '0': 3 }, + { a: 'y', '0': 4 }, + { a: 'x', '0': 1 }, + { a: 'y', '0': 2 }, + ]; + + const funcs = [func, lodashStable.partialRight(func, 'bogus')]; + + lodashStable.each(['a', 0, [0]], (props, index) => { + const expected = lodashStable.map( + funcs, + lodashStable.constant( + index + ? [objects[2], objects[3], objects[0], objects[1]] + : [objects[0], objects[2], objects[1], objects[3]], + ), + ); + + const actual = lodashStable.map(funcs, (func) => + lodashStable.reduce([props], func, objects), + ); + + assert.deepStrictEqual(actual, expected); + }); + }); + }); +}); diff --git a/test/sortBy.js b/test/sortBy.js deleted file mode 100644 index 6cf7acc4f..000000000 --- a/test/sortBy.js +++ /dev/null @@ -1,75 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import sortBy from '../sortBy.js'; - -describe('sortBy', function() { - var objects = [ - { 'a': 'x', 'b': 3 }, - { 'a': 'y', 'b': 4 }, - { 'a': 'x', 'b': 1 }, - { 'a': 'y', 'b': 2 } - ]; - - it('should sort in ascending order by `iteratee`', function() { - var actual = lodashStable.map(sortBy(objects, function(object) { - return object.b; - }), 'b'); - - assert.deepStrictEqual(actual, [1, 2, 3, 4]); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var array = [3, 2, 1], - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant([1, 2, 3])); - - var actual = lodashStable.map(values, function(value, index) { - return index ? sortBy(array, value) : sortBy(array); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `_.property` shorthands', function() { - var actual = lodashStable.map(sortBy(objects.concat(undefined), 'b'), 'b'); - assert.deepStrictEqual(actual, [1, 2, 3, 4, undefined]); - }); - - it('should work with an object for `collection`', function() { - var actual = sortBy({ 'a': 1, 'b': 2, 'c': 3 }, Math.sin); - assert.deepStrictEqual(actual, [3, 1, 2]); - }); - - it('should move `NaN`, nullish, and symbol values to the end', function() { - var symbol1 = Symbol ? Symbol('a') : null, - symbol2 = Symbol ? Symbol('b') : null, - array = [NaN, undefined, null, 4, symbol1, null, 1, symbol2, undefined, 3, NaN, 2], - expected = [1, 2, 3, 4, symbol1, symbol2, null, null, undefined, undefined, NaN, NaN]; - - assert.deepStrictEqual(sortBy(array), expected); - - array = [NaN, undefined, symbol1, null, 'd', null, 'a', symbol2, undefined, 'c', NaN, 'b']; - expected = ['a', 'b', 'c', 'd', symbol1, symbol2, null, null, undefined, undefined, NaN, NaN]; - - assert.deepStrictEqual(sortBy(array), expected); - }); - - it('should treat number values for `collection` as empty', function() { - assert.deepStrictEqual(sortBy(1), []); - }); - - it('should coerce arrays returned from `iteratee`', function() { - var actual = sortBy(objects, function(object) { - var result = [object.a, object.b]; - result.toString = function() { return String(this[0]); }; - return result; - }); - - assert.deepStrictEqual(actual, [objects[0], objects[2], objects[1], objects[3]]); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var actual = lodashStable.map([[2, 1, 3], [3, 2, 1]], sortBy); - assert.deepStrictEqual(actual, [[1, 2, 3], [1, 2, 3]]); - }); -}); diff --git a/test/sortBy.spec.ts b/test/sortBy.spec.ts new file mode 100644 index 000000000..7e87862c0 --- /dev/null +++ b/test/sortBy.spec.ts @@ -0,0 +1,100 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import sortBy from '../src/sortBy'; + +describe('sortBy', () => { + const objects = [ + { a: 'x', b: 3 }, + { a: 'y', b: 4 }, + { a: 'x', b: 1 }, + { a: 'y', b: 2 }, + ]; + + it('should sort in ascending order by `iteratee`', () => { + const actual = lodashStable.map( + sortBy(objects, (object) => object.b), + 'b', + ); + + assert.deepStrictEqual(actual, [1, 2, 3, 4]); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const array = [3, 2, 1], + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant([1, 2, 3])); + + const actual = lodashStable.map(values, (value, index) => + index ? sortBy(array, value) : sortBy(array), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `_.property` shorthands', () => { + const actual = lodashStable.map(sortBy(objects.concat(undefined), 'b'), 'b'); + assert.deepStrictEqual(actual, [1, 2, 3, 4, undefined]); + }); + + it('should work with an object for `collection`', () => { + const actual = sortBy({ a: 1, b: 2, c: 3 }, Math.sin); + assert.deepStrictEqual(actual, [3, 1, 2]); + }); + + it('should move `NaN`, nullish, and symbol values to the end', () => { + let symbol1 = Symbol ? Symbol('a') : null, + symbol2 = Symbol ? Symbol('b') : null, + array = [NaN, undefined, null, 4, symbol1, null, 1, symbol2, undefined, 3, NaN, 2], + expected = [1, 2, 3, 4, symbol1, symbol2, null, null, undefined, undefined, NaN, NaN]; + + assert.deepStrictEqual(sortBy(array), expected); + + array = [NaN, undefined, symbol1, null, 'd', null, 'a', symbol2, undefined, 'c', NaN, 'b']; + expected = [ + 'a', + 'b', + 'c', + 'd', + symbol1, + symbol2, + null, + null, + undefined, + undefined, + NaN, + NaN, + ]; + + assert.deepStrictEqual(sortBy(array), expected); + }); + + it('should treat number values for `collection` as empty', () => { + assert.deepStrictEqual(sortBy(1), []); + }); + + it('should coerce arrays returned from `iteratee`', () => { + const actual = sortBy(objects, (object) => { + const result = [object.a, object.b]; + result.toString = function () { + return String(this[0]); + }; + return result; + }); + + assert.deepStrictEqual(actual, [objects[0], objects[2], objects[1], objects[3]]); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const actual = lodashStable.map( + [ + [2, 1, 3], + [3, 2, 1], + ], + sortBy, + ); + assert.deepStrictEqual(actual, [ + [1, 2, 3], + [1, 2, 3], + ]); + }); +}); diff --git a/test/sortedIndex-methods.js b/test/sortedIndex-methods.js deleted file mode 100644 index 056918bc7..000000000 --- a/test/sortedIndex-methods.js +++ /dev/null @@ -1,84 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; -import sortBy from '../sortBy.js'; - -describe('sortedIndex methods', function() { - lodashStable.each(['sortedIndex', 'sortedLastIndex'], function(methodName) { - var func = _[methodName], - isSortedIndex = methodName == 'sortedIndex'; - - it('`_.' + methodName + '` should return the insert index', function() { - var array = [30, 50], - values = [30, 40, 50], - expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; - - var actual = lodashStable.map(values, function(value) { - return func(array, value); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with an array of strings', function() { - var array = ['a', 'c'], - values = ['a', 'b', 'c'], - expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; - - var actual = lodashStable.map(values, function(value) { - return func(array, value); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should accept a nullish `array` and a `value`', function() { - var values = [null, undefined], - expected = lodashStable.map(values, lodashStable.constant([0, 0, 0])); - - var actual = lodashStable.map(values, function(array) { - return [func(array, 1), func(array, undefined), func(array, NaN)]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should align with `_.sortBy`', function() { - var symbol1 = Symbol ? Symbol('a') : null, - symbol2 = Symbol ? Symbol('b') : null, - symbol3 = Symbol ? Symbol('c') : null, - expected = [1, '2', {}, symbol1, symbol2, null, undefined, NaN, NaN]; - - lodashStable.each([ - [NaN, symbol1, null, 1, '2', {}, symbol2, NaN, undefined], - ['2', null, 1, symbol1, NaN, {}, NaN, symbol2, undefined] - ], function(array) { - assert.deepStrictEqual(sortBy(array), expected); - assert.strictEqual(func(expected, 3), 2); - assert.strictEqual(func(expected, symbol3), isSortedIndex ? 3 : (Symbol ? 5 : 6)); - assert.strictEqual(func(expected, null), isSortedIndex ? (Symbol ? 5 : 3) : 6); - assert.strictEqual(func(expected, undefined), isSortedIndex ? 6 : 7); - assert.strictEqual(func(expected, NaN), isSortedIndex ? 7 : 9); - }); - }); - - it('`_.' + methodName + '` should align with `_.sortBy` for nulls', function() { - var array = [null, null]; - - assert.strictEqual(func(array, null), isSortedIndex ? 0 : 2); - assert.strictEqual(func(array, 1), 0); - assert.strictEqual(func(array, 'a'), 0); - }); - - it('`_.' + methodName + '` should align with `_.sortBy` for symbols', function() { - var symbol1 = Symbol ? Symbol('a') : null, - symbol2 = Symbol ? Symbol('b') : null, - symbol3 = Symbol ? Symbol('c') : null, - array = [symbol1, symbol2]; - - assert.strictEqual(func(array, symbol3), isSortedIndex ? 0 : 2); - assert.strictEqual(func(array, 1), 0); - assert.strictEqual(func(array, 'a'), 0); - }); - }); -}); diff --git a/test/sortedIndex-methods.spec.ts b/test/sortedIndex-methods.spec.ts new file mode 100644 index 000000000..b5c00884d --- /dev/null +++ b/test/sortedIndex-methods.spec.ts @@ -0,0 +1,85 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; +import sortBy from '../src/sortBy'; + +describe('sortedIndex methods', () => { + lodashStable.each(['sortedIndex', 'sortedLastIndex'], (methodName) => { + const func = _[methodName], + isSortedIndex = methodName == 'sortedIndex'; + + it(`\`_.${methodName}\` should return the insert index`, () => { + const array = [30, 50], + values = [30, 40, 50], + expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; + + const actual = lodashStable.map(values, (value) => func(array, value)); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with an array of strings`, () => { + const array = ['a', 'c'], + values = ['a', 'b', 'c'], + expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; + + const actual = lodashStable.map(values, (value) => func(array, value)); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should accept a nullish \`array\` and a \`value\``, () => { + const values = [null, undefined], + expected = lodashStable.map(values, lodashStable.constant([0, 0, 0])); + + const actual = lodashStable.map(values, (array) => [ + func(array, 1), + func(array, undefined), + func(array, NaN), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should align with \`_.sortBy\``, () => { + const symbol1 = Symbol ? Symbol('a') : null, + symbol2 = Symbol ? Symbol('b') : null, + symbol3 = Symbol ? Symbol('c') : null, + expected = [1, '2', {}, symbol1, symbol2, null, undefined, NaN, NaN]; + + lodashStable.each( + [ + [NaN, symbol1, null, 1, '2', {}, symbol2, NaN, undefined], + ['2', null, 1, symbol1, NaN, {}, NaN, symbol2, undefined], + ], + (array) => { + assert.deepStrictEqual(sortBy(array), expected); + assert.strictEqual(func(expected, 3), 2); + assert.strictEqual(func(expected, symbol3), isSortedIndex ? 3 : Symbol ? 5 : 6); + assert.strictEqual(func(expected, null), isSortedIndex ? (Symbol ? 5 : 3) : 6); + assert.strictEqual(func(expected, undefined), isSortedIndex ? 6 : 7); + assert.strictEqual(func(expected, NaN), isSortedIndex ? 7 : 9); + }, + ); + }); + + it(`\`_.${methodName}\` should align with \`_.sortBy\` for nulls`, () => { + const array = [null, null]; + + assert.strictEqual(func(array, null), isSortedIndex ? 0 : 2); + assert.strictEqual(func(array, 1), 0); + assert.strictEqual(func(array, 'a'), 0); + }); + + it(`\`_.${methodName}\` should align with \`_.sortBy\` for symbols`, () => { + const symbol1 = Symbol ? Symbol('a') : null, + symbol2 = Symbol ? Symbol('b') : null, + symbol3 = Symbol ? Symbol('c') : null, + array = [symbol1, symbol2]; + + assert.strictEqual(func(array, symbol3), isSortedIndex ? 0 : 2); + assert.strictEqual(func(array, 1), 0); + assert.strictEqual(func(array, 'a'), 0); + }); + }); +}); diff --git a/test/sortedIndexBy-methods.js b/test/sortedIndexBy-methods.js deleted file mode 100644 index ae3b5feaa..000000000 --- a/test/sortedIndexBy-methods.js +++ /dev/null @@ -1,59 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, slice, MAX_ARRAY_LENGTH, MAX_ARRAY_INDEX } from './utils.js'; - -describe('sortedIndexBy methods', function() { - lodashStable.each(['sortedIndexBy', 'sortedLastIndexBy'], function(methodName) { - var func = _[methodName], - isSortedIndexBy = methodName == 'sortedIndexBy'; - - it('`_.' + methodName + '` should provide correct `iteratee` arguments', function() { - var args; - - func([30, 50], 40, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [40]); - }); - - it('`_.' + methodName + '` should work with `_.property` shorthands', function() { - var objects = [{ 'x': 30 }, { 'x': 50 }], - actual = func(objects, { 'x': 40 }, 'x'); - - assert.strictEqual(actual, 1); - }); - - it('`_.' + methodName + '` should avoid calling iteratee when length is 0', function() { - var objects = [], - actual = func(objects, { 'x': 50 }, assert.fail); - - assert.strictEqual(actual, 0); - }); - - it('`_.' + methodName + '` should support arrays larger than `MAX_ARRAY_LENGTH / 2`', function() { - lodashStable.each([Math.ceil(MAX_ARRAY_LENGTH / 2), MAX_ARRAY_LENGTH], function(length) { - var array = [], - values = [MAX_ARRAY_LENGTH, NaN, undefined]; - - array.length = length; - - lodashStable.each(values, function(value) { - var steps = 0; - - var actual = func(array, value, function(value) { - steps++; - return value; - }); - - var expected = (isSortedIndexBy ? !lodashStable.isNaN(value) : lodashStable.isFinite(value)) - ? 0 - : Math.min(length, MAX_ARRAY_INDEX); - - assert.ok(steps == 32 || steps == 33); - assert.strictEqual(actual, expected); - }); - }); - }); - }); -}); diff --git a/test/sortedIndexBy-methods.spec.ts b/test/sortedIndexBy-methods.spec.ts new file mode 100644 index 000000000..a7e346cea --- /dev/null +++ b/test/sortedIndexBy-methods.spec.ts @@ -0,0 +1,61 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, slice, MAX_ARRAY_LENGTH, MAX_ARRAY_INDEX } from './utils'; + +describe('sortedIndexBy methods', () => { + lodashStable.each(['sortedIndexBy', 'sortedLastIndexBy'], (methodName) => { + const func = _[methodName], + isSortedIndexBy = methodName == 'sortedIndexBy'; + + it(`\`_.${methodName}\` should provide correct \`iteratee\` arguments`, () => { + let args; + + func([30, 50], 40, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [40]); + }); + + it(`\`_.${methodName}\` should work with \`_.property\` shorthands`, () => { + const objects = [{ x: 30 }, { x: 50 }], + actual = func(objects, { x: 40 }, 'x'); + + assert.strictEqual(actual, 1); + }); + + it(`\`_.${methodName}\` should avoid calling iteratee when length is 0`, () => { + const objects = [], + actual = func(objects, { x: 50 }, assert.fail); + + assert.strictEqual(actual, 0); + }); + + it(`\`_.${methodName}\` should support arrays larger than \`MAX_ARRAY_LENGTH / 2\``, () => { + lodashStable.each([Math.ceil(MAX_ARRAY_LENGTH / 2), MAX_ARRAY_LENGTH], (length) => { + const array = [], + values = [MAX_ARRAY_LENGTH, NaN, undefined]; + + array.length = length; + + lodashStable.each(values, (value) => { + let steps = 0; + + const actual = func(array, value, (value) => { + steps++; + return value; + }); + + const expected = ( + isSortedIndexBy ? !lodashStable.isNaN(value) : lodashStable.isFinite(value) + ) + ? 0 + : Math.min(length, MAX_ARRAY_INDEX); + + assert.ok(steps == 32 || steps == 33); + assert.strictEqual(actual, expected); + }); + }); + }); + }); +}); diff --git a/test/sortedIndexOf-methods.js b/test/sortedIndexOf-methods.js deleted file mode 100644 index 14550c564..000000000 --- a/test/sortedIndexOf-methods.js +++ /dev/null @@ -1,15 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('sortedIndexOf methods', function() { - lodashStable.each(['sortedIndexOf', 'sortedLastIndexOf'], function(methodName) { - var func = _[methodName], - isSortedIndexOf = methodName == 'sortedIndexOf'; - - it('`_.' + methodName + '` should perform a binary search', function() { - var sorted = [4, 4, 5, 5, 6, 6]; - assert.deepStrictEqual(func(sorted, 5), isSortedIndexOf ? 2 : 3); - }); - }); -}); diff --git a/test/sortedIndexOf-methods.spec.ts b/test/sortedIndexOf-methods.spec.ts new file mode 100644 index 000000000..91a061903 --- /dev/null +++ b/test/sortedIndexOf-methods.spec.ts @@ -0,0 +1,15 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('sortedIndexOf methods', () => { + lodashStable.each(['sortedIndexOf', 'sortedLastIndexOf'], (methodName) => { + const func = _[methodName], + isSortedIndexOf = methodName == 'sortedIndexOf'; + + it(`\`_.${methodName}\` should perform a binary search`, () => { + const sorted = [4, 4, 5, 5, 6, 6]; + assert.deepStrictEqual(func(sorted, 5), isSortedIndexOf ? 2 : 3); + }); + }); +}); diff --git a/test/sortedUniq.spec.ts b/test/sortedUniq.spec.ts new file mode 100644 index 000000000..84c970750 --- /dev/null +++ b/test/sortedUniq.spec.ts @@ -0,0 +1,20 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import sortedUniq from '../src/sortedUniq'; + +describe('sortedUniq', () => { + it('should return unique values of a sorted array', () => { + const expected = [1, 2, 3]; + + lodashStable.each( + [ + [1, 2, 3], + [1, 1, 2, 2, 3], + [1, 2, 3, 3, 3, 3, 3], + ], + (array) => { + assert.deepStrictEqual(sortedUniq(array), expected); + }, + ); + }); +}); diff --git a/test/sortedUniq.test.js b/test/sortedUniq.test.js deleted file mode 100644 index fec499a66..000000000 --- a/test/sortedUniq.test.js +++ /dev/null @@ -1,13 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import sortedUniq from '../sortedUniq.js'; - -describe('sortedUniq', function() { - it('should return unique values of a sorted array', function() { - var expected = [1, 2, 3]; - - lodashStable.each([[1, 2, 3], [1, 1, 2, 2, 3], [1, 2, 3, 3, 3, 3, 3]], function(array) { - assert.deepStrictEqual(sortedUniq(array), expected); - }); - }); -}); diff --git a/test/split.js b/test/split.js deleted file mode 100644 index cc8e05b7f..000000000 --- a/test/split.js +++ /dev/null @@ -1,35 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import split from '../split.js'; - -describe('split', function() { - it('should split a string by `separator`', function() { - var string = 'abcde'; - assert.deepStrictEqual(split(string, 'c'), ['ab', 'de']); - assert.deepStrictEqual(split(string, /[bd]/), ['a', 'c', 'e']); - assert.deepStrictEqual(split(string, '', 2), ['a', 'b']); - }); - - it('should return an array containing an empty string for empty values', function() { - var values = [, null, undefined, ''], - expected = lodashStable.map(values, lodashStable.constant([''])); - - var actual = lodashStable.map(values, function(value, index) { - return index ? split(value) : split(); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var strings = ['abc', 'def', 'ghi'], - actual = lodashStable.map(strings, split); - - assert.deepStrictEqual(actual, [['abc'], ['def'], ['ghi']]); - }); - - it('should allow mixed string and array prototype methods', function() { - var wrapped = _('abc'); - assert.strictEqual(wrapped.split('b').join(','), 'a,c'); - }); -}); diff --git a/test/split.spec.ts b/test/split.spec.ts new file mode 100644 index 000000000..66b22eecf --- /dev/null +++ b/test/split.spec.ts @@ -0,0 +1,33 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import split from '../src/split'; + +describe('split', () => { + it('should split a string by `separator`', () => { + const string = 'abcde'; + assert.deepStrictEqual(split(string, 'c'), ['ab', 'de']); + assert.deepStrictEqual(split(string, /[bd]/), ['a', 'c', 'e']); + assert.deepStrictEqual(split(string, '', 2), ['a', 'b']); + }); + + it('should return an array containing an empty string for empty values', () => { + const values = [, null, undefined, ''], + expected = lodashStable.map(values, lodashStable.constant([''])); + + const actual = lodashStable.map(values, (value, index) => (index ? split(value) : split())); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const strings = ['abc', 'def', 'ghi'], + actual = lodashStable.map(strings, split); + + assert.deepStrictEqual(actual, [['abc'], ['def'], ['ghi']]); + }); + + it('should allow mixed string and array prototype methods', () => { + const wrapped = _('abc'); + assert.strictEqual(wrapped.split('b').join(','), 'a,c'); + }); +}); diff --git a/test/spread.js b/test/spread.js deleted file mode 100644 index 862221b93..000000000 --- a/test/spread.js +++ /dev/null @@ -1,58 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, _, stubTrue, falsey } from './utils.js'; - -describe('spread', function() { - function fn(a, b, c) { - return slice.call(arguments); - } - - it('should spread arguments to `func`', function() { - var spread = _.spread(fn), - expected = [1, 2]; - - assert.deepStrictEqual(spread([1, 2]), expected); - assert.deepStrictEqual(spread([1, 2], 3), expected); - }); - - it('should accept a falsey `array`', function() { - var spread = _.spread(stubTrue), - expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(array, index) { - try { - return index ? spread(array) : spread(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with `start`', function() { - var spread = _.spread(fn, 1), - expected = [1, 2, 3]; - - assert.deepStrictEqual(spread(1, [2, 3]), expected); - assert.deepStrictEqual(spread(1, [2, 3], 4), expected); - }); - - it('should treat `start` as `0` for negative or `NaN` values', function() { - var values = [-1, NaN, 'a'], - expected = lodashStable.map(values, lodashStable.constant([1, 2])); - - var actual = lodashStable.map(values, function(value) { - var spread = _.spread(fn, value); - return spread([1, 2]); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should coerce `start` to an integer', function() { - var spread = _.spread(fn, 1.6), - expected = [1, 2, 3]; - - assert.deepStrictEqual(spread(1, [2, 3]), expected); - assert.deepStrictEqual(spread(1, [2, 3], 4), expected); - }); -}); diff --git a/test/spread.spec.ts b/test/spread.spec.ts new file mode 100644 index 000000000..f7c8c2096 --- /dev/null +++ b/test/spread.spec.ts @@ -0,0 +1,58 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, _, stubTrue, falsey } from './utils'; + +describe('spread', () => { + function fn(a, b, c) { + return slice.call(arguments); + } + + it('should spread arguments to `func`', () => { + const spread = _.spread(fn), + expected = [1, 2]; + + assert.deepStrictEqual(spread([1, 2]), expected); + assert.deepStrictEqual(spread([1, 2], 3), expected); + }); + + it('should accept a falsey `array`', () => { + const spread = _.spread(stubTrue), + expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (array, index) => { + try { + return index ? spread(array) : spread(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with `start`', () => { + const spread = _.spread(fn, 1), + expected = [1, 2, 3]; + + assert.deepStrictEqual(spread(1, [2, 3]), expected); + assert.deepStrictEqual(spread(1, [2, 3], 4), expected); + }); + + it('should treat `start` as `0` for negative or `NaN` values', () => { + const values = [-1, NaN, 'a'], + expected = lodashStable.map(values, lodashStable.constant([1, 2])); + + const actual = lodashStable.map(values, (value) => { + const spread = _.spread(fn, value); + return spread([1, 2]); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should coerce `start` to an integer', () => { + const spread = _.spread(fn, 1.6), + expected = [1, 2, 3]; + + assert.deepStrictEqual(spread(1, [2, 3]), expected); + assert.deepStrictEqual(spread(1, [2, 3], 4), expected); + }); +}); diff --git a/test/startCase.spec.ts b/test/startCase.spec.ts new file mode 100644 index 000000000..88e95e73d --- /dev/null +++ b/test/startCase.spec.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert'; +import startCase from '../src/startCase'; + +describe('startCase', () => { + it('should uppercase only the first character of each word', () => { + assert.strictEqual(startCase('--foo-bar--'), 'Foo Bar'); + assert.strictEqual(startCase('fooBar'), 'Foo Bar'); + assert.strictEqual(startCase('__FOO_BAR__'), 'FOO BAR'); + }); +}); diff --git a/test/startCase.test.js b/test/startCase.test.js deleted file mode 100644 index f61d329d0..000000000 --- a/test/startCase.test.js +++ /dev/null @@ -1,10 +0,0 @@ -import assert from 'assert'; -import startCase from '../startCase.js'; - -describe('startCase', function() { - it('should uppercase only the first character of each word', function() { - assert.strictEqual(startCase('--foo-bar--'), 'Foo Bar'); - assert.strictEqual(startCase('fooBar'), 'Foo Bar'); - assert.strictEqual(startCase('__FOO_BAR__'), 'FOO BAR'); - }); -}); diff --git a/test/startsWith-and-endsWith.js b/test/startsWith-and-endsWith.js deleted file mode 100644 index 58dabfe94..000000000 --- a/test/startsWith-and-endsWith.js +++ /dev/null @@ -1,38 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, MAX_SAFE_INTEGER } from './utils.js'; - -describe('startsWith and endsWith', function() { - lodashStable.each(['startsWith', 'endsWith'], function(methodName) { - var func = _[methodName], - isStartsWith = methodName == 'startsWith'; - - var string = 'abc', - chr = isStartsWith ? 'a' : 'c'; - - it('`_.' + methodName + '` should coerce `string` to a string', function() { - assert.strictEqual(func(Object(string), chr), true); - assert.strictEqual(func({ 'toString': lodashStable.constant(string) }, chr), true); - }); - - it('`_.' + methodName + '` should coerce `target` to a string', function() { - assert.strictEqual(func(string, Object(chr)), true); - assert.strictEqual(func(string, { 'toString': lodashStable.constant(chr) }), true); - }); - - it('`_.' + methodName + '` should coerce `position` to a number', function() { - var position = isStartsWith ? 1 : 2; - - assert.strictEqual(func(string, 'b', Object(position)), true); - assert.strictEqual(func(string, 'b', { 'toString': lodashStable.constant(String(position)) }), true); - }); - - it('should return `true` when `target` is an empty string regardless of `position`', function() { - var positions = [-Infinity, NaN, -3, -1, 0, 1, 2, 3, 5, MAX_SAFE_INTEGER, Infinity]; - - assert.ok(lodashStable.every(positions, function(position) { - return func(string, '', position); - })); - }); - }); -}); diff --git a/test/startsWith-and-endsWith.spec.ts b/test/startsWith-and-endsWith.spec.ts new file mode 100644 index 000000000..18f779fcf --- /dev/null +++ b/test/startsWith-and-endsWith.spec.ts @@ -0,0 +1,39 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, MAX_SAFE_INTEGER } from './utils'; + +describe('startsWith and endsWith', () => { + lodashStable.each(['startsWith', 'endsWith'], (methodName) => { + const func = _[methodName], + isStartsWith = methodName == 'startsWith'; + + const string = 'abc', + chr = isStartsWith ? 'a' : 'c'; + + it(`\`_.${methodName}\` should coerce \`string\` to a string`, () => { + assert.strictEqual(func(Object(string), chr), true); + assert.strictEqual(func({ toString: lodashStable.constant(string) }, chr), true); + }); + + it(`\`_.${methodName}\` should coerce \`target\` to a string`, () => { + assert.strictEqual(func(string, Object(chr)), true); + assert.strictEqual(func(string, { toString: lodashStable.constant(chr) }), true); + }); + + it(`\`_.${methodName}\` should coerce \`position\` to a number`, () => { + const position = isStartsWith ? 1 : 2; + + assert.strictEqual(func(string, 'b', Object(position)), true); + assert.strictEqual( + func(string, 'b', { toString: lodashStable.constant(String(position)) }), + true, + ); + }); + + it('should return `true` when `target` is an empty string regardless of `position`', () => { + const positions = [-Infinity, NaN, -3, -1, 0, 1, 2, 3, 5, MAX_SAFE_INTEGER, Infinity]; + + assert.ok(lodashStable.every(positions, (position) => func(string, '', position))); + }); + }); +}); diff --git a/test/startsWith.js b/test/startsWith.js deleted file mode 100644 index d58905032..000000000 --- a/test/startsWith.js +++ /dev/null @@ -1,47 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { MAX_SAFE_INTEGER, falsey, stubTrue } from './utils.js'; -import startsWith from '../startsWith.js'; - -describe('startsWith', function() { - var string = 'abc'; - - it('should return `true` if a string starts with `target`', function() { - assert.strictEqual(startsWith(string, 'a'), true); - }); - - it('should return `false` if a string does not start with `target`', function() { - assert.strictEqual(startsWith(string, 'b'), false); - }); - - it('should work with a `position`', function() { - assert.strictEqual(startsWith(string, 'b', 1), true); - }); - - it('should work with `position` >= `length`', function() { - lodashStable.each([3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { - assert.strictEqual(startsWith(string, 'a', position), false); - }); - }); - - it('should treat falsey `position` values as `0`', function() { - var expected = lodashStable.map(falsey, stubTrue); - - var actual = lodashStable.map(falsey, function(position) { - return startsWith(string, 'a', position); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should treat a negative `position` as `0`', function() { - lodashStable.each([-1, -3, -Infinity], function(position) { - assert.strictEqual(startsWith(string, 'a', position), true); - assert.strictEqual(startsWith(string, 'b', position), false); - }); - }); - - it('should coerce `position` to an integer', function() { - assert.strictEqual(startsWith(string, 'bc', 1.2), true); - }); -}); diff --git a/test/startsWith.spec.ts b/test/startsWith.spec.ts new file mode 100644 index 000000000..df23170e5 --- /dev/null +++ b/test/startsWith.spec.ts @@ -0,0 +1,45 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { MAX_SAFE_INTEGER, falsey, stubTrue } from './utils'; +import startsWith from '../src/startsWith'; + +describe('startsWith', () => { + const string = 'abc'; + + it('should return `true` if a string starts with `target`', () => { + assert.strictEqual(startsWith(string, 'a'), true); + }); + + it('should return `false` if a string does not start with `target`', () => { + assert.strictEqual(startsWith(string, 'b'), false); + }); + + it('should work with a `position`', () => { + assert.strictEqual(startsWith(string, 'b', 1), true); + }); + + it('should work with `position` >= `length`', () => { + lodashStable.each([3, 5, MAX_SAFE_INTEGER, Infinity], (position) => { + assert.strictEqual(startsWith(string, 'a', position), false); + }); + }); + + it('should treat falsey `position` values as `0`', () => { + const expected = lodashStable.map(falsey, stubTrue); + + const actual = lodashStable.map(falsey, (position) => startsWith(string, 'a', position)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should treat a negative `position` as `0`', () => { + lodashStable.each([-1, -3, -Infinity], (position) => { + assert.strictEqual(startsWith(string, 'a', position), true); + assert.strictEqual(startsWith(string, 'b', position), false); + }); + }); + + it('should coerce `position` to an integer', () => { + assert.strictEqual(startsWith(string, 'bc', 1.2), true); + }); +}); diff --git a/test/strict-mode-checks.js b/test/strict-mode-checks.js deleted file mode 100644 index 3423fe1b8..000000000 --- a/test/strict-mode-checks.js +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, isStrict, freeze } from './utils.js'; - -describe('strict mode checks', function() { - lodashStable.each(['assign', 'assignIn', 'bindAll', 'defaults', 'defaultsDeep', 'merge'], function(methodName) { - var func = _[methodName], - isBindAll = methodName == 'bindAll'; - - it('`_.' + methodName + '` should ' + (isStrict ? '' : 'not ') + 'throw strict mode errors', function() { - var object = freeze({ 'a': undefined, 'b': function() {} }), - pass = !isStrict; - - try { - func(object, isBindAll ? 'b' : { 'a': 1 }); - } catch (e) { - pass = !pass; - } - assert.ok(pass); - }); - }); -}); diff --git a/test/strict-mode-checks.spec.ts b/test/strict-mode-checks.spec.ts new file mode 100644 index 000000000..3779e6538 --- /dev/null +++ b/test/strict-mode-checks.spec.ts @@ -0,0 +1,27 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, isStrict, freeze } from './utils'; + +describe('strict mode checks', () => { + lodashStable.each( + ['assign', 'assignIn', 'bindAll', 'defaults', 'defaultsDeep', 'merge'], + (methodName) => { + const func = _[methodName], + isBindAll = methodName == 'bindAll'; + + it(`\`_.${methodName}\` should ${ + isStrict ? '' : 'not ' + }throw strict mode errors`, () => { + let object = freeze({ a: undefined, b: function () {} }), + pass = !isStrict; + + try { + func(object, isBindAll ? 'b' : { a: 1 }); + } catch (e) { + pass = !pass; + } + assert.ok(pass); + }); + }, + ); +}); diff --git a/test/stub-methods.js b/test/stub-methods.js deleted file mode 100644 index 1fb0e61b6..000000000 --- a/test/stub-methods.js +++ /dev/null @@ -1,32 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, empties } from './utils.js'; - -describe('stub methods', function() { - lodashStable.each(['noop', 'stubTrue', 'stubFalse', 'stubArray', 'stubObject', 'stubString'], function(methodName) { - var func = _[methodName]; - - var pair = ({ - 'stubArray': [[], 'an empty array'], - 'stubFalse': [false, '`false`'], - 'stubObject': [{}, 'an empty object'], - 'stubString': ['', 'an empty string'], - 'stubTrue': [true, '`true`'], - 'noop': [undefined, '`undefined`'] - })[methodName]; - - var values = Array(2).concat(empties, true, 1, 'a'), - expected = lodashStable.map(values, lodashStable.constant(pair[0])); - - it('`_.' + methodName + '` should return ' + pair[1], function() { - var actual = lodashStable.map(values, function(value, index) { - if (index < 2) { - return index ? func.call({}) : func(); - } - return func(value); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/stub-methods.spec.ts b/test/stub-methods.spec.ts new file mode 100644 index 000000000..e03d650b4 --- /dev/null +++ b/test/stub-methods.spec.ts @@ -0,0 +1,35 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, empties } from './utils'; + +describe('stub methods', () => { + lodashStable.each( + ['noop', 'stubTrue', 'stubFalse', 'stubArray', 'stubObject', 'stubString'], + (methodName) => { + const func = _[methodName]; + + const pair = { + stubArray: [[], 'an empty array'], + stubFalse: [false, '`false`'], + stubObject: [{}, 'an empty object'], + stubString: ['', 'an empty string'], + stubTrue: [true, '`true`'], + noop: [undefined, '`undefined`'], + }[methodName]; + + const values = Array(2).concat(empties, true, 1, 'a'), + expected = lodashStable.map(values, lodashStable.constant(pair[0])); + + it(`\`_.${methodName}\` should return ${pair[1]}`, () => { + const actual = lodashStable.map(values, (value, index) => { + if (index < 2) { + return index ? func.call({}) : func(); + } + return func(value); + }); + + assert.deepStrictEqual(actual, expected); + }); + }, + ); +}); diff --git a/test/subtract.spec.ts b/test/subtract.spec.ts new file mode 100644 index 000000000..2107ef211 --- /dev/null +++ b/test/subtract.spec.ts @@ -0,0 +1,15 @@ +import assert from 'node:assert'; +import subtract from '../src/subtract'; + +describe('subtract', () => { + it('should subtract two numbers', () => { + assert.strictEqual(subtract(6, 4), 2); + assert.strictEqual(subtract(-6, 4), -10); + assert.strictEqual(subtract(-6, -4), -2); + }); + + it('should coerce arguments to numbers', () => { + assert.strictEqual(subtract('6', '4'), 2); + assert.deepStrictEqual(subtract('x', 'y'), NaN); + }); +}); diff --git a/test/subtract.test.js b/test/subtract.test.js deleted file mode 100644 index b148411ad..000000000 --- a/test/subtract.test.js +++ /dev/null @@ -1,15 +0,0 @@ -import assert from 'assert'; -import subtract from '../subtract.js'; - -describe('subtract', function() { - it('should subtract two numbers', function() { - assert.strictEqual(subtract(6, 4), 2); - assert.strictEqual(subtract(-6, 4), -10); - assert.strictEqual(subtract(-6, -4), -2); - }); - - it('should coerce arguments to numbers', function() { - assert.strictEqual(subtract('6', '4'), 2); - assert.deepStrictEqual(subtract('x', 'y'), NaN); - }); -}); diff --git a/test/sum-methods.js b/test/sum-methods.js deleted file mode 100644 index d536b9c50..000000000 --- a/test/sum-methods.js +++ /dev/null @@ -1,36 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, empties, stubZero } from './utils.js'; - -describe('sum methods', function() { - lodashStable.each(['sum', 'sumBy'], function(methodName) { - var array = [6, 4, 2], - func = _[methodName]; - - it('`_.' + methodName + '` should return the sum of an array of numbers', function() { - assert.strictEqual(func(array), 12); - }); - - it('`_.' + methodName + '` should return `0` when passing empty `array` values', function() { - var expected = lodashStable.map(empties, stubZero); - - var actual = lodashStable.map(empties, function(value) { - return func(value); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should skip `undefined` values', function() { - assert.strictEqual(func([1, undefined]), 1); - }); - - it('`_.' + methodName + '` should not skip `NaN` values', function() { - assert.deepStrictEqual(func([1, NaN]), NaN); - }); - - it('`_.' + methodName + '` should not coerce values to numbers', function() { - assert.strictEqual(func(['1', '2']), '12'); - }); - }); -}); diff --git a/test/sum-methods.spec.ts b/test/sum-methods.spec.ts new file mode 100644 index 000000000..8b7f8d7a2 --- /dev/null +++ b/test/sum-methods.spec.ts @@ -0,0 +1,34 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, empties, stubZero } from './utils'; + +describe('sum methods', () => { + lodashStable.each(['sum', 'sumBy'], (methodName) => { + const array = [6, 4, 2], + func = _[methodName]; + + it(`\`_.${methodName}\` should return the sum of an array of numbers`, () => { + assert.strictEqual(func(array), 12); + }); + + it(`\`_.${methodName}\` should return \`0\` when passing empty \`array\` values`, () => { + const expected = lodashStable.map(empties, stubZero); + + const actual = lodashStable.map(empties, (value) => func(value)); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should skip \`undefined\` values`, () => { + assert.strictEqual(func([1, undefined]), 1); + }); + + it(`\`_.${methodName}\` should not skip \`NaN\` values`, () => { + assert.deepStrictEqual(func([1, NaN]), NaN); + }); + + it(`\`_.${methodName}\` should not coerce values to numbers`, () => { + assert.strictEqual(func(['1', '2']), '12'); + }); + }); +}); diff --git a/test/sumBy.js b/test/sumBy.js deleted file mode 100644 index 62c780e58..000000000 --- a/test/sumBy.js +++ /dev/null @@ -1,32 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import sumBy from '../sumBy.js'; - -describe('sumBy', function() { - var array = [6, 4, 2], - objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; - - it('should work with an `iteratee`', function() { - var actual = sumBy(objects, function(object) { - return object.a; - }); - - assert.deepStrictEqual(actual, 6); - }); - - it('should provide correct `iteratee` arguments', function() { - var args; - - sumBy(array, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [6]); - }); - - it('should work with `_.property` shorthands', function() { - var arrays = [[2], [3], [1]]; - assert.strictEqual(sumBy(arrays, 0), 6); - assert.strictEqual(sumBy(objects, 'a'), 6); - }); -}); diff --git a/test/sumBy.spec.ts b/test/sumBy.spec.ts new file mode 100644 index 000000000..6748c1e4c --- /dev/null +++ b/test/sumBy.spec.ts @@ -0,0 +1,30 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import sumBy from '../src/sumBy'; + +describe('sumBy', () => { + const array = [6, 4, 2], + objects = [{ a: 2 }, { a: 3 }, { a: 1 }]; + + it('should work with an `iteratee`', () => { + const actual = sumBy(objects, (object) => object.a); + + assert.deepStrictEqual(actual, 6); + }); + + it('should provide correct `iteratee` arguments', () => { + let args; + + sumBy(array, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [6]); + }); + + it('should work with `_.property` shorthands', () => { + const arrays = [[2], [3], [1]]; + assert.strictEqual(sumBy(arrays, 0), 6); + assert.strictEqual(sumBy(objects, 'a'), 6); + }); +}); diff --git a/test/tail.js b/test/tail.js deleted file mode 100644 index 6fd325796..000000000 --- a/test/tail.js +++ /dev/null @@ -1,77 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, stubArray, LARGE_ARRAY_SIZE } from './utils.js'; -import tail from '../tail.js'; - -describe('tail', function() { - var array = [1, 2, 3]; - - it('should accept a falsey `array`', function() { - var expected = lodashStable.map(falsey, stubArray); - - var actual = lodashStable.map(falsey, function(array, index) { - try { - return index ? tail(array) : tail(); - } catch (e) {} - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should exclude the first element', function() { - assert.deepStrictEqual(tail(array), [2, 3]); - }); - - it('should return an empty when querying empty arrays', function() { - assert.deepStrictEqual(tail([]), []); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = lodashStable.map(array, tail); - - assert.deepStrictEqual(actual, [[2, 3], [5, 6], [8, 9]]); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE), - values = []; - - var actual = _(array).tail().filter(function(value) { - values.push(value); - return false; - }) - .value(); - - assert.deepEqual(actual, []); - assert.deepEqual(values, array.slice(1)); - - values = []; - - actual = _(array).filter(function(value) { - values.push(value); - return isEven(value); - }) - .tail() - .value(); - - assert.deepEqual(actual, tail(_.filter(array, isEven))); - assert.deepEqual(values, array); - }); - - it('should not execute subsequent iteratees on an empty array in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE), - iteratee = function() { pass = false; }, - pass = true, - actual = _(array).slice(0, 1).tail().map(iteratee).value(); - - assert.ok(pass); - assert.deepEqual(actual, []); - - pass = true; - actual = _(array).filter().slice(0, 1).tail().map(iteratee).value(); - - assert.ok(pass); - assert.deepEqual(actual, []); - }); -}); diff --git a/test/tail.spec.ts b/test/tail.spec.ts new file mode 100644 index 000000000..f25f1ee2d --- /dev/null +++ b/test/tail.spec.ts @@ -0,0 +1,90 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, stubArray, LARGE_ARRAY_SIZE } from './utils'; +import tail from '../src/tail'; + +describe('tail', () => { + const array = [1, 2, 3]; + + it('should accept a falsey `array`', () => { + const expected = lodashStable.map(falsey, stubArray); + + const actual = lodashStable.map(falsey, (array, index) => { + try { + return index ? tail(array) : tail(); + } catch (e) {} + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should exclude the first element', () => { + assert.deepStrictEqual(tail(array), [2, 3]); + }); + + it('should return an empty when querying empty arrays', () => { + assert.deepStrictEqual(tail([]), []); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + actual = lodashStable.map(array, tail); + + assert.deepStrictEqual(actual, [ + [2, 3], + [5, 6], + [8, 9], + ]); + }); + + it('should work in a lazy sequence', () => { + let array = lodashStable.range(LARGE_ARRAY_SIZE), + values = []; + + let actual = _(array) + .tail() + .filter((value) => { + values.push(value); + return false; + }) + .value(); + + assert.deepEqual(actual, []); + assert.deepEqual(values, array.slice(1)); + + values = []; + + actual = _(array) + .filter((value) => { + values.push(value); + return isEven(value); + }) + .tail() + .value(); + + assert.deepEqual(actual, tail(_.filter(array, isEven))); + assert.deepEqual(values, array); + }); + + it('should not execute subsequent iteratees on an empty array in a lazy sequence', () => { + var array = lodashStable.range(LARGE_ARRAY_SIZE), + iteratee = function () { + pass = false; + }, + pass = true, + actual = _(array).slice(0, 1).tail().map(iteratee).value(); + + assert.ok(pass); + assert.deepEqual(actual, []); + + pass = true; + actual = _(array).filter().slice(0, 1).tail().map(iteratee).value(); + + assert.ok(pass); + assert.deepEqual(actual, []); + }); +}); diff --git a/test/take.js b/test/take.js deleted file mode 100644 index 76690a58b..000000000 --- a/test/take.js +++ /dev/null @@ -1,65 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils.js'; -import take from '../take.js'; - -describe('take', function() { - var array = [1, 2, 3]; - - it('should take the first two elements', function() { - assert.deepStrictEqual(take(array, 2), [1, 2]); - }); - - it('should treat falsey `n` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? [1] : []; - }); - - var actual = lodashStable.map(falsey, function(n) { - return take(array, n); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return an empty array when `n` < `1`', function() { - lodashStable.each([0, -1, -Infinity], function(n) { - assert.deepStrictEqual(take(array, n), []); - }); - }); - - it('should return all elements when `n` >= `length`', function() { - lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - assert.deepStrictEqual(take(array, n), array); - }); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = lodashStable.map(array, take); - - assert.deepStrictEqual(actual, [[1], [4], [7]]); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), - predicate = function(value) { values.push(value); return isEven(value); }, - values = [], - actual = _(array).take(2).take().value(); - - assert.deepEqual(actual, take(take(array, 2))); - - actual = _(array).filter(predicate).take(2).take().value(); - assert.deepEqual(values, [1, 2]); - assert.deepEqual(actual, take(take(_.filter(array, predicate), 2))); - - actual = _(array).take(6).takeRight(4).take(2).takeRight().value(); - assert.deepEqual(actual, _.takeRight(take(_.takeRight(take(array, 6), 4), 2))); - - values = []; - - actual = _(array).take(array.length - 1).filter(predicate).take(6).takeRight(4).take(2).takeRight().value(); - assert.deepEqual(values, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); - assert.deepEqual(actual, _.takeRight(take(_.takeRight(take(_.filter(take(array, array.length - 1), predicate), 6), 4), 2))); - }); -}); diff --git a/test/take.spec.ts b/test/take.spec.ts new file mode 100644 index 000000000..0b68ad0cc --- /dev/null +++ b/test/take.spec.ts @@ -0,0 +1,83 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils'; +import take from '../src/take'; + +describe('take', () => { + const array = [1, 2, 3]; + + it('should take the first two elements', () => { + assert.deepStrictEqual(take(array, 2), [1, 2]); + }); + + it('should treat falsey `n` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, (value) => (value === undefined ? [1] : [])); + + const actual = lodashStable.map(falsey, (n) => take(array, n)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return an empty array when `n` < `1`', () => { + lodashStable.each([0, -1, -Infinity], (n) => { + assert.deepStrictEqual(take(array, n), []); + }); + }); + + it('should return all elements when `n` >= `length`', () => { + lodashStable.each([3, 4, 2 ** 32, Infinity], (n) => { + assert.deepStrictEqual(take(array, n), array); + }); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + actual = lodashStable.map(array, take); + + assert.deepStrictEqual(actual, [[1], [4], [7]]); + }); + + it('should work in a lazy sequence', () => { + var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), + predicate = function (value) { + values.push(value); + return isEven(value); + }, + values = [], + actual = _(array).take(2).take().value(); + + assert.deepEqual(actual, take(take(array, 2))); + + actual = _(array).filter(predicate).take(2).take().value(); + assert.deepEqual(values, [1, 2]); + assert.deepEqual(actual, take(take(_.filter(array, predicate), 2))); + + actual = _(array).take(6).takeRight(4).take(2).takeRight().value(); + assert.deepEqual(actual, _.takeRight(take(_.takeRight(take(array, 6), 4), 2))); + + values = []; + + actual = _(array) + .take(array.length - 1) + .filter(predicate) + .take(6) + .takeRight(4) + .take(2) + .takeRight() + .value(); + assert.deepEqual(values, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); + assert.deepEqual( + actual, + _.takeRight( + take( + _.takeRight(take(_.filter(take(array, array.length - 1), predicate), 6), 4), + 2, + ), + ), + ); + }); +}); diff --git a/test/takeRight.js b/test/takeRight.js deleted file mode 100644 index ee48abc80..000000000 --- a/test/takeRight.js +++ /dev/null @@ -1,65 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils.js'; -import takeRight from '../takeRight.js'; - -describe('takeRight', function() { - var array = [1, 2, 3]; - - it('should take the last two elements', function() { - assert.deepStrictEqual(takeRight(array, 2), [2, 3]); - }); - - it('should treat falsey `n` values, except `undefined`, as `0`', function() { - var expected = lodashStable.map(falsey, function(value) { - return value === undefined ? [3] : []; - }); - - var actual = lodashStable.map(falsey, function(n) { - return takeRight(array, n); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return an empty array when `n` < `1`', function() { - lodashStable.each([0, -1, -Infinity], function(n) { - assert.deepStrictEqual(takeRight(array, n), []); - }); - }); - - it('should return all elements when `n` >= `length`', function() { - lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - assert.deepStrictEqual(takeRight(array, n), array); - }); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = lodashStable.map(array, takeRight); - - assert.deepStrictEqual(actual, [[3], [6], [9]]); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE), - predicate = function(value) { values.push(value); return isEven(value); }, - values = [], - actual = _(array).takeRight(2).takeRight().value(); - - assert.deepEqual(actual, takeRight(takeRight(array))); - - actual = _(array).filter(predicate).takeRight(2).takeRight().value(); - assert.deepEqual(values, array); - assert.deepEqual(actual, takeRight(takeRight(_.filter(array, predicate), 2))); - - actual = _(array).takeRight(6).take(4).takeRight(2).take().value(); - assert.deepEqual(actual, _.take(takeRight(_.take(takeRight(array, 6), 4), 2))); - - values = []; - - actual = _(array).filter(predicate).takeRight(6).take(4).takeRight(2).take().value(); - assert.deepEqual(values, array); - assert.deepEqual(actual, _.take(takeRight(_.take(takeRight(_.filter(array, predicate), 6), 4), 2))); - }); -}); diff --git a/test/takeRight.spec.ts b/test/takeRight.spec.ts new file mode 100644 index 000000000..3b8111e78 --- /dev/null +++ b/test/takeRight.spec.ts @@ -0,0 +1,71 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils'; +import takeRight from '../src/takeRight'; + +describe('takeRight', () => { + const array = [1, 2, 3]; + + it('should take the last two elements', () => { + assert.deepStrictEqual(takeRight(array, 2), [2, 3]); + }); + + it('should treat falsey `n` values, except `undefined`, as `0`', () => { + const expected = lodashStable.map(falsey, (value) => (value === undefined ? [3] : [])); + + const actual = lodashStable.map(falsey, (n) => takeRight(array, n)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return an empty array when `n` < `1`', () => { + lodashStable.each([0, -1, -Infinity], (n) => { + assert.deepStrictEqual(takeRight(array, n), []); + }); + }); + + it('should return all elements when `n` >= `length`', () => { + lodashStable.each([3, 4, 2 ** 32, Infinity], (n) => { + assert.deepStrictEqual(takeRight(array, n), array); + }); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + actual = lodashStable.map(array, takeRight); + + assert.deepStrictEqual(actual, [[3], [6], [9]]); + }); + + it('should work in a lazy sequence', () => { + var array = lodashStable.range(LARGE_ARRAY_SIZE), + predicate = function (value) { + values.push(value); + return isEven(value); + }, + values = [], + actual = _(array).takeRight(2).takeRight().value(); + + assert.deepEqual(actual, takeRight(takeRight(array))); + + actual = _(array).filter(predicate).takeRight(2).takeRight().value(); + assert.deepEqual(values, array); + assert.deepEqual(actual, takeRight(takeRight(_.filter(array, predicate), 2))); + + actual = _(array).takeRight(6).take(4).takeRight(2).take().value(); + assert.deepEqual(actual, _.take(takeRight(_.take(takeRight(array, 6), 4), 2))); + + values = []; + + actual = _(array).filter(predicate).takeRight(6).take(4).takeRight(2).take().value(); + assert.deepEqual(values, array); + assert.deepEqual( + actual, + _.take(takeRight(_.take(takeRight(_.filter(array, predicate), 6), 4), 2)), + ); + }); +}); diff --git a/test/takeRightWhile.js b/test/takeRightWhile.js deleted file mode 100644 index d080e0c60..000000000 --- a/test/takeRightWhile.js +++ /dev/null @@ -1,96 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, LARGE_ARRAY_SIZE } from './utils.js'; -import takeRightWhile from '../takeRightWhile.js'; - -describe('takeRightWhile', function() { - var array = [1, 2, 3, 4]; - - var objects = [ - { 'a': 0, 'b': 0 }, - { 'a': 1, 'b': 1 }, - { 'a': 2, 'b': 2 } - ]; - - it('should take elements while `predicate` returns truthy', function() { - var actual = takeRightWhile(array, function(n) { - return n > 2; - }); - - assert.deepStrictEqual(actual, [3, 4]); - }); - - it('should provide correct `predicate` arguments', function() { - var args; - - takeRightWhile(array, function() { - args = slice.call(arguments); - }); - - assert.deepStrictEqual(args, [4, 3, array]); - }); - - it('should work with `_.matches` shorthands', function() { - assert.deepStrictEqual(takeRightWhile(objects, { 'b': 2 }), objects.slice(2)); - }); - - it('should work with `_.matchesProperty` shorthands', function() { - assert.deepStrictEqual(takeRightWhile(objects, ['b', 2]), objects.slice(2)); - }); - - it('should work with `_.property` shorthands', function() { - assert.deepStrictEqual(takeRightWhile(objects, 'b'), objects.slice(1)); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE), - predicate = function(n) { return n > 2; }, - expected = takeRightWhile(array, predicate), - wrapped = _(array).takeRightWhile(predicate); - - assert.deepEqual(wrapped.value(), expected); - assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); - assert.strictEqual(wrapped.last(), _.last(expected)); - }); - - it('should provide correct `predicate` arguments in a lazy sequence', function() { - var args, - array = lodashStable.range(LARGE_ARRAY_SIZE + 1); - - var expected = [ - square(LARGE_ARRAY_SIZE), - LARGE_ARRAY_SIZE - 1, - lodashStable.map(array.slice(1), square) - ]; - - _(array).slice(1).takeRightWhile(function(value, index, array) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, [LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE - 1, array.slice(1)]); - - _(array).slice(1).map(square).takeRightWhile(function(value, index, array) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - - _(array).slice(1).map(square).takeRightWhile(function(value, index) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - - _(array).slice(1).map(square).takeRightWhile(function(index) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, [square(LARGE_ARRAY_SIZE)]); - - _(array).slice(1).map(square).takeRightWhile(function() { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - }); -}); diff --git a/test/takeRightWhile.spec.ts b/test/takeRightWhile.spec.ts new file mode 100644 index 000000000..d8b769c4a --- /dev/null +++ b/test/takeRightWhile.spec.ts @@ -0,0 +1,115 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, LARGE_ARRAY_SIZE } from './utils'; +import takeRightWhile from '../src/takeRightWhile'; + +describe('takeRightWhile', () => { + const array = [1, 2, 3, 4]; + + const objects = [ + { a: 0, b: 0 }, + { a: 1, b: 1 }, + { a: 2, b: 2 }, + ]; + + it('should take elements while `predicate` returns truthy', () => { + const actual = takeRightWhile(array, (n) => n > 2); + + assert.deepStrictEqual(actual, [3, 4]); + }); + + it('should provide correct `predicate` arguments', () => { + let args; + + takeRightWhile(array, function () { + args = slice.call(arguments); + }); + + assert.deepStrictEqual(args, [4, 3, array]); + }); + + it('should work with `_.matches` shorthands', () => { + assert.deepStrictEqual(takeRightWhile(objects, { b: 2 }), objects.slice(2)); + }); + + it('should work with `_.matchesProperty` shorthands', () => { + assert.deepStrictEqual(takeRightWhile(objects, ['b', 2]), objects.slice(2)); + }); + + it('should work with `_.property` shorthands', () => { + assert.deepStrictEqual(takeRightWhile(objects, 'b'), objects.slice(1)); + }); + + it('should work in a lazy sequence', () => { + const array = lodashStable.range(LARGE_ARRAY_SIZE), + predicate = function (n) { + return n > 2; + }, + expected = takeRightWhile(array, predicate), + wrapped = _(array).takeRightWhile(predicate); + + assert.deepEqual(wrapped.value(), expected); + assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); + assert.strictEqual(wrapped.last(), _.last(expected)); + }); + + it('should provide correct `predicate` arguments in a lazy sequence', () => { + let args, + array = lodashStable.range(LARGE_ARRAY_SIZE + 1); + + const expected = [ + square(LARGE_ARRAY_SIZE), + LARGE_ARRAY_SIZE - 1, + lodashStable.map(array.slice(1), square), + ]; + + _(array) + .slice(1) + .takeRightWhile(function (value, index, array) { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, [LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE - 1, array.slice(1)]); + + _(array) + .slice(1) + .map(square) + .takeRightWhile(function (value, index, array) { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, expected); + + _(array) + .slice(1) + .map(square) + .takeRightWhile(function (value, index) { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, expected); + + _(array) + .slice(1) + .map(square) + .takeRightWhile(function (index) { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, [square(LARGE_ARRAY_SIZE)]); + + _(array) + .slice(1) + .map(square) + .takeRightWhile(function () { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, expected); + }); +}); diff --git a/test/takeWhile.js b/test/takeWhile.js deleted file mode 100644 index 43d1b10d9..000000000 --- a/test/takeWhile.js +++ /dev/null @@ -1,102 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, LARGE_ARRAY_SIZE, square } from './utils.js'; -import takeWhile from '../takeWhile.js'; - -describe('takeWhile', function() { - var array = [1, 2, 3, 4]; - - var objects = [ - { 'a': 2, 'b': 2 }, - { 'a': 1, 'b': 1 }, - { 'a': 0, 'b': 0 } - ]; - - it('should take elements while `predicate` returns truthy', function() { - var actual = takeWhile(array, function(n) { - return n < 3; - }); - - assert.deepStrictEqual(actual, [1, 2]); - }); - - it('should provide correct `predicate` arguments', function() { - var args; - - takeWhile(array, function() { - args = slice.call(arguments); - }); - - assert.deepStrictEqual(args, [1, 0, array]); - }); - - it('should work with `_.matches` shorthands', function() { - assert.deepStrictEqual(takeWhile(objects, { 'b': 2 }), objects.slice(0, 1)); - }); - - it('should work with `_.matchesProperty` shorthands', function() { - assert.deepStrictEqual(takeWhile(objects, ['b', 2]), objects.slice(0, 1)); - }); - it('should work with `_.property` shorthands', function() { - assert.deepStrictEqual(takeWhile(objects, 'b'), objects.slice(0, 2)); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE), - predicate = function(n) { return n < 3; }, - expected = takeWhile(array, predicate), - wrapped = _(array).takeWhile(predicate); - - assert.deepEqual(wrapped.value(), expected); - assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); - assert.strictEqual(wrapped.last(), _.last(expected)); - }); - - it('should work in a lazy sequence with `take`', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE); - - var actual = _(array) - .takeWhile(function(n) { return n < 4; }) - .take(2) - .takeWhile(function(n) { return n == 0; }) - .value(); - - assert.deepEqual(actual, [0]); - }); - - it('should provide correct `predicate` arguments in a lazy sequence', function() { - var args, - array = lodashStable.range(LARGE_ARRAY_SIZE + 1), - expected = [1, 0, lodashStable.map(array.slice(1), square)]; - - _(array).slice(1).takeWhile(function(value, index, array) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, [1, 0, array.slice(1)]); - - _(array).slice(1).map(square).takeWhile(function(value, index, array) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - - _(array).slice(1).map(square).takeWhile(function(value, index) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - - _(array).slice(1).map(square).takeWhile(function(value) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, [1]); - - _(array).slice(1).map(square).takeWhile(function() { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - }); -}); diff --git a/test/takeWhile.spec.ts b/test/takeWhile.spec.ts new file mode 100644 index 000000000..1b8c999f2 --- /dev/null +++ b/test/takeWhile.spec.ts @@ -0,0 +1,121 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, LARGE_ARRAY_SIZE, square } from './utils'; +import takeWhile from '../src/takeWhile'; + +describe('takeWhile', () => { + const array = [1, 2, 3, 4]; + + const objects = [ + { a: 2, b: 2 }, + { a: 1, b: 1 }, + { a: 0, b: 0 }, + ]; + + it('should take elements while `predicate` returns truthy', () => { + const actual = takeWhile(array, (n) => n < 3); + + assert.deepStrictEqual(actual, [1, 2]); + }); + + it('should provide correct `predicate` arguments', () => { + let args; + + takeWhile(array, function () { + args = slice.call(arguments); + }); + + assert.deepStrictEqual(args, [1, 0, array]); + }); + + it('should work with `_.matches` shorthands', () => { + assert.deepStrictEqual(takeWhile(objects, { b: 2 }), objects.slice(0, 1)); + }); + + it('should work with `_.matchesProperty` shorthands', () => { + assert.deepStrictEqual(takeWhile(objects, ['b', 2]), objects.slice(0, 1)); + }); + it('should work with `_.property` shorthands', () => { + assert.deepStrictEqual(takeWhile(objects, 'b'), objects.slice(0, 2)); + }); + + it('should work in a lazy sequence', () => { + const array = lodashStable.range(LARGE_ARRAY_SIZE), + predicate = function (n) { + return n < 3; + }, + expected = takeWhile(array, predicate), + wrapped = _(array).takeWhile(predicate); + + assert.deepEqual(wrapped.value(), expected); + assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); + assert.strictEqual(wrapped.last(), _.last(expected)); + }); + + it('should work in a lazy sequence with `take`', () => { + const array = lodashStable.range(LARGE_ARRAY_SIZE); + + const actual = _(array) + .takeWhile((n) => n < 4) + .take(2) + .takeWhile((n) => n == 0) + .value(); + + assert.deepEqual(actual, [0]); + }); + + it('should provide correct `predicate` arguments in a lazy sequence', () => { + let args, + array = lodashStable.range(LARGE_ARRAY_SIZE + 1), + expected = [1, 0, lodashStable.map(array.slice(1), square)]; + + _(array) + .slice(1) + .takeWhile(function (value, index, array) { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, [1, 0, array.slice(1)]); + + _(array) + .slice(1) + .map(square) + .takeWhile(function (value, index, array) { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, expected); + + _(array) + .slice(1) + .map(square) + .takeWhile(function (value, index) { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, expected); + + _(array) + .slice(1) + .map(square) + .takeWhile(function (value) { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, [1]); + + _(array) + .slice(1) + .map(square) + .takeWhile(function () { + args = slice.call(arguments); + }) + .value(); + + assert.deepEqual(args, expected); + }); +}); diff --git a/test/tap.js b/test/tap.js deleted file mode 100644 index d50fa573c..000000000 --- a/test/tap.js +++ /dev/null @@ -1,30 +0,0 @@ -import assert from 'assert'; - -describe('tap', function() { - it('should intercept and return the given value', function() { - var intercepted, - array = [1, 2, 3]; - - var actual = _.tap(array, function(value) { - intercepted = value; - }); - - assert.strictEqual(actual, array); - assert.strictEqual(intercepted, array); - }); - - it('should intercept unwrapped values and return wrapped values when chaining', function() { - var intercepted, - array = [1, 2, 3]; - - var wrapped = _(array).tap(function(value) { - intercepted = value; - value.pop(); - }); - - assert.ok(wrapped instanceof _); - - wrapped.value(); - assert.strictEqual(intercepted, array); - }); -}); diff --git a/test/tap.spec.ts b/test/tap.spec.ts new file mode 100644 index 000000000..19fae27ed --- /dev/null +++ b/test/tap.spec.ts @@ -0,0 +1,30 @@ +import assert from 'node:assert'; + +describe('tap', () => { + it('should intercept and return the given value', () => { + let intercepted, + array = [1, 2, 3]; + + const actual = _.tap(array, (value) => { + intercepted = value; + }); + + assert.strictEqual(actual, array); + assert.strictEqual(intercepted, array); + }); + + it('should intercept unwrapped values and return wrapped values when chaining', () => { + let intercepted, + array = [1, 2, 3]; + + const wrapped = _(array).tap((value) => { + intercepted = value; + value.pop(); + }); + + assert.ok(wrapped instanceof _); + + wrapped.value(); + assert.strictEqual(intercepted, array); + }); +}); diff --git a/test/template.js b/test/template.js deleted file mode 100644 index 01308dbce..000000000 --- a/test/template.js +++ /dev/null @@ -1,451 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { numberTag, stubString, stubTrue, stubFalse } from './utils.js'; -import template from '../template.js'; -import templateSettings from '../templateSettings.js'; - -describe('template', function() { - it('should escape values in "escape" delimiters', function() { - var strings = ['

<%- value %>

', '

<%-value%>

', '

<%-\nvalue\n%>

'], - expected = lodashStable.map(strings, lodashStable.constant('

&<>"'/

')), - data = { 'value': '&<>"\'/' }; - - var actual = lodashStable.map(strings, function(string) { - return template(string)(data); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should not reference `_.escape` when "escape" delimiters are not used', function() { - var compiled = template('<%= typeof __e %>'); - assert.strictEqual(compiled({}), 'undefined'); - }); - - it('should evaluate JavaScript in "evaluate" delimiters', function() { - var compiled = template( - '' - ); - - var data = { 'collection': { 'a': 'A', 'b': 'B' } }, - actual = compiled(data); - - assert.strictEqual(actual, ''); - }); - - it('should support "evaluate" delimiters with single line comments (test production builds)', function() { - var compiled = template('<% // A code comment. %><% if (value) { %>yap<% } else { %>nope<% } %>'), - data = { 'value': true }; - - assert.strictEqual(compiled(data), 'yap'); - }); - - it('should support referencing variables declared in "evaluate" delimiters from other delimiters', function() { - var compiled = template('<% var b = a; %><%= b.value %>'), - data = { 'a': { 'value': 1 } }; - - assert.strictEqual(compiled(data), '1'); - }); - - it('should interpolate data properties in "interpolate" delimiters', function() { - var strings = ['<%= a %>BC', '<%=a%>BC', '<%=\na\n%>BC'], - expected = lodashStable.map(strings, lodashStable.constant('ABC')), - data = { 'a': 'A' }; - - var actual = lodashStable.map(strings, function(string) { - return template(string)(data); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should support "interpolate" delimiters with escaped values', function() { - var compiled = template('<%= a ? "a=\\"A\\"" : "" %>'), - data = { 'a': true }; - - assert.strictEqual(compiled(data), 'a="A"'); - }); - - it('should support "interpolate" delimiters containing ternary operators', function() { - var compiled = template('<%= value ? value : "b" %>'), - data = { 'value': 'a' }; - - assert.strictEqual(compiled(data), 'a'); - }); - - it('should support "interpolate" delimiters containing global values', function() { - var compiled = template('<%= typeof Math.abs %>'); - - try { - var actual = compiled(); - } catch (e) {} - - assert.strictEqual(actual, 'function'); - }); - - it('should support complex "interpolate" delimiters', function() { - lodashStable.forOwn({ - '<%= a + b %>': '3', - '<%= b - a %>': '1', - '<%= a = b %>': '2', - '<%= !a %>': 'false', - '<%= ~a %>': '-2', - '<%= a * b %>': '2', - '<%= a / b %>': '0.5', - '<%= a % b %>': '1', - '<%= a >> b %>': '0', - '<%= a << b %>': '4', - '<%= a & b %>': '0', - '<%= a ^ b %>': '3', - '<%= a | b %>': '3', - '<%= {}.toString.call(0) %>': numberTag, - '<%= a.toFixed(2) %>': '1.00', - '<%= obj["a"] %>': '1', - '<%= delete a %>': 'true', - '<%= "a" in obj %>': 'true', - '<%= obj instanceof Object %>': 'true', - '<%= new Boolean %>': 'false', - '<%= typeof a %>': 'number', - '<%= void a %>': '' - }, - function(value, key) { - var compiled = template(key), - data = { 'a': 1, 'b': 2 }; - - assert.strictEqual(compiled(data), value, key); - }); - }); - - it('should support ES6 template delimiters', function() { - var data = { 'value': 2 }; - assert.strictEqual(template('1${value}3')(data), '123'); - assert.strictEqual(template('${"{" + value + "\\}"}')(data), '{2}'); - }); - - it('should support the "imports" option', function() { - var compiled = template('<%= a %>', { 'imports': { 'a': 1 } }); - assert.strictEqual(compiled({}), '1'); - }); - - it('should support the "variable" options', function() { - var compiled = template( - '<% _.each( data.a, function( value ) { %>' + - '<%= value.valueOf() %>' + - '<% }) %>', { 'variable': 'data' } - ); - - var data = { 'a': [1, 2, 3] }; - - try { - assert.strictEqual(compiled(data), '123'); - } catch (e) { - assert.ok(false, e.message); - } - }); - - it('should support custom delimiters', function() { - lodashStable.times(2, function(index) { - var settingsClone = lodashStable.clone(templateSettings); - - var settings = lodashStable.assign(index ? templateSettings : {}, { - 'escape': /\{\{-([\s\S]+?)\}\}/g, - 'evaluate': /\{\{([\s\S]+?)\}\}/g, - 'interpolate': /\{\{=([\s\S]+?)\}\}/g - }); - - var expected = '', - compiled = template('', index ? null : settings), - data = { 'collection': ['a & A', 'b & B'] }; - - assert.strictEqual(compiled(data), expected); - lodashStable.assign(templateSettings, settingsClone); - }); - }); - - it('should support custom delimiters containing special characters', function() { - lodashStable.times(2, function(index) { - var settingsClone = lodashStable.clone(templateSettings); - - var settings = lodashStable.assign(index ? templateSettings : {}, { - 'escape': /<\?-([\s\S]+?)\?>/g, - 'evaluate': /<\?([\s\S]+?)\?>/g, - 'interpolate': /<\?=([\s\S]+?)\?>/g - }); - - var expected = '', - compiled = template('', index ? null : settings), - data = { 'collection': ['a & A', 'b & B'] }; - - assert.strictEqual(compiled(data), expected); - lodashStable.assign(templateSettings, settingsClone); - }); - }); - - it('should use a `with` statement by default', function() { - var compiled = template('<%= index %><%= collection[index] %><% _.each(collection, function(value, index) { %><%= index %><% }); %>'), - actual = compiled({ 'index': 1, 'collection': ['a', 'b', 'c'] }); - - assert.strictEqual(actual, '1b012'); - }); - - it('should use `_.templateSettings.imports._.templateSettings`', function() { - var lodash = templateSettings.imports._, - settingsClone = lodashStable.clone(lodash.templateSettings); - - lodash.templateSettings = lodashStable.assign(lodash.templateSettings, { - 'interpolate': /\{\{=([\s\S]+?)\}\}/g - }); - - var compiled = template('{{= a }}'); - assert.strictEqual(compiled({ 'a': 1 }), '1'); - - if (settingsClone) { - lodashStable.assign(lodash.templateSettings, settingsClone); - } else { - delete lodash.templateSettings; - } - }); - - it('should fallback to `_.templateSettings`', function() { - var lodash = templateSettings.imports._, - delimiter = templateSettings.interpolate; - - templateSettings.imports._ = { 'escape': lodashStable.escape }; - templateSettings.interpolate = /\{\{=([\s\S]+?)\}\}/g; - - var compiled = template('{{= a }}'); - assert.strictEqual(compiled({ 'a': 1 }), '1'); - - templateSettings.imports._ = lodash; - templateSettings.interpolate = delimiter; - }); - - it('should ignore `null` delimiters', function() { - var delimiter = { - 'escape': /\{\{-([\s\S]+?)\}\}/g, - 'evaluate': /\{\{([\s\S]+?)\}\}/g, - 'interpolate': /\{\{=([\s\S]+?)\}\}/g - }; - - lodashStable.forOwn({ - 'escape': '{{- a }}', - 'evaluate': '{{ print(a) }}', - 'interpolate': '{{= a }}' - }, - function(value, key) { - var settings = { 'escape': null, 'evaluate': null, 'interpolate': null }; - settings[key] = delimiter[key]; - - var expected = '1 <%- a %> <% print(a) %> <%= a %>', - compiled = template(value + ' <%- a %> <% print(a) %> <%= a %>', settings), - data = { 'a': 1 }; - - assert.strictEqual(compiled(data), expected); - }); - }); - - it('should work without delimiters', function() { - var expected = 'abc'; - assert.strictEqual(template(expected)({}), expected); - }); - - it('should work with `this` references', function() { - var compiled = template('a<%= this.String("b") %>c'); - assert.strictEqual(compiled(), 'abc'); - - var object = { 'b': 'B' }; - object.compiled = template('A<%= this.b %>C', { 'variable': 'obj' }); - assert.strictEqual(object.compiled(), 'ABC'); - }); - - it('should work with backslashes', function() { - var compiled = template('<%= a %> \\b'), - data = { 'a': 'A' }; - - assert.strictEqual(compiled(data), 'A \\b'); - }); - - it('should work with escaped characters in string literals', function() { - var compiled = template('<% print("\'\\n\\r\\t\\u2028\\u2029\\\\") %>'); - assert.strictEqual(compiled(), "'\n\r\t\u2028\u2029\\"); - - var data = { 'a': 'A' }; - compiled = template('\'\n\r\t<%= a %>\u2028\u2029\\"'); - assert.strictEqual(compiled(data), '\'\n\r\tA\u2028\u2029\\"'); - }); - - it('should handle \\u2028 & \\u2029 characters', function() { - var compiled = template('\u2028<%= "\\u2028\\u2029" %>\u2029'); - assert.strictEqual(compiled(), '\u2028\u2028\u2029\u2029'); - }); - - it('should work with statements containing quotes', function() { - var compiled = template("<%\ - if (a == 'A' || a == \"a\") {\ - %>'a',\"A\"<%\ - } %>" - ); - - var data = { 'a': 'A' }; - assert.strictEqual(compiled(data), "'a',\"A\""); - }); - - it('should work with templates containing newlines and comments', function() { - var compiled = template('<%\n\ - // A code comment.\n\ - if (value) { value += 3; }\n\ - %>

<%= value %>

' - ); - - assert.strictEqual(compiled({ 'value': 3 }), '

6

'); - }); - - it('should tokenize delimiters', function() { - var compiled = template(''), - data = { 'type': 1 }; - - assert.strictEqual(compiled(data), ''); - }); - - it('should evaluate delimiters once', function() { - var actual = [], - compiled = template('<%= func("a") %><%- func("b") %><% func("c") %>'), - data = { 'func': function(value) { actual.push(value); } }; - - compiled(data); - assert.deepStrictEqual(actual, ['a', 'b', 'c']); - }); - - it('should match delimiters before escaping text', function() { - var compiled = template('<<\n a \n>>', { 'evaluate': /<<(.*?)>>/g }); - assert.strictEqual(compiled(), '<<\n a \n>>'); - }); - - it('should resolve nullish values to an empty string', function() { - var compiled = template('<%= a %><%- a %>'), - data = { 'a': null }; - - assert.strictEqual(compiled(data), ''); - - data = { 'a': undefined }; - assert.strictEqual(compiled(data), ''); - - data = { 'a': {} }; - compiled = template('<%= a.b %><%- a.b %>'); - assert.strictEqual(compiled(data), ''); - }); - - it('should return an empty string for empty values', function() { - var values = [, null, undefined, ''], - expected = lodashStable.map(values, stubString), - data = { 'a': 1 }; - - var actual = lodashStable.map(values, function(value, index) { - var compiled = index ? template(value) : template(); - return compiled(data); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should parse delimiters without newlines', function() { - var expected = '<<\nprint("

" + (value ? "yes" : "no") + "

")\n>>', - compiled = template(expected, { 'evaluate': /<<(.+?)>>/g }), - data = { 'value': true }; - - assert.strictEqual(compiled(data), expected); - }); - - it('should support recursive calls', function() { - var compiled = template('<%= a %><% a = _.template(c)(obj) %><%= a %>'), - data = { 'a': 'A', 'b': 'B', 'c': '<%= b %>' }; - - assert.strictEqual(compiled(data), 'AB'); - }); - - it('should coerce `text` to a string', function() { - var object = { 'toString': lodashStable.constant('<%= a %>') }, - data = { 'a': 1 }; - - assert.strictEqual(template(object)(data), '1'); - }); - - it('should not modify the `options` object', function() { - var options = {}; - template('', options); - assert.deepStrictEqual(options, {}); - }); - - it('should not modify `_.templateSettings` when `options` are given', function() { - var data = { 'a': 1 }; - - assert.ok(!('a' in templateSettings)); - template('', {}, data); - assert.ok(!('a' in templateSettings)); - - delete templateSettings.a; - }); - - it('should not error for non-object `data` and `options` values', function() { - template('')(1); - assert.ok(true, '`data` value'); - - template('', 1)(1); - assert.ok(true, '`options` value'); - }); - - it('should expose the source on compiled templates', function() { - var compiled = template('x'), - values = [String(compiled), compiled.source], - expected = lodashStable.map(values, stubTrue); - - var actual = lodashStable.map(values, function(value) { - return lodashStable.includes(value, '__p'); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should expose the source on SyntaxErrors', function() { - try { - template('<% if x %>'); - } catch (e) { - var source = e.source; - } - assert.ok(lodashStable.includes(source, '__p')); - }); - - it('should not include sourceURLs in the source', function() { - var options = { 'sourceURL': '/a/b/c' }, - compiled = template('x', options), - values = [compiled.source, undefined]; - - try { - template('<% if x %>', options); - } catch (e) { - values[1] = e.source; - } - var expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(values, function(value) { - return lodashStable.includes(value, 'sourceURL'); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var array = ['<%= a %>', '<%- b %>', '<% print(c) %>'], - compiles = lodashStable.map(array, template), - data = { 'a': 'one', 'b': '"two"', 'c': 'three' }; - - var actual = lodashStable.map(compiles, function(compiled) { - return compiled(data); - }); - - assert.deepStrictEqual(actual, ['one', '"two"', 'three']); - }); -}); diff --git a/test/template.spec.ts b/test/template.spec.ts new file mode 100644 index 000000000..f405a3e6e --- /dev/null +++ b/test/template.spec.ts @@ -0,0 +1,465 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { numberTag, stubString, stubTrue, stubFalse } from './utils'; +import template from '../src/template'; +import templateSettings from '../src/templateSettings'; + +describe('template', () => { + it('should escape values in "escape" delimiters', () => { + const strings = ['

<%- value %>

', '

<%-value%>

', '

<%-\nvalue\n%>

'], + expected = lodashStable.map( + strings, + lodashStable.constant('

&<>"'/

'), + ), + data = { value: '&<>"\'/' }; + + const actual = lodashStable.map(strings, (string) => template(string)(data)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should not reference `_.escape` when "escape" delimiters are not used', () => { + const compiled = template('<%= typeof __e %>'); + assert.strictEqual(compiled({}), 'undefined'); + }); + + it('should evaluate JavaScript in "evaluate" delimiters', () => { + const compiled = template( + '', + ); + + const data = { collection: { a: 'A', b: 'B' } }, + actual = compiled(data); + + assert.strictEqual(actual, ''); + }); + + it('should support "evaluate" delimiters with single line comments (test production builds)', () => { + const compiled = template( + '<% // A code comment. %><% if (value) { %>yap<% } else { %>nope<% } %>', + ), + data = { value: true }; + + assert.strictEqual(compiled(data), 'yap'); + }); + + it('should support referencing variables declared in "evaluate" delimiters from other delimiters', () => { + const compiled = template('<% var b = a; %><%= b.value %>'), + data = { a: { value: 1 } }; + + assert.strictEqual(compiled(data), '1'); + }); + + it('should interpolate data properties in "interpolate" delimiters', () => { + const strings = ['<%= a %>BC', '<%=a%>BC', '<%=\na\n%>BC'], + expected = lodashStable.map(strings, lodashStable.constant('ABC')), + data = { a: 'A' }; + + const actual = lodashStable.map(strings, (string) => template(string)(data)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should support "interpolate" delimiters with escaped values', () => { + const compiled = template('<%= a ? "a=\\"A\\"" : "" %>'), + data = { a: true }; + + assert.strictEqual(compiled(data), 'a="A"'); + }); + + it('should support "interpolate" delimiters containing ternary operators', () => { + const compiled = template('<%= value ? value : "b" %>'), + data = { value: 'a' }; + + assert.strictEqual(compiled(data), 'a'); + }); + + it('should support "interpolate" delimiters containing global values', () => { + const compiled = template('<%= typeof Math.abs %>'); + + try { + var actual = compiled(); + } catch (e) {} + + assert.strictEqual(actual, 'function'); + }); + + it('should support complex "interpolate" delimiters', () => { + lodashStable.forOwn( + { + '<%= a + b %>': '3', + '<%= b - a %>': '1', + '<%= a = b %>': '2', + '<%= !a %>': 'false', + '<%= ~a %>': '-2', + '<%= a * b %>': '2', + '<%= a / b %>': '0.5', + '<%= a % b %>': '1', + '<%= a >> b %>': '0', + '<%= a << b %>': '4', + '<%= a & b %>': '0', + '<%= a ^ b %>': '3', + '<%= a | b %>': '3', + '<%= {}.toString.call(0) %>': numberTag, + '<%= a.toFixed(2) %>': '1.00', + '<%= obj["a"] %>': '1', + '<%= delete a %>': 'true', + '<%= "a" in obj %>': 'true', + '<%= obj instanceof Object %>': 'true', + '<%= new Boolean %>': 'false', + '<%= typeof a %>': 'number', + '<%= void a %>': '', + }, + (value, key) => { + const compiled = template(key), + data = { a: 1, b: 2 }; + + assert.strictEqual(compiled(data), value, key); + }, + ); + }); + + it('should support ES6 template delimiters', () => { + const data = { value: 2 }; + assert.strictEqual(template('1${value}3')(data), '123'); + assert.strictEqual(template('${"{" + value + "\\}"}')(data), '{2}'); + }); + + it('should support the "imports" option', () => { + const compiled = template('<%= a %>', { imports: { a: 1 } }); + assert.strictEqual(compiled({}), '1'); + }); + + it('should support the "variable" options', () => { + const compiled = template( + '<% _.each( data.a, function( value ) { %>' + '<%= value.valueOf() %>' + '<% }) %>', + { variable: 'data' }, + ); + + const data = { a: [1, 2, 3] }; + + try { + assert.strictEqual(compiled(data), '123'); + } catch (e) { + assert.ok(false, e.message); + } + }); + + it('should support custom delimiters', () => { + lodashStable.times(2, (index) => { + const settingsClone = lodashStable.clone(templateSettings); + + const settings = lodashStable.assign(index ? templateSettings : {}, { + escape: /\{\{-([\s\S]+?)\}\}/g, + evaluate: /\{\{([\s\S]+?)\}\}/g, + interpolate: /\{\{=([\s\S]+?)\}\}/g, + }); + + const expected = '', + compiled = template( + '', + index ? null : settings, + ), + data = { collection: ['a & A', 'b & B'] }; + + assert.strictEqual(compiled(data), expected); + lodashStable.assign(templateSettings, settingsClone); + }); + }); + + it('should support custom delimiters containing special characters', () => { + lodashStable.times(2, (index) => { + const settingsClone = lodashStable.clone(templateSettings); + + const settings = lodashStable.assign(index ? templateSettings : {}, { + escape: /<\?-([\s\S]+?)\?>/g, + evaluate: /<\?([\s\S]+?)\?>/g, + interpolate: /<\?=([\s\S]+?)\?>/g, + }); + + const expected = '', + compiled = template( + '', + index ? null : settings, + ), + data = { collection: ['a & A', 'b & B'] }; + + assert.strictEqual(compiled(data), expected); + lodashStable.assign(templateSettings, settingsClone); + }); + }); + + it('should use a `with` statement by default', () => { + const compiled = template( + '<%= index %><%= collection[index] %><% _.each(collection, function(value, index) { %><%= index %><% }); %>', + ), + actual = compiled({ index: 1, collection: ['a', 'b', 'c'] }); + + assert.strictEqual(actual, '1b012'); + }); + + it('should use `_.templateSettings.imports._.templateSettings`', () => { + const lodash = templateSettings.imports._, + settingsClone = lodashStable.clone(lodash.templateSettings); + + lodash.templateSettings = lodashStable.assign(lodash.templateSettings, { + interpolate: /\{\{=([\s\S]+?)\}\}/g, + }); + + const compiled = template('{{= a }}'); + assert.strictEqual(compiled({ a: 1 }), '1'); + + if (settingsClone) { + lodashStable.assign(lodash.templateSettings, settingsClone); + } else { + delete lodash.templateSettings; + } + }); + + it('should fallback to `_.templateSettings`', () => { + const lodash = templateSettings.imports._, + delimiter = templateSettings.interpolate; + + templateSettings.imports._ = { escape: lodashStable.escape }; + templateSettings.interpolate = /\{\{=([\s\S]+?)\}\}/g; + + const compiled = template('{{= a }}'); + assert.strictEqual(compiled({ a: 1 }), '1'); + + templateSettings.imports._ = lodash; + templateSettings.interpolate = delimiter; + }); + + it('should ignore `null` delimiters', () => { + const delimiter = { + escape: /\{\{-([\s\S]+?)\}\}/g, + evaluate: /\{\{([\s\S]+?)\}\}/g, + interpolate: /\{\{=([\s\S]+?)\}\}/g, + }; + + lodashStable.forOwn( + { + escape: '{{- a }}', + evaluate: '{{ print(a) }}', + interpolate: '{{= a }}', + }, + (value, key) => { + const settings = { escape: null, evaluate: null, interpolate: null }; + settings[key] = delimiter[key]; + + const expected = '1 <%- a %> <% print(a) %> <%= a %>', + compiled = template(`${value} <%- a %> <% print(a) %> <%= a %>`, settings), + data = { a: 1 }; + + assert.strictEqual(compiled(data), expected); + }, + ); + }); + + it('should work without delimiters', () => { + const expected = 'abc'; + assert.strictEqual(template(expected)({}), expected); + }); + + it('should work with `this` references', () => { + const compiled = template('a<%= this.String("b") %>c'); + assert.strictEqual(compiled(), 'abc'); + + const object = { b: 'B' }; + object.compiled = template('A<%= this.b %>C', { variable: 'obj' }); + assert.strictEqual(object.compiled(), 'ABC'); + }); + + it('should work with backslashes', () => { + const compiled = template('<%= a %> \\b'), + data = { a: 'A' }; + + assert.strictEqual(compiled(data), 'A \\b'); + }); + + it('should work with escaped characters in string literals', () => { + let compiled = template('<% print("\'\\n\\r\\t\\u2028\\u2029\\\\") %>'); + assert.strictEqual(compiled(), "'\n\r\t\u2028\u2029\\"); + + const data = { a: 'A' }; + compiled = template('\'\n\r\t<%= a %>\u2028\u2029\\"'); + assert.strictEqual(compiled(data), '\'\n\r\tA\u2028\u2029\\"'); + }); + + it('should handle \\u2028 & \\u2029 characters', () => { + const compiled = template('\u2028<%= "\\u2028\\u2029" %>\u2029'); + assert.strictEqual(compiled(), '\u2028\u2028\u2029\u2029'); + }); + + it('should work with statements containing quotes', () => { + const compiled = template( + '<%\ + if (a == \'A\' || a == "a") {\ + %>\'a\',"A"<%\ + } %>', + ); + + const data = { a: 'A' }; + assert.strictEqual(compiled(data), '\'a\',"A"'); + }); + + it('should work with templates containing newlines and comments', () => { + const compiled = template( + '<%\n\ + // A code comment.\n\ + if (value) { value += 3; }\n\ + %>

<%= value %>

', + ); + + assert.strictEqual(compiled({ value: 3 }), '

6

'); + }); + + it('should tokenize delimiters', () => { + const compiled = template(''), + data = { type: 1 }; + + assert.strictEqual(compiled(data), ''); + }); + + it('should evaluate delimiters once', () => { + const actual = [], + compiled = template('<%= func("a") %><%- func("b") %><% func("c") %>'), + data = { + func: function (value) { + actual.push(value); + }, + }; + + compiled(data); + assert.deepStrictEqual(actual, ['a', 'b', 'c']); + }); + + it('should match delimiters before escaping text', () => { + const compiled = template('<<\n a \n>>', { evaluate: /<<(.*?)>>/g }); + assert.strictEqual(compiled(), '<<\n a \n>>'); + }); + + it('should resolve nullish values to an empty string', () => { + let compiled = template('<%= a %><%- a %>'), + data = { a: null }; + + assert.strictEqual(compiled(data), ''); + + data = { a: undefined }; + assert.strictEqual(compiled(data), ''); + + data = { a: {} }; + compiled = template('<%= a.b %><%- a.b %>'); + assert.strictEqual(compiled(data), ''); + }); + + it('should return an empty string for empty values', () => { + const values = [, null, undefined, ''], + expected = lodashStable.map(values, stubString), + data = { a: 1 }; + + const actual = lodashStable.map(values, (value, index) => { + const compiled = index ? template(value) : template(); + return compiled(data); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should parse delimiters without newlines', () => { + const expected = '<<\nprint("

" + (value ? "yes" : "no") + "

")\n>>', + compiled = template(expected, { evaluate: /<<(.+?)>>/g }), + data = { value: true }; + + assert.strictEqual(compiled(data), expected); + }); + + it('should support recursive calls', () => { + const compiled = template('<%= a %><% a = _.template(c)(obj) %><%= a %>'), + data = { a: 'A', b: 'B', c: '<%= b %>' }; + + assert.strictEqual(compiled(data), 'AB'); + }); + + it('should coerce `text` to a string', () => { + const object = { toString: lodashStable.constant('<%= a %>') }, + data = { a: 1 }; + + assert.strictEqual(template(object)(data), '1'); + }); + + it('should not modify the `options` object', () => { + const options = {}; + template('', options); + assert.deepStrictEqual(options, {}); + }); + + it('should not modify `_.templateSettings` when `options` are given', () => { + const data = { a: 1 }; + + assert.ok(!('a' in templateSettings)); + template('', {}, data); + assert.ok(!('a' in templateSettings)); + + delete templateSettings.a; + }); + + it('should not error for non-object `data` and `options` values', () => { + template('')(1); + assert.ok(true, '`data` value'); + + template('', 1)(1); + assert.ok(true, '`options` value'); + }); + + it('should expose the source on compiled templates', () => { + const compiled = template('x'), + values = [String(compiled), compiled.source], + expected = lodashStable.map(values, stubTrue); + + const actual = lodashStable.map(values, (value) => lodashStable.includes(value, '__p')); + + assert.deepStrictEqual(actual, expected); + }); + + it('should expose the source on SyntaxErrors', () => { + try { + template('<% if x %>'); + } catch (e) { + var source = e.source; + } + assert.ok(lodashStable.includes(source, '__p')); + }); + + it('should not include sourceURLs in the source', () => { + const options = { sourceURL: '/a/b/c' }, + compiled = template('x', options), + values = [compiled.source, undefined]; + + try { + template('<% if x %>', options); + } catch (e) { + values[1] = e.source; + } + const expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(values, (value) => + lodashStable.includes(value, 'sourceURL'), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const array = ['<%= a %>', '<%- b %>', '<% print(c) %>'], + compiles = lodashStable.map(array, template), + data = { a: 'one', b: '"two"', c: 'three' }; + + const actual = lodashStable.map(compiles, (compiled) => compiled(data)); + + assert.deepStrictEqual(actual, ['one', '"two"', 'three']); + }); +}); diff --git a/test/throttle.js b/test/throttle.js deleted file mode 100644 index c495b00eb..000000000 --- a/test/throttle.js +++ /dev/null @@ -1,227 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { identity, isModularize, argv, isPhantom } from './utils.js'; -import throttle from '../throttle.js'; -import runInContext from '../runInContext.js'; - -describe('throttle', function() { - it('should throttle a function', function(done) { - var callCount = 0, - throttled = throttle(function() { callCount++; }, 32); - - throttled(); - throttled(); - throttled(); - - var lastCount = callCount; - assert.ok(callCount); - - setTimeout(function() { - assert.ok(callCount > lastCount); - done(); - }, 64); - }); - - it('subsequent calls should return the result of the first call', function(done) { - var throttled = throttle(identity, 32), - results = [throttled('a'), throttled('b')]; - - assert.deepStrictEqual(results, ['a', 'a']); - - setTimeout(function() { - var results = [throttled('c'), throttled('d')]; - assert.notStrictEqual(results[0], 'a'); - assert.notStrictEqual(results[0], undefined); - - assert.notStrictEqual(results[1], 'd'); - assert.notStrictEqual(results[1], undefined); - done(); - }, 64); - }); - - it('should clear timeout when `func` is called', function(done) { - if (!isModularize) { - var callCount = 0, - dateCount = 0; - - var lodash = runInContext({ - 'Date': { - 'now': function() { - return ++dateCount == 5 ? Infinity : +new Date; - } - } - }); - - var throttled = lodash.throttle(function() { callCount++; }, 32); - - throttled(); - throttled(); - - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 64); - } - else { - done(); - } - }); - - it('should not trigger a trailing call when invoked once', function(done) { - var callCount = 0, - throttled = throttle(function() { callCount++; }, 32); - - throttled(); - assert.strictEqual(callCount, 1); - - setTimeout(function() { - assert.strictEqual(callCount, 1); - done(); - }, 64); - }); - - lodashStable.times(2, function(index) { - it('should trigger a call when invoked repeatedly' + (index ? ' and `leading` is `false`' : ''), function(done) { - var callCount = 0, - limit = (argv || isPhantom) ? 1000 : 320, - options = index ? { 'leading': false } : {}, - throttled = throttle(function() { callCount++; }, 32, options); - - var start = +new Date; - while ((new Date - start) < limit) { - throttled(); - } - var actual = callCount > 1; - setTimeout(function() { - assert.ok(actual); - done(); - }, 1); - }); - }); - - it('should trigger a second throttled call as soon as possible', function(done) { - var callCount = 0; - - var throttled = throttle(function() { - callCount++; - }, 128, { 'leading': false }); - - throttled(); - - setTimeout(function() { - assert.strictEqual(callCount, 1); - throttled(); - }, 192); - - setTimeout(function() { - assert.strictEqual(callCount, 1); - }, 254); - - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 384); - }); - - it('should apply default options', function(done) { - var callCount = 0, - throttled = throttle(function() { callCount++; }, 32, {}); - - throttled(); - throttled(); - assert.strictEqual(callCount, 1); - - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 128); - }); - - it('should support a `leading` option', function() { - var withLeading = throttle(identity, 32, { 'leading': true }); - assert.strictEqual(withLeading('a'), 'a'); - - var withoutLeading = throttle(identity, 32, { 'leading': false }); - assert.strictEqual(withoutLeading('a'), undefined); - }); - - it('should support a `trailing` option', function(done) { - var withCount = 0, - withoutCount = 0; - - var withTrailing = throttle(function(value) { - withCount++; - return value; - }, 64, { 'trailing': true }); - - var withoutTrailing = throttle(function(value) { - withoutCount++; - return value; - }, 64, { 'trailing': false }); - - assert.strictEqual(withTrailing('a'), 'a'); - assert.strictEqual(withTrailing('b'), 'a'); - - assert.strictEqual(withoutTrailing('a'), 'a'); - assert.strictEqual(withoutTrailing('b'), 'a'); - - setTimeout(function() { - assert.strictEqual(withCount, 2); - assert.strictEqual(withoutCount, 1); - done(); - }, 256); - }); - - it('should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`', function(done) { - var callCount = 0; - - var throttled = throttle(function() { - callCount++; - }, 64, { 'trailing': false }); - - throttled(); - throttled(); - - setTimeout(function() { - throttled(); - throttled(); - }, 96); - - setTimeout(function() { - assert.ok(callCount > 1); - done(); - }, 192); - }); - - it('should work with a system time of `0`', function(done) { - if (!isModularize) { - var callCount = 0, - dateCount = 0; - - var lodash = runInContext({ - 'Date': { - 'now': function() { - return ++dateCount < 4 ? 0 : +new Date; - } - } - }); - - var throttled = lodash.throttle(function(value) { - callCount++; - return value; - }, 32); - - var results = [throttled('a'), throttled('b'), throttled('c')]; - assert.deepStrictEqual(results, ['a', 'a', 'a']); - assert.strictEqual(callCount, 1); - - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 64); - } - else { - done(); - } - }); -}); diff --git a/test/throttle.spec.ts b/test/throttle.spec.ts new file mode 100644 index 000000000..9d8b7943c --- /dev/null +++ b/test/throttle.spec.ts @@ -0,0 +1,261 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { identity, isModularize, argv, isPhantom } from './utils'; +import throttle from '../src/throttle'; +import runInContext from '../src/runInContext'; + +describe('throttle', () => { + it('should throttle a function', (done) => { + let callCount = 0, + throttled = throttle(() => { + callCount++; + }, 32); + + throttled(); + throttled(); + throttled(); + + const lastCount = callCount; + assert.ok(callCount); + + setTimeout(() => { + assert.ok(callCount > lastCount); + done(); + }, 64); + }); + + it('subsequent calls should return the result of the first call', (done) => { + const throttled = throttle(identity, 32), + results = [throttled('a'), throttled('b')]; + + assert.deepStrictEqual(results, ['a', 'a']); + + setTimeout(() => { + const results = [throttled('c'), throttled('d')]; + assert.notStrictEqual(results[0], 'a'); + assert.notStrictEqual(results[0], undefined); + + assert.notStrictEqual(results[1], 'd'); + assert.notStrictEqual(results[1], undefined); + done(); + }, 64); + }); + + it('should clear timeout when `func` is called', (done) => { + if (!isModularize) { + let callCount = 0, + dateCount = 0; + + const lodash = runInContext({ + Date: { + now: function () { + return ++dateCount == 5 ? Infinity : +new Date(); + }, + }, + }); + + const throttled = lodash.throttle(() => { + callCount++; + }, 32); + + throttled(); + throttled(); + + setTimeout(() => { + assert.strictEqual(callCount, 2); + done(); + }, 64); + } else { + done(); + } + }); + + it('should not trigger a trailing call when invoked once', (done) => { + let callCount = 0, + throttled = throttle(() => { + callCount++; + }, 32); + + throttled(); + assert.strictEqual(callCount, 1); + + setTimeout(() => { + assert.strictEqual(callCount, 1); + done(); + }, 64); + }); + + lodashStable.times(2, (index) => { + it(`should trigger a call when invoked repeatedly${ + index ? ' and `leading` is `false`' : '' + }`, (done) => { + let callCount = 0, + limit = argv || isPhantom ? 1000 : 320, + options = index ? { leading: false } : {}, + throttled = throttle( + () => { + callCount++; + }, + 32, + options, + ); + + const start = +new Date(); + while (new Date() - start < limit) { + throttled(); + } + const actual = callCount > 1; + setTimeout(() => { + assert.ok(actual); + done(); + }, 1); + }); + }); + + it('should trigger a second throttled call as soon as possible', (done) => { + let callCount = 0; + + const throttled = throttle( + () => { + callCount++; + }, + 128, + { leading: false }, + ); + + throttled(); + + setTimeout(() => { + assert.strictEqual(callCount, 1); + throttled(); + }, 192); + + setTimeout(() => { + assert.strictEqual(callCount, 1); + }, 254); + + setTimeout(() => { + assert.strictEqual(callCount, 2); + done(); + }, 384); + }); + + it('should apply default options', (done) => { + let callCount = 0, + throttled = throttle( + () => { + callCount++; + }, + 32, + {}, + ); + + throttled(); + throttled(); + assert.strictEqual(callCount, 1); + + setTimeout(() => { + assert.strictEqual(callCount, 2); + done(); + }, 128); + }); + + it('should support a `leading` option', () => { + const withLeading = throttle(identity, 32, { leading: true }); + assert.strictEqual(withLeading('a'), 'a'); + + const withoutLeading = throttle(identity, 32, { leading: false }); + assert.strictEqual(withoutLeading('a'), undefined); + }); + + it('should support a `trailing` option', (done) => { + let withCount = 0, + withoutCount = 0; + + const withTrailing = throttle( + (value) => { + withCount++; + return value; + }, + 64, + { trailing: true }, + ); + + const withoutTrailing = throttle( + (value) => { + withoutCount++; + return value; + }, + 64, + { trailing: false }, + ); + + assert.strictEqual(withTrailing('a'), 'a'); + assert.strictEqual(withTrailing('b'), 'a'); + + assert.strictEqual(withoutTrailing('a'), 'a'); + assert.strictEqual(withoutTrailing('b'), 'a'); + + setTimeout(() => { + assert.strictEqual(withCount, 2); + assert.strictEqual(withoutCount, 1); + done(); + }, 256); + }); + + it('should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`', (done) => { + let callCount = 0; + + const throttled = throttle( + () => { + callCount++; + }, + 64, + { trailing: false }, + ); + + throttled(); + throttled(); + + setTimeout(() => { + throttled(); + throttled(); + }, 96); + + setTimeout(() => { + assert.ok(callCount > 1); + done(); + }, 192); + }); + + it('should work with a system time of `0`', (done) => { + if (!isModularize) { + let callCount = 0, + dateCount = 0; + + const lodash = runInContext({ + Date: { + now: function () { + return ++dateCount < 4 ? 0 : +new Date(); + }, + }, + }); + + const throttled = lodash.throttle((value) => { + callCount++; + return value; + }, 32); + + const results = [throttled('a'), throttled('b'), throttled('c')]; + assert.deepStrictEqual(results, ['a', 'a', 'a']); + assert.strictEqual(callCount, 1); + + setTimeout(() => { + assert.strictEqual(callCount, 2); + done(); + }, 64); + } else { + done(); + } + }); +}); diff --git a/test/times.js b/test/times.js deleted file mode 100644 index b9873f204..000000000 --- a/test/times.js +++ /dev/null @@ -1,62 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice, doubled, falsey, stubArray } from './utils.js'; -import times from '../times.js'; -import identity from '../identity.js'; - -describe('times', function() { - it('should coerce non-finite `n` values to `0`', function() { - lodashStable.each([-Infinity, NaN, Infinity], function(n) { - assert.deepStrictEqual(times(n), []); - }); - }); - - it('should coerce `n` to an integer', function() { - var actual = times(2.6, identity); - assert.deepStrictEqual(actual, [0, 1]); - }); - - it('should provide correct `iteratee` arguments', function() { - var args; - - times(1, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [0]); - }); - - it('should use `_.identity` when `iteratee` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant([0, 1, 2])); - - var actual = lodashStable.map(values, function(value, index) { - return index ? times(3, value) : times(3); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return an array of the results of each `iteratee` execution', function() { - assert.deepStrictEqual(times(3, doubled), [0, 2, 4]); - }); - - it('should return an empty array for falsey and negative `n` values', function() { - var values = falsey.concat(-1, -Infinity), - expected = lodashStable.map(values, stubArray); - - var actual = lodashStable.map(values, function(value, index) { - return index ? times(value) : times(); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should return an unwrapped value when implicitly chaining', function() { - assert.deepStrictEqual(_(3).times(), [0, 1, 2]); - }); - - it('should return a wrapped value when explicitly chaining', function() { - assert.ok(_(3).chain().times() instanceof _); - }); -}); diff --git a/test/times.spec.ts b/test/times.spec.ts new file mode 100644 index 000000000..66ebc9cfb --- /dev/null +++ b/test/times.spec.ts @@ -0,0 +1,59 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice, doubled, falsey, stubArray } from './utils'; +import times from '../src/times'; + +describe('times', () => { + it('should coerce non-finite `n` values to `0`', () => { + lodashStable.each([-Infinity, NaN, Infinity], (n) => { + assert.deepStrictEqual(times(n), []); + }); + }); + + it('should coerce `n` to an integer', () => { + const actual = times(2.6, (n) => n)); + assert.deepStrictEqual(actual, [0, 1]); + }); + + it('should provide correct `iteratee` arguments', () => { + let args; + + times(1, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [0]); + }); + + it('should use `_.identity` when `iteratee` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant([0, 1, 2])); + + const actual = lodashStable.map(values, (value, index) => + index ? times(3, value) : times(3), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return an array of the results of each `iteratee` execution', () => { + assert.deepStrictEqual(times(3, doubled), [0, 2, 4]); + }); + + it('should return an empty array for falsey and negative `n` values', () => { + const values = falsey.concat(-1, -Infinity), + expected = lodashStable.map(values, stubArray); + + const actual = lodashStable.map(values, (value, index) => (index ? times(value) : times())); + + assert.deepStrictEqual(actual, expected); + }); + + it('should return an unwrapped value when implicitly chaining', () => { + assert.deepStrictEqual(_(3).times(), [0, 1, 2]); + }); + + it('should return a wrapped value when explicitly chaining', () => { + assert.ok(_(3).chain().times() instanceof _); + }); +}); diff --git a/test/toArray.spec.ts b/test/toArray.spec.ts new file mode 100644 index 000000000..74124a971 --- /dev/null +++ b/test/toArray.spec.ts @@ -0,0 +1,51 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { arrayProto, LARGE_ARRAY_SIZE } from './utils'; +import toArray from '../src/toArray'; + +describe('toArray', () => { + it('should convert objects to arrays', () => { + assert.deepStrictEqual(toArray({ a: 1, b: 2 }), [1, 2]); + }); + + it('should convert iterables to arrays', () => { + if (Symbol && Symbol.iterator) { + const object = { '0': 'a', length: 1 }; + object[Symbol.iterator] = arrayProto[Symbol.iterator]; + + assert.deepStrictEqual(toArray(object), ['a']); + } + }); + + it('should convert maps to arrays', () => { + if (Map) { + const map = new Map(); + map.set('a', 1); + map.set('b', 2); + assert.deepStrictEqual(toArray(map), [ + ['a', 1], + ['b', 2], + ]); + } + }); + + it('should convert strings to arrays', () => { + assert.deepStrictEqual(toArray(''), []); + assert.deepStrictEqual(toArray('ab'), ['a', 'b']); + assert.deepStrictEqual(toArray(Object('ab')), ['a', 'b']); + }); + + it('should work in a lazy sequence', () => { + const array = lodashStable.range(LARGE_ARRAY_SIZE + 1); + + const object = lodashStable.zipObject( + lodashStable.times(LARGE_ARRAY_SIZE, (index) => [`key${index}`, index]), + ); + + let actual = _(array).slice(1).map(String).toArray().value(); + assert.deepEqual(actual, lodashStable.map(array.slice(1), String)); + + actual = _(object).toArray().slice(1).map(String).value(); + assert.deepEqual(actual, _.map(toArray(object).slice(1), String)); + }); +}); diff --git a/test/toArray.test.js b/test/toArray.test.js deleted file mode 100644 index 7baaf3c41..000000000 --- a/test/toArray.test.js +++ /dev/null @@ -1,48 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { arrayProto, LARGE_ARRAY_SIZE } from './utils.js'; -import toArray from '../toArray.js'; - -describe('toArray', function() { - it('should convert objects to arrays', function() { - assert.deepStrictEqual(toArray({ 'a': 1, 'b': 2 }), [1, 2]); - }); - - it('should convert iterables to arrays', function() { - if (Symbol && Symbol.iterator) { - var object = { '0': 'a', 'length': 1 }; - object[Symbol.iterator] = arrayProto[Symbol.iterator]; - - assert.deepStrictEqual(toArray(object), ['a']); - } - }); - - it('should convert maps to arrays', function() { - if (Map) { - var map = new Map; - map.set('a', 1); - map.set('b', 2); - assert.deepStrictEqual(toArray(map), [['a', 1], ['b', 2]]); - } - }); - - it('should convert strings to arrays', function() { - assert.deepStrictEqual(toArray(''), []); - assert.deepStrictEqual(toArray('ab'), ['a', 'b']); - assert.deepStrictEqual(toArray(Object('ab')), ['a', 'b']); - }); - - it('should work in a lazy sequence', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE + 1); - - var object = lodashStable.zipObject(lodashStable.times(LARGE_ARRAY_SIZE, function(index) { - return ['key' + index, index]; - })); - - var actual = _(array).slice(1).map(String).toArray().value(); - assert.deepEqual(actual, lodashStable.map(array.slice(1), String)); - - actual = _(object).toArray().slice(1).map(String).value(); - assert.deepEqual(actual, _.map(toArray(object).slice(1), String)); - }); -}); diff --git a/test/toInteger-methods.js b/test/toInteger-methods.js deleted file mode 100644 index c9d0c0349..000000000 --- a/test/toInteger-methods.js +++ /dev/null @@ -1,25 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, MAX_SAFE_INTEGER, MAX_INTEGER } from './utils.js'; - -describe('toInteger methods', function() { - lodashStable.each(['toInteger', 'toSafeInteger'], function(methodName) { - var func = _[methodName], - isSafe = methodName == 'toSafeInteger'; - - it('`_.' + methodName + '` should convert values to integers', function() { - assert.strictEqual(func(-5.6), -5); - assert.strictEqual(func('5.6'), 5); - assert.strictEqual(func(), 0); - assert.strictEqual(func(NaN), 0); - - var expected = isSafe ? MAX_SAFE_INTEGER : MAX_INTEGER; - assert.strictEqual(func(Infinity), expected); - assert.strictEqual(func(-Infinity), -expected); - }); - - it('`_.' + methodName + '` should support `value` of `-0`', function() { - assert.strictEqual(1 / func(-0), -Infinity); - }); - }); -}); diff --git a/test/toInteger-methods.spec.ts b/test/toInteger-methods.spec.ts new file mode 100644 index 000000000..cf02d8d94 --- /dev/null +++ b/test/toInteger-methods.spec.ts @@ -0,0 +1,25 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, MAX_SAFE_INTEGER, MAX_INTEGER } from './utils'; + +describe('toInteger methods', () => { + lodashStable.each(['toInteger', 'toSafeInteger'], (methodName) => { + const func = _[methodName], + isSafe = methodName == 'toSafeInteger'; + + it(`\`_.${methodName}\` should convert values to integers`, () => { + assert.strictEqual(func(-5.6), -5); + assert.strictEqual(func('5.6'), 5); + assert.strictEqual(func(), 0); + assert.strictEqual(func(NaN), 0); + + const expected = isSafe ? MAX_SAFE_INTEGER : MAX_INTEGER; + assert.strictEqual(func(Infinity), expected); + assert.strictEqual(func(-Infinity), -expected); + }); + + it(`\`_.${methodName}\` should support \`value\` of \`-0\``, () => { + assert.strictEqual(1 / func(-0), -Infinity); + }); + }); +}); diff --git a/test/toLength.spec.ts b/test/toLength.spec.ts new file mode 100644 index 000000000..eb873f96b --- /dev/null +++ b/test/toLength.spec.ts @@ -0,0 +1,22 @@ +import assert from 'node:assert'; +import { MAX_INTEGER, MAX_ARRAY_LENGTH } from './utils'; +import toLength from '../src/toLength'; + +describe('toLength', () => { + it('should return a valid length', () => { + assert.strictEqual(toLength(-1), 0); + assert.strictEqual(toLength('1'), 1); + assert.strictEqual(toLength(1.1), 1); + assert.strictEqual(toLength(MAX_INTEGER), MAX_ARRAY_LENGTH); + }); + + it('should return `value` if a valid length', () => { + assert.strictEqual(toLength(0), 0); + assert.strictEqual(toLength(3), 3); + assert.strictEqual(toLength(MAX_ARRAY_LENGTH), MAX_ARRAY_LENGTH); + }); + + it('should convert `-0` to `0`', () => { + assert.strictEqual(1 / toLength(-0), Infinity); + }); +}); diff --git a/test/toLength.test.js b/test/toLength.test.js deleted file mode 100644 index 3abbdd227..000000000 --- a/test/toLength.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; -import { MAX_INTEGER, MAX_ARRAY_LENGTH } from './utils.js'; -import toLength from '../toLength.js'; - -describe('toLength', function() { - it('should return a valid length', function() { - assert.strictEqual(toLength(-1), 0); - assert.strictEqual(toLength('1'), 1); - assert.strictEqual(toLength(1.1), 1); - assert.strictEqual(toLength(MAX_INTEGER), MAX_ARRAY_LENGTH); - }); - - it('should return `value` if a valid length', function() { - assert.strictEqual(toLength(0), 0); - assert.strictEqual(toLength(3), 3); - assert.strictEqual(toLength(MAX_ARRAY_LENGTH), MAX_ARRAY_LENGTH); - }); - - it('should convert `-0` to `0`', function() { - assert.strictEqual(1 / toLength(-0), Infinity); - }); -}); diff --git a/test/toLower.js b/test/toLower.js deleted file mode 100644 index 03e7117d9..000000000 --- a/test/toLower.js +++ /dev/null @@ -1,10 +0,0 @@ -import assert from 'assert'; -import toLower from '../toLower.js'; - -describe('toLower', function() { - it('should convert whole string to lower case', function() { - assert.deepStrictEqual(toLower('--Foo-Bar--'), '--foo-bar--'); - assert.deepStrictEqual(toLower('fooBar'), 'foobar'); - assert.deepStrictEqual(toLower('__FOO_BAR__'), '__foo_bar__'); - }); -}); diff --git a/test/toLower.spec.ts b/test/toLower.spec.ts new file mode 100644 index 000000000..3080df49c --- /dev/null +++ b/test/toLower.spec.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert'; +import toLower from '../src/toLower'; + +describe('toLower', () => { + it('should convert whole string to lower case', () => { + assert.deepStrictEqual(toLower('--Foo-Bar--'), '--foo-bar--'); + assert.deepStrictEqual(toLower('fooBar'), 'foobar'); + assert.deepStrictEqual(toLower('__FOO_BAR__'), '__foo_bar__'); + }); +}); diff --git a/test/toPairs-methods.js b/test/toPairs-methods.js deleted file mode 100644 index 34f0ddba2..000000000 --- a/test/toPairs-methods.js +++ /dev/null @@ -1,61 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('toPairs methods', function() { - lodashStable.each(['toPairs', 'toPairsIn'], function(methodName) { - var func = _[methodName], - isToPairs = methodName == 'toPairs'; - - it('`_.' + methodName + '` should create an array of string keyed-value pairs', function() { - var object = { 'a': 1, 'b': 2 }, - actual = lodashStable.sortBy(func(object), 0); - - assert.deepStrictEqual(actual, [['a', 1], ['b', 2]]); - }); - - it('`_.' + methodName + '` should ' + (isToPairs ? 'not ' : '') + 'include inherited string keyed property values', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var expected = isToPairs ? [['a', 1]] : [['a', 1], ['b', 2]], - actual = lodashStable.sortBy(func(new Foo), 0); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should convert objects with a `length` property', function() { - var object = { '0': 'a', '1': 'b', 'length': 2 }, - actual = lodashStable.sortBy(func(object), 0); - - assert.deepStrictEqual(actual, [['0', 'a'], ['1', 'b'], ['length', 2]]); - }); - - it('`_.' + methodName + '` should convert maps', function() { - if (Map) { - var map = new Map; - map.set('a', 1); - map.set('b', 2); - assert.deepStrictEqual(func(map), [['a', 1], ['b', 2]]); - } - }); - - it('`_.' + methodName + '` should convert sets', function() { - if (Set) { - var set = new Set; - set.add(1); - set.add(2); - assert.deepStrictEqual(func(set), [[1, 1], [2, 2]]); - } - }); - - it('`_.' + methodName + '` should convert strings', function() { - lodashStable.each(['xo', Object('xo')], function(string) { - var actual = lodashStable.sortBy(func(string), 0); - assert.deepStrictEqual(actual, [['0', 'x'], ['1', 'o']]); - }); - }); - }); -}); diff --git a/test/toPairs-methods.spec.ts b/test/toPairs-methods.spec.ts new file mode 100644 index 000000000..28a8d242a --- /dev/null +++ b/test/toPairs-methods.spec.ts @@ -0,0 +1,84 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('toPairs methods', () => { + lodashStable.each(['toPairs', 'toPairsIn'], (methodName) => { + const func = _[methodName], + isToPairs = methodName == 'toPairs'; + + it(`\`_.${methodName}\` should create an array of string keyed-value pairs`, () => { + const object = { a: 1, b: 2 }, + actual = lodashStable.sortBy(func(object), 0); + + assert.deepStrictEqual(actual, [ + ['a', 1], + ['b', 2], + ]); + }); + + it(`\`_.${methodName}\` should ${ + isToPairs ? 'not ' : '' + }include inherited string keyed property values`, () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const expected = isToPairs + ? [['a', 1]] + : [ + ['a', 1], + ['b', 2], + ], + actual = lodashStable.sortBy(func(new Foo()), 0); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should convert objects with a \`length\` property`, () => { + const object = { '0': 'a', '1': 'b', length: 2 }, + actual = lodashStable.sortBy(func(object), 0); + + assert.deepStrictEqual(actual, [ + ['0', 'a'], + ['1', 'b'], + ['length', 2], + ]); + }); + + it(`\`_.${methodName}\` should convert maps`, () => { + if (Map) { + const map = new Map(); + map.set('a', 1); + map.set('b', 2); + assert.deepStrictEqual(func(map), [ + ['a', 1], + ['b', 2], + ]); + } + }); + + it(`\`_.${methodName}\` should convert sets`, () => { + if (Set) { + const set = new Set(); + set.add(1); + set.add(2); + assert.deepStrictEqual(func(set), [ + [1, 1], + [2, 2], + ]); + } + }); + + it(`\`_.${methodName}\` should convert strings`, () => { + lodashStable.each(['xo', Object('xo')], (string) => { + const actual = lodashStable.sortBy(func(string), 0); + assert.deepStrictEqual(actual, [ + ['0', 'x'], + ['1', 'o'], + ]); + }); + }); + }); +}); diff --git a/test/toPairs.js b/test/toPairs.js deleted file mode 100644 index 8605aa7bb..000000000 --- a/test/toPairs.js +++ /dev/null @@ -1,9 +0,0 @@ -import assert from 'assert'; -import entries from '../entries.js'; -import toPairs from '../toPairs.js'; - -describe('toPairs', function() { - it('should be aliased', function() { - assert.strictEqual(entries, toPairs); - }); -}); diff --git a/test/toPairs.spec.ts b/test/toPairs.spec.ts new file mode 100644 index 000000000..4443f43fe --- /dev/null +++ b/test/toPairs.spec.ts @@ -0,0 +1,9 @@ +import assert from 'node:assert'; +import entries from '../src/entries'; +import toPairs from '../src/toPairs'; + +describe('toPairs', () => { + it('should be aliased', () => { + assert.strictEqual(entries, toPairs); + }); +}); diff --git a/test/toPairsIn.js b/test/toPairsIn.js deleted file mode 100644 index f35de06d9..000000000 --- a/test/toPairsIn.js +++ /dev/null @@ -1,9 +0,0 @@ -import assert from 'assert'; -import entriesIn from '../entriesIn.js'; -import toPairsIn from '../toPairsIn.js'; - -describe('toPairsIn', function() { - it('should be aliased', function() { - assert.strictEqual(entriesIn, toPairsIn); - }); -}); diff --git a/test/toPairsIn.spec.ts b/test/toPairsIn.spec.ts new file mode 100644 index 000000000..032294b80 --- /dev/null +++ b/test/toPairsIn.spec.ts @@ -0,0 +1,9 @@ +import assert from 'node:assert'; +import entriesIn from '../src/entriesIn'; +import toPairsIn from '../src/toPairsIn'; + +describe('toPairsIn', () => { + it('should be aliased', () => { + assert.strictEqual(entriesIn, toPairsIn); + }); +}); diff --git a/test/toPath.js b/test/toPath.js deleted file mode 100644 index 361de4657..000000000 --- a/test/toPath.js +++ /dev/null @@ -1,66 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { symbol } from './utils.js'; -import toPath from '../toPath.js'; - -describe('toPath', function() { - it('should convert a string to a path', function() { - assert.deepStrictEqual(toPath('a.b.c'), ['a', 'b', 'c']); - assert.deepStrictEqual(toPath('a[0].b.c'), ['a', '0', 'b', 'c']); - }); - - it('should coerce array elements to strings', function() { - var array = ['a', 'b', 'c']; - - lodashStable.each([array, lodashStable.map(array, Object)], function(value) { - var actual = toPath(value); - assert.deepStrictEqual(actual, array); - assert.notStrictEqual(actual, array); - }); - }); - - it('should return new path array', function() { - assert.notStrictEqual(toPath('a.b.c'), toPath('a.b.c')); - }); - - it('should not coerce symbols to strings', function() { - if (Symbol) { - var object = Object(symbol); - lodashStable.each([symbol, object, [symbol], [object]], function(value) { - var actual = toPath(value); - assert.ok(lodashStable.isSymbol(actual[0])); - }); - } - }); - - it('should handle complex paths', function() { - var actual = toPath('a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g'); - assert.deepStrictEqual(actual, ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g']); - }); - - it('should handle consecutive empty brackets and dots', function() { - var expected = ['', 'a']; - assert.deepStrictEqual(toPath('.a'), expected); - assert.deepStrictEqual(toPath('[].a'), expected); - - expected = ['', '', 'a']; - assert.deepStrictEqual(toPath('..a'), expected); - assert.deepStrictEqual(toPath('[][].a'), expected); - - expected = ['a', '', 'b']; - assert.deepStrictEqual(toPath('a..b'), expected); - assert.deepStrictEqual(toPath('a[].b'), expected); - - expected = ['a', '', '', 'b']; - assert.deepStrictEqual(toPath('a...b'), expected); - assert.deepStrictEqual(toPath('a[][].b'), expected); - - expected = ['a', '']; - assert.deepStrictEqual(toPath('a.'), expected); - assert.deepStrictEqual(toPath('a[]'), expected); - - expected = ['a', '', '']; - assert.deepStrictEqual(toPath('a..'), expected); - assert.deepStrictEqual(toPath('a[][]'), expected); - }); -}); diff --git a/test/toPath.spec.ts b/test/toPath.spec.ts new file mode 100644 index 000000000..aaefec6c6 --- /dev/null +++ b/test/toPath.spec.ts @@ -0,0 +1,66 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { symbol } from './utils'; +import toPath from '../src/toPath'; + +describe('toPath', () => { + it('should convert a string to a path', () => { + assert.deepStrictEqual(toPath('a.b.c'), ['a', 'b', 'c']); + assert.deepStrictEqual(toPath('a[0].b.c'), ['a', '0', 'b', 'c']); + }); + + it('should coerce array elements to strings', () => { + const array = ['a', 'b', 'c']; + + lodashStable.each([array, lodashStable.map(array, Object)], (value) => { + const actual = toPath(value); + assert.deepStrictEqual(actual, array); + assert.notStrictEqual(actual, array); + }); + }); + + it('should return new path array', () => { + assert.notStrictEqual(toPath('a.b.c'), toPath('a.b.c')); + }); + + it('should not coerce symbols to strings', () => { + if (Symbol) { + const object = Object(symbol); + lodashStable.each([symbol, object, [symbol], [object]], (value) => { + const actual = toPath(value); + assert.ok(lodashStable.isSymbol(actual[0])); + }); + } + }); + + it('should handle complex paths', () => { + const actual = toPath('a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g'); + assert.deepStrictEqual(actual, ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g']); + }); + + it('should handle consecutive empty brackets and dots', () => { + let expected = ['', 'a']; + assert.deepStrictEqual(toPath('.a'), expected); + assert.deepStrictEqual(toPath('[].a'), expected); + + expected = ['', '', 'a']; + assert.deepStrictEqual(toPath('..a'), expected); + assert.deepStrictEqual(toPath('[][].a'), expected); + + expected = ['a', '', 'b']; + assert.deepStrictEqual(toPath('a..b'), expected); + assert.deepStrictEqual(toPath('a[].b'), expected); + + expected = ['a', '', '', 'b']; + assert.deepStrictEqual(toPath('a...b'), expected); + assert.deepStrictEqual(toPath('a[][].b'), expected); + + expected = ['a', '']; + assert.deepStrictEqual(toPath('a.'), expected); + assert.deepStrictEqual(toPath('a[]'), expected); + + expected = ['a', '', '']; + assert.deepStrictEqual(toPath('a..'), expected); + assert.deepStrictEqual(toPath('a[][]'), expected); + }); +}); diff --git a/test/toPlainObject.js b/test/toPlainObject.js deleted file mode 100644 index 78046d28f..000000000 --- a/test/toPlainObject.js +++ /dev/null @@ -1,30 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { args } from './utils.js'; -import toPlainObject from '../toPlainObject.js'; - -describe('toPlainObject', function() { - it('should flatten inherited string keyed properties', function() { - function Foo() { - this.b = 2; - } - Foo.prototype.c = 3; - - var actual = lodashStable.assign({ 'a': 1 }, toPlainObject(new Foo)); - assert.deepStrictEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); - }); - - it('should convert `arguments` objects to plain objects', function() { - var actual = toPlainObject(args), - expected = { '0': 1, '1': 2, '2': 3 }; - - assert.deepStrictEqual(actual, expected); - }); - - it('should convert arrays to plain objects', function() { - var actual = toPlainObject(['a', 'b', 'c']), - expected = { '0': 'a', '1': 'b', '2': 'c' }; - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/toPlainObject.spec.ts b/test/toPlainObject.spec.ts new file mode 100644 index 000000000..cc883bc17 --- /dev/null +++ b/test/toPlainObject.spec.ts @@ -0,0 +1,30 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { args } from './utils'; +import toPlainObject from '../src/toPlainObject'; + +describe('toPlainObject', () => { + it('should flatten inherited string keyed properties', () => { + function Foo() { + this.b = 2; + } + Foo.prototype.c = 3; + + const actual = lodashStable.assign({ a: 1 }, toPlainObject(new Foo())); + assert.deepStrictEqual(actual, { a: 1, b: 2, c: 3 }); + }); + + it('should convert `arguments` objects to plain objects', () => { + const actual = toPlainObject(args), + expected = { '0': 1, '1': 2, '2': 3 }; + + assert.deepStrictEqual(actual, expected); + }); + + it('should convert arrays to plain objects', () => { + const actual = toPlainObject(['a', 'b', 'c']), + expected = { '0': 'a', '1': 'b', '2': 'c' }; + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/toString.spec.ts b/test/toString.spec.ts new file mode 100644 index 000000000..529b2d636 --- /dev/null +++ b/test/toString.spec.ts @@ -0,0 +1,43 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubString, symbol } from './utils'; +import toString from '../src/toString'; + +describe('toString', () => { + it('should treat nullish values as empty strings', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubString); + + const actual = lodashStable.map(values, (value, index) => + index ? toString(value) : toString(), + ); + + assert.deepStrictEqual(actual, expected); + }); + + it('should preserve the sign of `0`', () => { + const values = [-0, Object(-0), 0, Object(0)], + expected = ['-0', '-0', '0', '0'], + actual = lodashStable.map(values, toString); + + assert.deepStrictEqual(actual, expected); + }); + + it('should preserve the sign of `0` in an array', () => { + const values = [-0, Object(-0), 0, Object(0)]; + assert.deepStrictEqual(toString(values), '-0,-0,0,0'); + }); + + it('should handle symbols', () => { + assert.strictEqual(toString(symbol), 'Symbol(a)'); + }); + + it('should handle an array of symbols', () => { + assert.strictEqual(toString([symbol]), 'Symbol(a)'); + }); + + it('should return the `toString` result of the wrapped value', () => { + const wrapped = _([1, 2, 3]); + assert.strictEqual(wrapped.toString(), '1,2,3'); + }); +}); diff --git a/test/toString.test.js b/test/toString.test.js deleted file mode 100644 index 16e08ab57..000000000 --- a/test/toString.test.js +++ /dev/null @@ -1,43 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubString, symbol } from './utils.js'; -import toString from '../toString.js'; - -describe('toString', function() { - it('should treat nullish values as empty strings', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubString); - - var actual = lodashStable.map(values, function(value, index) { - return index ? toString(value) : toString(); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should preserve the sign of `0`', function() { - var values = [-0, Object(-0), 0, Object(0)], - expected = ['-0', '-0', '0', '0'], - actual = lodashStable.map(values, toString); - - assert.deepStrictEqual(actual, expected); - }); - - it('should preserve the sign of `0` in an array', function() { - var values = [-0, Object(-0), 0, Object(0)]; - assert.deepStrictEqual(toString(values), '-0,-0,0,0'); - }); - - it('should handle symbols', function() { - assert.strictEqual(toString(symbol), 'Symbol(a)'); - }); - - it('should handle an array of symbols', function() { - assert.strictEqual(toString([symbol]), 'Symbol(a)'); - }); - - it('should return the `toString` result of the wrapped value', function() { - var wrapped = _([1, 2, 3]); - assert.strictEqual(wrapped.toString(), '1,2,3'); - }); -}); diff --git a/test/toUpper.js b/test/toUpper.js deleted file mode 100644 index bb6b83729..000000000 --- a/test/toUpper.js +++ /dev/null @@ -1,10 +0,0 @@ -import assert from 'assert'; -import toUpper from '../toUpper.js'; - -describe('toUpper', function() { - it('should convert whole string to upper case', function() { - assert.deepStrictEqual(toUpper('--Foo-Bar'), '--FOO-BAR'); - assert.deepStrictEqual(toUpper('fooBar'), 'FOOBAR'); - assert.deepStrictEqual(toUpper('__FOO_BAR__'), '__FOO_BAR__'); - }); -}); diff --git a/test/toUpper.spec.ts b/test/toUpper.spec.ts new file mode 100644 index 000000000..759398b8b --- /dev/null +++ b/test/toUpper.spec.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert'; +import toUpper from '../src/toUpper'; + +describe('toUpper', () => { + it('should convert whole string to upper case', () => { + assert.deepStrictEqual(toUpper('--Foo-Bar'), '--FOO-BAR'); + assert.deepStrictEqual(toUpper('fooBar'), 'FOOBAR'); + assert.deepStrictEqual(toUpper('__FOO_BAR__'), '__FOO_BAR__'); + }); +}); diff --git a/test/transform.js b/test/transform.js deleted file mode 100644 index c8121183a..000000000 --- a/test/transform.js +++ /dev/null @@ -1,205 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -import { - stubTrue, - square, - typedArrays, - noop, - stubObject, - stubFalse, - falsey, - slice, - realm, -} from './utils.js'; - -import transform from '../transform.js'; - -describe('transform', function() { - function Foo() { - this.a = 1; - this.b = 2; - this.c = 3; - } - - it('should create an object with the same `[[Prototype]]` as `object` when `accumulator` is nullish', function() { - var accumulators = [, null, undefined], - object = new Foo, - expected = lodashStable.map(accumulators, stubTrue); - - var iteratee = function(result, value, key) { - result[key] = square(value); - }; - - var mapper = function(accumulator, index) { - return index ? transform(object, iteratee, accumulator) : transform(object, iteratee); - }; - - var results = lodashStable.map(accumulators, mapper); - - var actual = lodashStable.map(results, function(result) { - return result instanceof Foo; - }); - - assert.deepStrictEqual(actual, expected); - - expected = lodashStable.map(accumulators, lodashStable.constant({ 'a': 1, 'b': 4, 'c': 9 })); - actual = lodashStable.map(results, lodashStable.toPlainObject); - - assert.deepStrictEqual(actual, expected); - - object = { 'a': 1, 'b': 2, 'c': 3 }; - actual = lodashStable.map(accumulators, mapper); - - assert.deepStrictEqual(actual, expected); - - object = [1, 2, 3]; - expected = lodashStable.map(accumulators, lodashStable.constant([1, 4, 9])); - actual = lodashStable.map(accumulators, mapper); - - assert.deepStrictEqual(actual, expected); - }); - - it('should create regular arrays from typed arrays', function() { - var expected = lodashStable.map(typedArrays, stubTrue); - - var actual = lodashStable.map(typedArrays, function(type) { - var Ctor = root[type], - array = Ctor ? new Ctor(new ArrayBuffer(24)) : []; - - return lodashStable.isArray(transform(array, noop)); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should support an `accumulator` value', function() { - var values = [new Foo, [1, 2, 3], { 'a': 1, 'b': 2, 'c': 3 }], - expected = lodashStable.map(values, lodashStable.constant([1, 4, 9])); - - var actual = lodashStable.map(values, function(value) { - return transform(value, function(result, value) { - result.push(square(value)); - }, []); - }); - - assert.deepStrictEqual(actual, expected); - - var object = { 'a': 1, 'b': 4, 'c': 9 }, - expected = [object, { '0': 1, '1': 4, '2': 9 }, object]; - - actual = lodashStable.map(values, function(value) { - return transform(value, function(result, value, key) { - result[key] = square(value); - }, {}); - }); - - assert.deepStrictEqual(actual, expected); - - lodashStable.each([[], {}], function(accumulator) { - var actual = lodashStable.map(values, function(value) { - return transform(value, noop, accumulator); - }); - - assert.ok(lodashStable.every(actual, function(result) { - return result === accumulator; - })); - - assert.strictEqual(transform(null, null, accumulator), accumulator); - }); - }); - - it('should treat sparse arrays as dense', function() { - var actual = transform(Array(1), function(result, value, index) { - result[index] = String(value); - }); - - assert.deepStrictEqual(actual, ['undefined']); - }); - - it('should work without an `iteratee`', function() { - assert.ok(transform(new Foo) instanceof Foo); - }); - - it('should ensure `object` is an object before using its `[[Prototype]]`', function() { - var Ctors = [Boolean, Boolean, Number, Number, Number, String, String], - values = [false, true, 0, 1, NaN, '', 'a'], - expected = lodashStable.map(values, stubObject); - - var results = lodashStable.map(values, function(value) { - return transform(value); - }); - - assert.deepStrictEqual(results, expected); - - expected = lodashStable.map(values, stubFalse); - - var actual = lodashStable.map(results, function(value, index) { - return value instanceof Ctors[index]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should ensure `object` constructor is a function before using its `[[Prototype]]`', function() { - Foo.prototype.constructor = null; - assert.ok(!(transform(new Foo) instanceof Foo)); - Foo.prototype.constructor = Foo; - }); - - it('should create an empty object when given a falsey `object`', function() { - var expected = lodashStable.map(falsey, stubObject); - - var actual = lodashStable.map(falsey, function(object, index) { - return index ? transform(object) : transform(); - }); - - assert.deepStrictEqual(actual, expected); - }); - - lodashStable.each({ - 'array': [1, 2, 3], - 'object': { 'a': 1, 'b': 2, 'c': 3 } - }, - function(object, key) { - it('should provide correct `iteratee` arguments when transforming an ' + key, function() { - var args; - - transform(object, function() { - args || (args = slice.call(arguments)); - }); - - var first = args[0]; - if (key == 'array') { - assert.ok(first !== object && lodashStable.isArray(first)); - assert.deepStrictEqual(args, [first, 1, 0, object]); - } else { - assert.ok(first !== object && lodashStable.isPlainObject(first)); - assert.deepStrictEqual(args, [first, 1, 'a', object]); - } - }); - }); - - it('should create an object from the same realm as `object`', function() { - var objects = lodashStable.filter(realm, function(value) { - return lodashStable.isObject(value) && !lodashStable.isElement(value); - }); - - var expected = lodashStable.map(objects, stubTrue); - - var actual = lodashStable.map(objects, function(object) { - var Ctor = object.constructor, - result = transform(object); - - if (result === object) { - return false; - } - if (lodashStable.isTypedArray(object)) { - return result instanceof Array; - } - return result instanceof Ctor || !(new Ctor instanceof Ctor); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/transform.spec.ts b/test/transform.spec.ts new file mode 100644 index 000000000..feabc1915 --- /dev/null +++ b/test/transform.spec.ts @@ -0,0 +1,206 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +import { + stubTrue, + square, + typedArrays, + noop, + stubObject, + stubFalse, + falsey, + slice, + realm, +} from './utils'; + +import transform from '../src/transform'; + +describe('transform', () => { + function Foo() { + this.a = 1; + this.b = 2; + this.c = 3; + } + + it('should create an object with the same `[[Prototype]]` as `object` when `accumulator` is nullish', () => { + let accumulators = [, null, undefined], + object = new Foo(), + expected = lodashStable.map(accumulators, stubTrue); + + const iteratee = function (result, value, key) { + result[key] = square(value); + }; + + const mapper = function (accumulator, index) { + return index ? transform(object, iteratee, accumulator) : transform(object, iteratee); + }; + + const results = lodashStable.map(accumulators, mapper); + + let actual = lodashStable.map(results, (result) => result instanceof Foo); + + assert.deepStrictEqual(actual, expected); + + expected = lodashStable.map(accumulators, lodashStable.constant({ a: 1, b: 4, c: 9 })); + actual = lodashStable.map(results, lodashStable.toPlainObject); + + assert.deepStrictEqual(actual, expected); + + object = { a: 1, b: 2, c: 3 }; + actual = lodashStable.map(accumulators, mapper); + + assert.deepStrictEqual(actual, expected); + + object = [1, 2, 3]; + expected = lodashStable.map(accumulators, lodashStable.constant([1, 4, 9])); + actual = lodashStable.map(accumulators, mapper); + + assert.deepStrictEqual(actual, expected); + }); + + it('should create regular arrays from typed arrays', () => { + const expected = lodashStable.map(typedArrays, stubTrue); + + const actual = lodashStable.map(typedArrays, (type) => { + const Ctor = root[type], + array = Ctor ? new Ctor(new ArrayBuffer(24)) : []; + + return lodashStable.isArray(transform(array, noop)); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should support an `accumulator` value', () => { + var values = [new Foo(), [1, 2, 3], { a: 1, b: 2, c: 3 }], + expected = lodashStable.map(values, lodashStable.constant([1, 4, 9])); + + let actual = lodashStable.map(values, (value) => + transform( + value, + (result, value) => { + result.push(square(value)); + }, + [], + ), + ); + + assert.deepStrictEqual(actual, expected); + + var object = { a: 1, b: 4, c: 9 }, + expected = [object, { '0': 1, '1': 4, '2': 9 }, object]; + + actual = lodashStable.map(values, (value) => + transform( + value, + (result, value, key) => { + result[key] = square(value); + }, + {}, + ), + ); + + assert.deepStrictEqual(actual, expected); + + lodashStable.each([[], {}], (accumulator) => { + const actual = lodashStable.map(values, (value) => transform(value, noop, accumulator)); + + assert.ok(lodashStable.every(actual, (result) => result === accumulator)); + + assert.strictEqual(transform(null, null, accumulator), accumulator); + }); + }); + + it('should treat sparse arrays as dense', () => { + const actual = transform(Array(1), (result, value, index) => { + result[index] = String(value); + }); + + assert.deepStrictEqual(actual, ['undefined']); + }); + + it('should work without an `iteratee`', () => { + assert.ok(transform(new Foo()) instanceof Foo); + }); + + it('should ensure `object` is an object before using its `[[Prototype]]`', () => { + let Ctors = [Boolean, Boolean, Number, Number, Number, String, String], + values = [false, true, 0, 1, NaN, '', 'a'], + expected = lodashStable.map(values, stubObject); + + const results = lodashStable.map(values, (value) => transform(value)); + + assert.deepStrictEqual(results, expected); + + expected = lodashStable.map(values, stubFalse); + + const actual = lodashStable.map(results, (value, index) => value instanceof Ctors[index]); + + assert.deepStrictEqual(actual, expected); + }); + + it('should ensure `object` constructor is a function before using its `[[Prototype]]`', () => { + Foo.prototype.constructor = null; + assert.ok(!(transform(new Foo()) instanceof Foo)); + Foo.prototype.constructor = Foo; + }); + + it('should create an empty object when given a falsey `object`', () => { + const expected = lodashStable.map(falsey, stubObject); + + const actual = lodashStable.map(falsey, (object, index) => + index ? transform(object) : transform(), + ); + + assert.deepStrictEqual(actual, expected); + }); + + lodashStable.each( + { + array: [1, 2, 3], + object: { a: 1, b: 2, c: 3 }, + }, + (object, key) => { + it(`should provide correct \`iteratee\` arguments when transforming an ${key}`, () => { + let args; + + transform(object, function () { + args || (args = slice.call(arguments)); + }); + + const first = args[0]; + if (key == 'array') { + assert.ok(first !== object && lodashStable.isArray(first)); + assert.deepStrictEqual(args, [first, 1, 0, object]); + } else { + assert.ok(first !== object && lodashStable.isPlainObject(first)); + assert.deepStrictEqual(args, [first, 1, 'a', object]); + } + }); + }, + ); + + it('should create an object from the same realm as `object`', () => { + const objects = lodashStable.filter( + realm, + (value) => lodashStable.isObject(value) && !lodashStable.isElement(value), + ); + + const expected = lodashStable.map(objects, stubTrue); + + const actual = lodashStable.map(objects, (object) => { + const Ctor = object.constructor, + result = transform(object); + + if (result === object) { + return false; + } + if (lodashStable.isTypedArray(object)) { + return result instanceof Array; + } + return result instanceof Ctor || !(new Ctor() instanceof Ctor); + }); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/trim-methods.js b/test/trim-methods.js deleted file mode 100644 index c3f8a845c..000000000 --- a/test/trim-methods.js +++ /dev/null @@ -1,83 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, whitespace } from './utils.js'; - -describe('trim methods', function() { - lodashStable.each(['trim', 'trimStart', 'trimEnd'], function(methodName, index) { - var func = _[methodName], - parts = []; - - if (index != 2) { - parts.push('leading'); - } - if (index != 1) { - parts.push('trailing'); - } - parts = parts.join(' and '); - - it('`_.' + methodName + '` should remove ' + parts + ' whitespace', function() { - var string = whitespace + 'a b c' + whitespace, - expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); - - assert.strictEqual(func(string), expected); - }); - - it('`_.' + methodName + '` should coerce `string` to a string', function() { - var object = { 'toString': lodashStable.constant(whitespace + 'a b c' + whitespace) }, - expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); - - assert.strictEqual(func(object), expected); - }); - - it('`_.' + methodName + '` should remove ' + parts + ' `chars`', function() { - var string = '-_-a-b-c-_-', - expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : ''); - - assert.strictEqual(func(string, '_-'), expected); - }); - - it('`_.' + methodName + '` should coerce `chars` to a string', function() { - var object = { 'toString': lodashStable.constant('_-') }, - string = '-_-a-b-c-_-', - expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : ''); - - assert.strictEqual(func(string, object), expected); - }); - - it('`_.' + methodName + '` should return an empty string for empty values and `chars`', function() { - lodashStable.each([null, '_-'], function(chars) { - assert.strictEqual(func(null, chars), ''); - assert.strictEqual(func(undefined, chars), ''); - assert.strictEqual(func('', chars), ''); - }); - }); - - it('`_.' + methodName + '` should work with `undefined` or empty string values for `chars`', function() { - var string = whitespace + 'a b c' + whitespace, - expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); - - assert.strictEqual(func(string, undefined), expected); - assert.strictEqual(func(string, ''), string); - }); - - it('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function() { - var string = Object(whitespace + 'a b c' + whitespace), - trimmed = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''), - actual = lodashStable.map([string, string, string], func); - - assert.deepStrictEqual(actual, [trimmed, trimmed, trimmed]); - }); - - it('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function() { - var string = whitespace + 'a b c' + whitespace, - expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); - - assert.strictEqual(_(string)[methodName](), expected); - }); - - it('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function() { - var string = whitespace + 'a b c' + whitespace; - assert.ok(_(string).chain()[methodName]() instanceof _); - }); - }); -}); diff --git a/test/trim-methods.spec.ts b/test/trim-methods.spec.ts new file mode 100644 index 000000000..037d10c95 --- /dev/null +++ b/test/trim-methods.spec.ts @@ -0,0 +1,83 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, whitespace } from './utils'; + +describe('trim methods', () => { + lodashStable.each(['trim', 'trimStart', 'trimEnd'], (methodName, index) => { + let func = _[methodName], + parts = []; + + if (index != 2) { + parts.push('leading'); + } + if (index != 1) { + parts.push('trailing'); + } + parts = parts.join(' and '); + + it(`\`_.${methodName}\` should remove ${parts} whitespace`, () => { + const string = `${whitespace}a b c${whitespace}`, + expected = `${index == 2 ? whitespace : ''}a b c${index == 1 ? whitespace : ''}`; + + assert.strictEqual(func(string), expected); + }); + + it(`\`_.${methodName}\` should coerce \`string\` to a string`, () => { + const object = { toString: lodashStable.constant(`${whitespace}a b c${whitespace}`) }, + expected = `${index == 2 ? whitespace : ''}a b c${index == 1 ? whitespace : ''}`; + + assert.strictEqual(func(object), expected); + }); + + it(`\`_.${methodName}\` should remove ${parts} \`chars\``, () => { + const string = '-_-a-b-c-_-', + expected = `${index == 2 ? '-_-' : ''}a-b-c${index == 1 ? '-_-' : ''}`; + + assert.strictEqual(func(string, '_-'), expected); + }); + + it(`\`_.${methodName}\` should coerce \`chars\` to a string`, () => { + const object = { toString: lodashStable.constant('_-') }, + string = '-_-a-b-c-_-', + expected = `${index == 2 ? '-_-' : ''}a-b-c${index == 1 ? '-_-' : ''}`; + + assert.strictEqual(func(string, object), expected); + }); + + it(`\`_.${methodName}\` should return an empty string for empty values and \`chars\``, () => { + lodashStable.each([null, '_-'], (chars) => { + assert.strictEqual(func(null, chars), ''); + assert.strictEqual(func(undefined, chars), ''); + assert.strictEqual(func('', chars), ''); + }); + }); + + it(`\`_.${methodName}\` should work with \`undefined\` or empty string values for \`chars\``, () => { + const string = `${whitespace}a b c${whitespace}`, + expected = `${index == 2 ? whitespace : ''}a b c${index == 1 ? whitespace : ''}`; + + assert.strictEqual(func(string, undefined), expected); + assert.strictEqual(func(string, ''), string); + }); + + it(`\`_.${methodName}\` should work as an iteratee for methods like \`_.map\``, () => { + const string = Object(`${whitespace}a b c${whitespace}`), + trimmed = `${index == 2 ? whitespace : ''}a b c${index == 1 ? whitespace : ''}`, + actual = lodashStable.map([string, string, string], func); + + assert.deepStrictEqual(actual, [trimmed, trimmed, trimmed]); + }); + + it(`\`_.${methodName}\` should return an unwrapped value when implicitly chaining`, () => { + const string = `${whitespace}a b c${whitespace}`, + expected = `${index == 2 ? whitespace : ''}a b c${index == 1 ? whitespace : ''}`; + + assert.strictEqual(_(string)[methodName](), expected); + }); + + it(`\`_.${methodName}\` should return a wrapped value when explicitly chaining`, () => { + const string = `${whitespace}a b c${whitespace}`; + assert.ok(_(string).chain()[methodName]() instanceof _); + }); + }); +}); diff --git a/test/truncate.js b/test/truncate.js deleted file mode 100644 index 240eae0b9..000000000 --- a/test/truncate.js +++ /dev/null @@ -1,64 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import truncate from '../truncate.js'; - -describe('truncate', function() { - var string = 'hi-diddly-ho there, neighborino'; - - it('should use a default `length` of `30`', function() { - assert.strictEqual(truncate(string), 'hi-diddly-ho there, neighbo...'); - }); - - it('should not truncate if `string` is <= `length`', function() { - assert.strictEqual(truncate(string, { 'length': string.length }), string); - assert.strictEqual(truncate(string, { 'length': string.length + 2 }), string); - }); - - it('should truncate string the given length', function() { - assert.strictEqual(truncate(string, { 'length': 24 }), 'hi-diddly-ho there, n...'); - }); - - it('should support a `omission` option', function() { - assert.strictEqual(truncate(string, { 'omission': ' [...]' }), 'hi-diddly-ho there, neig [...]'); - }); - - it('should coerce nullish `omission` values to strings', function() { - assert.strictEqual(truncate(string, { 'omission': null }), 'hi-diddly-ho there, neighbnull'); - assert.strictEqual(truncate(string, { 'omission': undefined }), 'hi-diddly-ho there, nundefined'); - }); - - it('should support a `length` option', function() { - assert.strictEqual(truncate(string, { 'length': 4 }), 'h...'); - }); - - it('should support a `separator` option', function() { - assert.strictEqual(truncate(string, { 'length': 24, 'separator': ' ' }), 'hi-diddly-ho there,...'); - assert.strictEqual(truncate(string, { 'length': 24, 'separator': /,? +/ }), 'hi-diddly-ho there...'); - assert.strictEqual(truncate(string, { 'length': 24, 'separator': /,? +/g }), 'hi-diddly-ho there...'); - }); - - it('should treat negative `length` as `0`', function() { - lodashStable.each([0, -2], function(length) { - assert.strictEqual(truncate(string, { 'length': length }), '...'); - }); - }); - - it('should coerce `length` to an integer', function() { - lodashStable.each(['', NaN, 4.6, '4'], function(length, index) { - var actual = index > 1 ? 'h...' : '...'; - assert.strictEqual(truncate(string, { 'length': { 'valueOf': lodashStable.constant(length) } }), actual); - }); - }); - - it('should coerce `string` to a string', function() { - assert.strictEqual(truncate(Object(string), { 'length': 4 }), 'h...'); - assert.strictEqual(truncate({ 'toString': lodashStable.constant(string) }, { 'length': 5 }), 'hi...'); - }); - - it('should work as an iteratee for methods like `_.map`', function() { - var actual = lodashStable.map([string, string, string], truncate), - truncated = 'hi-diddly-ho there, neighbo...'; - - assert.deepStrictEqual(actual, [truncated, truncated, truncated]); - }); -}); diff --git a/test/truncate.spec.ts b/test/truncate.spec.ts new file mode 100644 index 000000000..df942d1aa --- /dev/null +++ b/test/truncate.spec.ts @@ -0,0 +1,85 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import truncate from '../src/truncate'; + +describe('truncate', () => { + const string = 'hi-diddly-ho there, neighborino'; + + it('should use a default `length` of `30`', () => { + assert.strictEqual(truncate(string), 'hi-diddly-ho there, neighbo...'); + }); + + it('should not truncate if `string` is <= `length`', () => { + assert.strictEqual(truncate(string, { length: string.length }), string); + assert.strictEqual(truncate(string, { length: string.length + 2 }), string); + }); + + it('should truncate string the given length', () => { + assert.strictEqual(truncate(string, { length: 24 }), 'hi-diddly-ho there, n...'); + }); + + it('should support a `omission` option', () => { + assert.strictEqual( + truncate(string, { omission: ' [...]' }), + 'hi-diddly-ho there, neig [...]', + ); + }); + + it('should coerce nullish `omission` values to strings', () => { + assert.strictEqual(truncate(string, { omission: null }), 'hi-diddly-ho there, neighbnull'); + assert.strictEqual( + truncate(string, { omission: undefined }), + 'hi-diddly-ho there, nundefined', + ); + }); + + it('should support a `length` option', () => { + assert.strictEqual(truncate(string, { length: 4 }), 'h...'); + }); + + it('should support a `separator` option', () => { + assert.strictEqual( + truncate(string, { length: 24, separator: ' ' }), + 'hi-diddly-ho there,...', + ); + assert.strictEqual( + truncate(string, { length: 24, separator: /,? +/ }), + 'hi-diddly-ho there...', + ); + assert.strictEqual( + truncate(string, { length: 24, separator: /,? +/g }), + 'hi-diddly-ho there...', + ); + }); + + it('should treat negative `length` as `0`', () => { + lodashStable.each([0, -2], (length) => { + assert.strictEqual(truncate(string, { length: length }), '...'); + }); + }); + + it('should coerce `length` to an integer', () => { + lodashStable.each(['', NaN, 4.6, '4'], (length, index) => { + const actual = index > 1 ? 'h...' : '...'; + assert.strictEqual( + truncate(string, { length: { valueOf: lodashStable.constant(length) } }), + actual, + ); + }); + }); + + it('should coerce `string` to a string', () => { + assert.strictEqual(truncate(Object(string), { length: 4 }), 'h...'); + assert.strictEqual( + truncate({ toString: lodashStable.constant(string) }, { length: 5 }), + 'hi...', + ); + }); + + it('should work as an iteratee for methods like `_.map`', () => { + const actual = lodashStable.map([string, string, string], truncate), + truncated = 'hi-diddly-ho there, neighbo...'; + + assert.deepStrictEqual(actual, [truncated, truncated, truncated]); + }); +}); diff --git a/test/unary.js b/test/unary.js deleted file mode 100644 index 333c89091..000000000 --- a/test/unary.js +++ /dev/null @@ -1,27 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice } from './utils.js'; -import unary from '../unary.js'; - -describe('unary', function() { - function fn() { - return slice.call(arguments); - } - - it('should cap the number of arguments provided to `func`', function() { - var actual = lodashStable.map(['6', '8', '10'], unary(parseInt)); - assert.deepStrictEqual(actual, [6, 8, 10]); - }); - - it('should not force a minimum argument count', function() { - var capped = unary(fn); - assert.deepStrictEqual(capped(), []); - }); - - it('should use `this` binding of function', function() { - var capped = unary(function(a, b) { return this; }), - object = { 'capped': capped }; - - assert.strictEqual(object.capped(), object); - }); -}); diff --git a/test/unary.spec.ts b/test/unary.spec.ts new file mode 100644 index 000000000..2d0028fb0 --- /dev/null +++ b/test/unary.spec.ts @@ -0,0 +1,29 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice } from './utils'; +import unary from '../src/unary'; + +describe('unary', () => { + function fn() { + return slice.call(arguments); + } + + it('should cap the number of arguments provided to `func`', () => { + const actual = lodashStable.map(['6', '8', '10'], unary(parseInt)); + assert.deepStrictEqual(actual, [6, 8, 10]); + }); + + it('should not force a minimum argument count', () => { + const capped = unary(fn); + assert.deepStrictEqual(capped(), []); + }); + + it('should use `this` binding of function', () => { + const capped = unary(function (a, b) { + return this; + }), + object = { capped: capped }; + + assert.strictEqual(object.capped(), object); + }); +}); diff --git a/test/uncommon-symbols.js b/test/uncommon-symbols.js deleted file mode 100644 index f108be793..000000000 --- a/test/uncommon-symbols.js +++ /dev/null @@ -1,170 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { emojiVar, comboMarks, fitzModifiers } from './utils.js'; -import repeat from '../repeat.js'; -import camelCase from '../camelCase.js'; -import capitalize from '../capitalize.js'; -import pad from '../pad.js'; -import padStart from '../padStart.js'; -import padEnd from '../padEnd.js'; -import size from '../size.js'; -import split from '../split.js'; -import toArray from '../toArray.js'; -import trim from '../trim.js'; -import trimStart from '../trimStart.js'; -import trimEnd from '../trimEnd.js'; -import truncate from '../truncate.js'; -import words from '../words.js'; - -describe('uncommon symbols', function() { - var flag = '\ud83c\uddfa\ud83c\uddf8', - heart = '\u2764' + emojiVar, - hearts = '\ud83d\udc95', - comboGlyph = '\ud83d\udc68\u200d' + heart + '\u200d\ud83d\udc8B\u200d\ud83d\udc68', - hashKeycap = '#' + emojiVar + '\u20e3', - leafs = '\ud83c\udf42', - mic = '\ud83c\udf99', - noMic = mic + '\u20e0', - raisedHand = '\u270B' + emojiVar, - rocket = '\ud83d\ude80', - thumbsUp = '\ud83d\udc4d'; - - it('should account for astral symbols', function() { - var allHearts = repeat(hearts, 10), - chars = hearts + comboGlyph, - string = 'A ' + leafs + ', ' + comboGlyph + ', and ' + rocket, - trimChars = comboGlyph + hearts, - trimString = trimChars + string + trimChars; - - assert.strictEqual(camelCase(hearts + ' the ' + leafs), hearts + 'The' + leafs); - assert.strictEqual(camelCase(string), 'a' + leafs + comboGlyph + 'And' + rocket); - assert.strictEqual(capitalize(rocket), rocket); - - assert.strictEqual(pad(string, 16), ' ' + string + ' '); - assert.strictEqual(padStart(string, 16), ' ' + string); - assert.strictEqual(padEnd(string, 16), string + ' '); - - assert.strictEqual(pad(string, 16, chars), hearts + string + chars); - assert.strictEqual(padStart(string, 16, chars), chars + hearts + string); - assert.strictEqual(padEnd(string, 16, chars), string + chars + hearts); - - assert.strictEqual(size(string), 13); - assert.deepStrictEqual(split(string, ' '), ['A', leafs + ',', comboGlyph + ',', 'and', rocket]); - assert.deepStrictEqual(split(string, ' ', 3), ['A', leafs + ',', comboGlyph + ',']); - assert.deepStrictEqual(split(string, undefined), [string]); - assert.deepStrictEqual(split(string, undefined, -1), [string]); - assert.deepStrictEqual(split(string, undefined, 0), []); - - var expected = ['A', ' ', leafs, ',', ' ', comboGlyph, ',', ' ', 'a', 'n', 'd', ' ', rocket]; - - assert.deepStrictEqual(split(string, ''), expected); - assert.deepStrictEqual(split(string, '', 6), expected.slice(0, 6)); - assert.deepStrictEqual(toArray(string), expected); - - assert.strictEqual(trim(trimString, chars), string); - assert.strictEqual(trimStart(trimString, chars), string + trimChars); - assert.strictEqual(trimEnd(trimString, chars), trimChars + string); - - assert.strictEqual(truncate(string, { 'length': 13 }), string); - assert.strictEqual(truncate(string, { 'length': 6 }), 'A ' + leafs + '...'); - - assert.deepStrictEqual(words(string), ['A', leafs, comboGlyph, 'and', rocket]); - assert.deepStrictEqual(toArray(hashKeycap), [hashKeycap]); - assert.deepStrictEqual(toArray(noMic), [noMic]); - - lodashStable.times(2, function(index) { - var separator = index ? RegExp(hearts) : hearts, - options = { 'length': 4, 'separator': separator }, - actual = truncate(string, options); - - assert.strictEqual(actual, 'A...'); - assert.strictEqual(actual.length, 4); - - actual = truncate(allHearts, options); - assert.strictEqual(actual, hearts + '...'); - assert.strictEqual(actual.length, 5); - }); - }); - - it('should account for combining diacritical marks', function() { - var values = lodashStable.map(comboMarks, function(mark) { - return 'o' + mark; - }); - - var expected = lodashStable.map(values, function(value) { - return [1, [value], [value]]; - }); - - var actual = lodashStable.map(values, function(value) { - return [size(value), toArray(value), words(value)]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should account for fitzpatrick modifiers', function() { - var values = lodashStable.map(fitzModifiers, function(modifier) { - return thumbsUp + modifier; - }); - - var expected = lodashStable.map(values, function(value) { - return [1, [value], [value]]; - }); - - var actual = lodashStable.map(values, function(value) { - return [size(value), toArray(value), words(value)]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should account for regional symbols', function() { - var pair = flag.match(/\ud83c[\udde6-\uddff]/g), - regionals = pair.join(' '); - - assert.strictEqual(size(flag), 1); - assert.strictEqual(size(regionals), 3); - - assert.deepStrictEqual(toArray(flag), [flag]); - assert.deepStrictEqual(toArray(regionals), [pair[0], ' ', pair[1]]); - - assert.deepStrictEqual(words(flag), [flag]); - assert.deepStrictEqual(words(regionals), [pair[0], pair[1]]); - }); - - it('should account for variation selectors', function() { - assert.strictEqual(size(heart), 1); - assert.deepStrictEqual(toArray(heart), [heart]); - assert.deepStrictEqual(words(heart), [heart]); - }); - - it('should account for variation selectors with fitzpatrick modifiers', function() { - var values = lodashStable.map(fitzModifiers, function(modifier) { - return raisedHand + modifier; - }); - - var expected = lodashStable.map(values, function(value) { - return [1, [value], [value]]; - }); - - var actual = lodashStable.map(values, function(value) { - return [size(value), toArray(value), words(value)]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should match lone surrogates', function() { - var pair = hearts.split(''), - surrogates = pair[0] + ' ' + pair[1]; - - assert.strictEqual(size(surrogates), 3); - assert.deepStrictEqual(toArray(surrogates), [pair[0], ' ', pair[1]]); - assert.deepStrictEqual(words(surrogates), []); - }); - - it('should match side by side fitzpatrick modifiers separately ', function() { - var string = fitzModifiers[0] + fitzModifiers[0]; - assert.deepStrictEqual(toArray(string), [fitzModifiers[0], fitzModifiers[0]]); - }); -}); diff --git a/test/uncommon-symbols.spec.ts b/test/uncommon-symbols.spec.ts new file mode 100644 index 000000000..106c1108e --- /dev/null +++ b/test/uncommon-symbols.spec.ts @@ -0,0 +1,184 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { emojiVar, comboMarks, fitzModifiers } from './utils'; +import repeat from '../src/repeat'; +import camelCase from '../src/camelCase'; +import capitalize from '../src/capitalize'; +import pad from '../src/pad'; +import padStart from '../src/padStart'; +import padEnd from '../src/padEnd'; +import size from '../src/size'; +import split from '../src/split'; +import toArray from '../src/toArray'; +import trim from '../src/trim'; +import trimStart from '../src/trimStart'; +import trimEnd from '../src/trimEnd'; +import truncate from '../src/truncate'; +import words from '../src/words'; + +describe('uncommon symbols', () => { + const flag = '\ud83c\uddfa\ud83c\uddf8', + heart = `\u2764${emojiVar}`, + hearts = '\ud83d\udc95', + comboGlyph = `\ud83d\udc68\u200d${heart}\u200d\ud83d\udc8B\u200d\ud83d\udc68`, + hashKeycap = `#${emojiVar}\u20e3`, + leafs = '\ud83c\udf42', + mic = '\ud83c\udf99', + noMic = `${mic}\u20e0`, + raisedHand = `\u270B${emojiVar}`, + rocket = '\ud83d\ude80', + thumbsUp = '\ud83d\udc4d'; + + it('should account for astral symbols', () => { + const allHearts = repeat(hearts, 10), + chars = hearts + comboGlyph, + string = `A ${leafs}, ${comboGlyph}, and ${rocket}`, + trimChars = comboGlyph + hearts, + trimString = trimChars + string + trimChars; + + assert.strictEqual(camelCase(`${hearts} the ${leafs}`), `${hearts}The${leafs}`); + assert.strictEqual(camelCase(string), `a${leafs}${comboGlyph}And${rocket}`); + assert.strictEqual(capitalize(rocket), rocket); + + assert.strictEqual(pad(string, 16), ` ${string} `); + assert.strictEqual(padStart(string, 16), ` ${string}`); + assert.strictEqual(padEnd(string, 16), `${string} `); + + assert.strictEqual(pad(string, 16, chars), hearts + string + chars); + assert.strictEqual(padStart(string, 16, chars), chars + hearts + string); + assert.strictEqual(padEnd(string, 16, chars), string + chars + hearts); + + assert.strictEqual(size(string), 13); + assert.deepStrictEqual(split(string, ' '), [ + 'A', + `${leafs},`, + `${comboGlyph},`, + 'and', + rocket, + ]); + assert.deepStrictEqual(split(string, ' ', 3), ['A', `${leafs},`, `${comboGlyph},`]); + assert.deepStrictEqual(split(string, undefined), [string]); + assert.deepStrictEqual(split(string, undefined, -1), [string]); + assert.deepStrictEqual(split(string, undefined, 0), []); + + const expected = [ + 'A', + ' ', + leafs, + ',', + ' ', + comboGlyph, + ',', + ' ', + 'a', + 'n', + 'd', + ' ', + rocket, + ]; + + assert.deepStrictEqual(split(string, ''), expected); + assert.deepStrictEqual(split(string, '', 6), expected.slice(0, 6)); + assert.deepStrictEqual(toArray(string), expected); + + assert.strictEqual(trim(trimString, chars), string); + assert.strictEqual(trimStart(trimString, chars), string + trimChars); + assert.strictEqual(trimEnd(trimString, chars), trimChars + string); + + assert.strictEqual(truncate(string, { length: 13 }), string); + assert.strictEqual(truncate(string, { length: 6 }), `A ${leafs}...`); + + assert.deepStrictEqual(words(string), ['A', leafs, comboGlyph, 'and', rocket]); + assert.deepStrictEqual(toArray(hashKeycap), [hashKeycap]); + assert.deepStrictEqual(toArray(noMic), [noMic]); + + lodashStable.times(2, (index) => { + let separator = index ? RegExp(hearts) : hearts, + options = { length: 4, separator: separator }, + actual = truncate(string, options); + + assert.strictEqual(actual, 'A...'); + assert.strictEqual(actual.length, 4); + + actual = truncate(allHearts, options); + assert.strictEqual(actual, `${hearts}...`); + assert.strictEqual(actual.length, 5); + }); + }); + + it('should account for combining diacritical marks', () => { + const values = lodashStable.map(comboMarks, (mark) => `o${mark}`); + + const expected = lodashStable.map(values, (value) => [1, [value], [value]]); + + const actual = lodashStable.map(values, (value) => [ + size(value), + toArray(value), + words(value), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it('should account for fitzpatrick modifiers', () => { + const values = lodashStable.map(fitzModifiers, (modifier) => thumbsUp + modifier); + + const expected = lodashStable.map(values, (value) => [1, [value], [value]]); + + const actual = lodashStable.map(values, (value) => [ + size(value), + toArray(value), + words(value), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it('should account for regional symbols', () => { + const pair = flag.match(/\ud83c[\udde6-\uddff]/g), + regionals = pair.join(' '); + + assert.strictEqual(size(flag), 1); + assert.strictEqual(size(regionals), 3); + + assert.deepStrictEqual(toArray(flag), [flag]); + assert.deepStrictEqual(toArray(regionals), [pair[0], ' ', pair[1]]); + + assert.deepStrictEqual(words(flag), [flag]); + assert.deepStrictEqual(words(regionals), [pair[0], pair[1]]); + }); + + it('should account for variation selectors', () => { + assert.strictEqual(size(heart), 1); + assert.deepStrictEqual(toArray(heart), [heart]); + assert.deepStrictEqual(words(heart), [heart]); + }); + + it('should account for variation selectors with fitzpatrick modifiers', () => { + const values = lodashStable.map(fitzModifiers, (modifier) => raisedHand + modifier); + + const expected = lodashStable.map(values, (value) => [1, [value], [value]]); + + const actual = lodashStable.map(values, (value) => [ + size(value), + toArray(value), + words(value), + ]); + + assert.deepStrictEqual(actual, expected); + }); + + it('should match lone surrogates', () => { + const pair = hearts.split(''), + surrogates = `${pair[0]} ${pair[1]}`; + + assert.strictEqual(size(surrogates), 3); + assert.deepStrictEqual(toArray(surrogates), [pair[0], ' ', pair[1]]); + assert.deepStrictEqual(words(surrogates), []); + }); + + it('should match side by side fitzpatrick modifiers separately ', () => { + const string = fitzModifiers[0] + fitzModifiers[0]; + assert.deepStrictEqual(toArray(string), [fitzModifiers[0], fitzModifiers[0]]); + }); +}); diff --git a/test/unescape.js b/test/unescape.js deleted file mode 100644 index 7bd56137f..000000000 --- a/test/unescape.js +++ /dev/null @@ -1,40 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import unescape from '../unescape.js'; -import escape from '../escape.js'; - -describe('unescape', function() { - var escaped = '&<>"'/', - unescaped = '&<>"\'/'; - - escaped += escaped; - unescaped += unescaped; - - it('should unescape entities in order', function() { - assert.strictEqual(unescape('&lt;'), '<'); - }); - - it('should unescape the proper entities', function() { - assert.strictEqual(unescape(escaped), unescaped); - }); - - it('should handle strings with nothing to unescape', function() { - assert.strictEqual(unescape('abc'), 'abc'); - }); - - it('should unescape the same characters escaped by `_.escape`', function() { - assert.strictEqual(unescape(escape(unescaped)), unescaped); - }); - - it('should handle leading zeros in html entities', function() { - assert.strictEqual(unescape('''), "'"); - assert.strictEqual(unescape('''), "'"); - assert.strictEqual(unescape('''), "'"); - }); - - lodashStable.each(['`', '/'], function(entity) { - it('should not unescape the "' + entity + '" entity', function() { - assert.strictEqual(unescape(entity), entity); - }); - }); -}); diff --git a/test/unescape.spec.ts b/test/unescape.spec.ts new file mode 100644 index 000000000..d9fe73889 --- /dev/null +++ b/test/unescape.spec.ts @@ -0,0 +1,40 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import unescape from '../src/unescape'; +import escape from '../src/escape'; + +describe('unescape', () => { + let escaped = '&<>"'/', + unescaped = '&<>"\'/'; + + escaped += escaped; + unescaped += unescaped; + + it('should unescape entities in order', () => { + assert.strictEqual(unescape('&lt;'), '<'); + }); + + it('should unescape the proper entities', () => { + assert.strictEqual(unescape(escaped), unescaped); + }); + + it('should handle strings with nothing to unescape', () => { + assert.strictEqual(unescape('abc'), 'abc'); + }); + + it('should unescape the same characters escaped by `_.escape`', () => { + assert.strictEqual(unescape(escape(unescaped)), unescaped); + }); + + it('should handle leading zeros in html entities', () => { + assert.strictEqual(unescape('''), "'"); + assert.strictEqual(unescape('''), "'"); + assert.strictEqual(unescape('''), "'"); + }); + + lodashStable.each(['`', '/'], (entity) => { + it(`should not unescape the "${entity}" entity`, () => { + assert.strictEqual(unescape(entity), entity); + }); + }); +}); diff --git a/test/union-methods.js b/test/union-methods.js deleted file mode 100644 index fc872e278..000000000 --- a/test/union-methods.js +++ /dev/null @@ -1,31 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, args } from './utils.js'; - -describe('union methods', function() { - lodashStable.each(['union', 'unionBy', 'unionWith'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should return the union of two arrays', function() { - var actual = func([2], [1, 2]); - assert.deepStrictEqual(actual, [2, 1]); - }); - - it('`_.' + methodName + '` should return the union of multiple arrays', function() { - var actual = func([2], [1, 2], [2, 3]); - assert.deepStrictEqual(actual, [2, 1, 3]); - }); - - it('`_.' + methodName + '` should not flatten nested arrays', function() { - var actual = func([1, 3, 2], [1, [5]], [2, [4]]); - assert.deepStrictEqual(actual, [1, 3, 2, [5], [4]]); - }); - - it('`_.' + methodName + '` should ignore values that are not arrays or `arguments` objects', function() { - var array = [0]; - assert.deepStrictEqual(func(array, 3, { '0': 1 }, null), array); - assert.deepStrictEqual(func(null, array, null, [2, 1]), [0, 2, 1]); - assert.deepStrictEqual(func(array, null, args, null), [0, 1, 2, 3]); - }); - }); -}); diff --git a/test/union-methods.spec.ts b/test/union-methods.spec.ts new file mode 100644 index 000000000..92105cdd0 --- /dev/null +++ b/test/union-methods.spec.ts @@ -0,0 +1,31 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, args } from './utils'; + +describe('union methods', () => { + lodashStable.each(['union', 'unionBy', 'unionWith'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should return the union of two arrays`, () => { + const actual = func([2], [1, 2]); + assert.deepStrictEqual(actual, [2, 1]); + }); + + it(`\`_.${methodName}\` should return the union of multiple arrays`, () => { + const actual = func([2], [1, 2], [2, 3]); + assert.deepStrictEqual(actual, [2, 1, 3]); + }); + + it(`\`_.${methodName}\` should not flatten nested arrays`, () => { + const actual = func([1, 3, 2], [1, [5]], [2, [4]]); + assert.deepStrictEqual(actual, [1, 3, 2, [5], [4]]); + }); + + it(`\`_.${methodName}\` should ignore values that are not arrays or \`arguments\` objects`, () => { + const array = [0]; + assert.deepStrictEqual(func(array, 3, { '0': 1 }, null), array); + assert.deepStrictEqual(func(null, array, null, [2, 1]), [0, 2, 1]); + assert.deepStrictEqual(func(array, null, args, null), [0, 1, 2, 3]); + }); + }); +}); diff --git a/test/unionBy.js b/test/unionBy.js deleted file mode 100644 index 9dd5f8e55..000000000 --- a/test/unionBy.js +++ /dev/null @@ -1,28 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import unionBy from '../unionBy.js'; - -describe('unionBy', function() { - it('should accept an `iteratee`', function() { - var actual = unionBy([2.1], [1.2, 2.3], Math.floor); - assert.deepStrictEqual(actual, [2.1, 1.2]); - - actual = unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - assert.deepStrictEqual(actual, [{ 'x': 1 }, { 'x': 2 }]); - }); - - it('should provide correct `iteratee` arguments', function() { - var args; - - unionBy([2.1], [1.2, 2.3], function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [2.1]); - }); - - it('should output values from the first possible array', function() { - var actual = unionBy([{ 'x': 1, 'y': 1 }], [{ 'x': 1, 'y': 2 }], 'x'); - assert.deepStrictEqual(actual, [{ 'x': 1, 'y': 1 }]); - }); -}); diff --git a/test/unionBy.spec.ts b/test/unionBy.spec.ts new file mode 100644 index 000000000..6edee3079 --- /dev/null +++ b/test/unionBy.spec.ts @@ -0,0 +1,28 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import unionBy from '../src/unionBy'; + +describe('unionBy', () => { + it('should accept an `iteratee`', () => { + let actual = unionBy([2.1], [1.2, 2.3], Math.floor); + assert.deepStrictEqual(actual, [2.1, 1.2]); + + actual = unionBy([{ x: 1 }], [{ x: 2 }, { x: 1 }], 'x'); + assert.deepStrictEqual(actual, [{ x: 1 }, { x: 2 }]); + }); + + it('should provide correct `iteratee` arguments', () => { + let args; + + unionBy([2.1], [1.2, 2.3], function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [2.1]); + }); + + it('should output values from the first possible array', () => { + const actual = unionBy([{ x: 1, y: 1 }], [{ x: 1, y: 2 }], 'x'); + assert.deepStrictEqual(actual, [{ x: 1, y: 1 }]); + }); +}); diff --git a/test/unionWith.spec.ts b/test/unionWith.spec.ts new file mode 100644 index 000000000..dc9711cac --- /dev/null +++ b/test/unionWith.spec.ts @@ -0,0 +1,28 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import unionWith from '../src/unionWith'; + +describe('unionWith', () => { + it('should work with a `comparator`', () => { + const objects = [ + { x: 1, y: 2 }, + { x: 2, y: 1 }, + ], + others = [ + { x: 1, y: 1 }, + { x: 1, y: 2 }, + ], + actual = unionWith(objects, others, lodashStable.isEqual); + + assert.deepStrictEqual(actual, [objects[0], objects[1], others[0]]); + }); + + it('should output values from the first possible array', () => { + const objects = [{ x: 1, y: 1 }], + others = [{ x: 1, y: 2 }]; + + const actual = unionWith(objects, others, (a, b) => a.x == b.x); + + assert.deepStrictEqual(actual, [{ x: 1, y: 1 }]); + }); +}); diff --git a/test/unionWith.test.js b/test/unionWith.test.js deleted file mode 100644 index e5f4d9664..000000000 --- a/test/unionWith.test.js +++ /dev/null @@ -1,24 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import unionWith from '../unionWith.js'; - -describe('unionWith', function() { - it('should work with a `comparator`', function() { - var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }], - others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }], - actual = unionWith(objects, others, lodashStable.isEqual); - - assert.deepStrictEqual(actual, [objects[0], objects[1], others[0]]); - }); - - it('should output values from the first possible array', function() { - var objects = [{ 'x': 1, 'y': 1 }], - others = [{ 'x': 1, 'y': 2 }]; - - var actual = unionWith(objects, others, function(a, b) { - return a.x == b.x; - }); - - assert.deepStrictEqual(actual, [{ 'x': 1, 'y': 1 }]); - }); -}); diff --git a/test/uniq-methods.js b/test/uniq-methods.js deleted file mode 100644 index 6949a311f..000000000 --- a/test/uniq-methods.js +++ /dev/null @@ -1,123 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, LARGE_ARRAY_SIZE, isEven } from './utils.js'; -import sortBy from '../sortBy.js'; - -describe('uniq methods', function() { - lodashStable.each(['uniq', 'uniqBy', 'uniqWith', 'sortedUniq', 'sortedUniqBy'], function(methodName) { - var func = _[methodName], - isSorted = /^sorted/.test(methodName), - objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; - - if (isSorted) { - objects = sortBy(objects, 'a'); - } - else { - it('`_.' + methodName + '` should return unique values of an unsorted array', function() { - var array = [2, 1, 2]; - assert.deepStrictEqual(func(array), [2, 1]); - }); - } - it('`_.' + methodName + '` should return unique values of a sorted array', function() { - var array = [1, 2, 2]; - assert.deepStrictEqual(func(array), [1, 2]); - }); - - it('`_.' + methodName + '` should treat object instances as unique', function() { - assert.deepStrictEqual(func(objects), objects); - }); - - it('`_.' + methodName + '` should treat `-0` as `0`', function() { - var actual = lodashStable.map(func([-0, 0]), lodashStable.toString); - assert.deepStrictEqual(actual, ['0']); - }); - - it('`_.' + methodName + '` should match `NaN`', function() { - assert.deepStrictEqual(func([NaN, NaN]), [NaN]); - }); - - it('`_.' + methodName + '` should work with large arrays', function() { - var largeArray = [], - expected = [0, {}, 'a'], - count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); - - lodashStable.each(expected, function(value) { - lodashStable.times(count, function() { - largeArray.push(value); - }); - }); - - assert.deepStrictEqual(func(largeArray), expected); - }); - - it('`_.' + methodName + '` should work with large arrays of `-0` as `0`', function() { - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { - return isEven(index) ? -0 : 0; - }); - - var actual = lodashStable.map(func(largeArray), lodashStable.toString); - assert.deepStrictEqual(actual, ['0']); - }); - - it('`_.' + methodName + '` should work with large arrays of boolean, `NaN`, and nullish values', function() { - var largeArray = [], - expected = [null, undefined, false, true, NaN], - count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); - - lodashStable.each(expected, function(value) { - lodashStable.times(count, function() { - largeArray.push(value); - }); - }); - - assert.deepStrictEqual(func(largeArray), expected); - }); - - it('`_.' + methodName + '` should work with large arrays of symbols', function() { - if (Symbol) { - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, Symbol); - assert.deepStrictEqual(func(largeArray), largeArray); - } - }); - - it('`_.' + methodName + '` should work with large arrays of well-known symbols', function() { - // See http://www.ecma-international.org/ecma-262/6.0/#sec-well-known-symbols. - if (Symbol) { - var expected = [ - Symbol.hasInstance, Symbol.isConcatSpreadable, Symbol.iterator, - Symbol.match, Symbol.replace, Symbol.search, Symbol.species, - Symbol.split, Symbol.toPrimitive, Symbol.toStringTag, Symbol.unscopables - ]; - - var largeArray = [], - count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); - - expected = lodashStable.map(expected, function(symbol) { - return symbol || {}; - }); - - lodashStable.each(expected, function(value) { - lodashStable.times(count, function() { - largeArray.push(value); - }); - }); - - assert.deepStrictEqual(func(largeArray), expected); - } - }); - - it('`_.' + methodName + '` should distinguish between numbers and numeric strings', function() { - var largeArray = [], - expected = ['2', 2, Object('2'), Object(2)], - count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); - - lodashStable.each(expected, function(value) { - lodashStable.times(count, function() { - largeArray.push(value); - }); - }); - - assert.deepStrictEqual(func(largeArray), expected); - }); - }); -}); diff --git a/test/uniq-methods.spec.ts b/test/uniq-methods.spec.ts new file mode 100644 index 000000000..e624969a2 --- /dev/null +++ b/test/uniq-methods.spec.ts @@ -0,0 +1,131 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, LARGE_ARRAY_SIZE, isEven } from './utils'; +import sortBy from '../src/sortBy'; + +describe('uniq methods', () => { + lodashStable.each( + ['uniq', 'uniqBy', 'uniqWith', 'sortedUniq', 'sortedUniqBy'], + (methodName) => { + let func = _[methodName], + isSorted = /^sorted/.test(methodName), + objects = [{ a: 2 }, { a: 3 }, { a: 1 }, { a: 2 }, { a: 3 }, { a: 1 }]; + + if (isSorted) { + objects = sortBy(objects, 'a'); + } else { + it(`\`_.${methodName}\` should return unique values of an unsorted array`, () => { + const array = [2, 1, 2]; + assert.deepStrictEqual(func(array), [2, 1]); + }); + } + it(`\`_.${methodName}\` should return unique values of a sorted array`, () => { + const array = [1, 2, 2]; + assert.deepStrictEqual(func(array), [1, 2]); + }); + + it(`\`_.${methodName}\` should treat object instances as unique`, () => { + assert.deepStrictEqual(func(objects), objects); + }); + + it(`\`_.${methodName}\` should treat \`-0\` as \`0\``, () => { + const actual = lodashStable.map(func([-0, 0]), lodashStable.toString); + assert.deepStrictEqual(actual, ['0']); + }); + + it(`\`_.${methodName}\` should match \`NaN\``, () => { + assert.deepStrictEqual(func([NaN, NaN]), [NaN]); + }); + + it(`\`_.${methodName}\` should work with large arrays`, () => { + const largeArray = [], + expected = [0, {}, 'a'], + count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); + + lodashStable.each(expected, (value) => { + lodashStable.times(count, () => { + largeArray.push(value); + }); + }); + + assert.deepStrictEqual(func(largeArray), expected); + }); + + it(`\`_.${methodName}\` should work with large arrays of \`-0\` as \`0\``, () => { + const largeArray = lodashStable.times(LARGE_ARRAY_SIZE, (index) => + isEven(index) ? -0 : 0, + ); + + const actual = lodashStable.map(func(largeArray), lodashStable.toString); + assert.deepStrictEqual(actual, ['0']); + }); + + it(`\`_.${methodName}\` should work with large arrays of boolean, \`NaN\`, and nullish values`, () => { + const largeArray = [], + expected = [null, undefined, false, true, NaN], + count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); + + lodashStable.each(expected, (value) => { + lodashStable.times(count, () => { + largeArray.push(value); + }); + }); + + assert.deepStrictEqual(func(largeArray), expected); + }); + + it(`\`_.${methodName}\` should work with large arrays of symbols`, () => { + if (Symbol) { + const largeArray = lodashStable.times(LARGE_ARRAY_SIZE, Symbol); + assert.deepStrictEqual(func(largeArray), largeArray); + } + }); + + it(`\`_.${methodName}\` should work with large arrays of well-known symbols`, () => { + // See http://www.ecma-international.org/ecma-262/6.0/#sec-well-known-symbols. + if (Symbol) { + let expected = [ + Symbol.hasInstance, + Symbol.isConcatSpreadable, + Symbol.iterator, + Symbol.match, + Symbol.replace, + Symbol.search, + Symbol.species, + Symbol.split, + Symbol.toPrimitive, + Symbol.toStringTag, + Symbol.unscopables, + ]; + + const largeArray = [], + count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); + + expected = lodashStable.map(expected, (symbol) => symbol || {}); + + lodashStable.each(expected, (value) => { + lodashStable.times(count, () => { + largeArray.push(value); + }); + }); + + assert.deepStrictEqual(func(largeArray), expected); + } + }); + + it(`\`_.${methodName}\` should distinguish between numbers and numeric strings`, () => { + const largeArray = [], + expected = ['2', 2, Object('2'), Object(2)], + count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); + + lodashStable.each(expected, (value) => { + lodashStable.times(count, () => { + largeArray.push(value); + }); + }); + + assert.deepStrictEqual(func(largeArray), expected); + }); + }, + ); +}); diff --git a/test/uniq.js b/test/uniq.js deleted file mode 100644 index 5eaf74c41..000000000 --- a/test/uniq.js +++ /dev/null @@ -1,11 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; - -describe('uniq', function() { - it('should perform an unsorted uniq when used as an iteratee for methods like `_.map`', function() { - var array = [[2, 1, 2], [1, 2, 1]], - actual = lodashStable.map(array, lodashStable.uniq); - - assert.deepStrictEqual(actual, [[2, 1], [1, 2]]); - }); -}); diff --git a/test/uniq.spec.ts b/test/uniq.spec.ts new file mode 100644 index 000000000..208a7554e --- /dev/null +++ b/test/uniq.spec.ts @@ -0,0 +1,17 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; + +describe('uniq', () => { + it('should perform an unsorted uniq when used as an iteratee for methods like `_.map`', () => { + const array = [ + [2, 1, 2], + [1, 2, 1], + ], + actual = lodashStable.map(array, lodashStable.uniq); + + assert.deepStrictEqual(actual, [ + [2, 1], + [1, 2], + ]); + }); +}); diff --git a/test/uniqBy-methods.js b/test/uniqBy-methods.js deleted file mode 100644 index 046ae644d..000000000 --- a/test/uniqBy-methods.js +++ /dev/null @@ -1,74 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, LARGE_ARRAY_SIZE, slice } from './utils.js'; -import sortBy from '../sortBy.js'; - -describe('uniqBy methods', function() { - lodashStable.each(['uniqBy', 'sortedUniqBy'], function(methodName) { - var func = _[methodName], - isSorted = methodName == 'sortedUniqBy', - objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; - - if (isSorted) { - objects = sortBy(objects, 'a'); - } - it('`_.' + methodName + '` should work with an `iteratee`', function() { - var expected = isSorted ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3); - - var actual = func(objects, function(object) { - return object.a; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should work with large arrays', function() { - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, function() { - return [1, 2]; - }); - - var actual = func(largeArray, String); - assert.strictEqual(actual[0], largeArray[0]); - assert.deepStrictEqual(actual, [[1, 2]]); - }); - - it('`_.' + methodName + '` should provide correct `iteratee` arguments', function() { - var args; - - func(objects, function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [objects[0]]); - }); - - it('`_.' + methodName + '` should work with `_.property` shorthands', function() { - var expected = isSorted ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3), - actual = func(objects, 'a'); - - assert.deepStrictEqual(actual, expected); - - var arrays = [[2], [3], [1], [2], [3], [1]]; - if (isSorted) { - arrays = lodashStable.sortBy(arrays, 0); - } - expected = isSorted ? [[1], [2], [3]] : arrays.slice(0, 3); - actual = func(arrays, 0); - - assert.deepStrictEqual(actual, expected); - }); - - lodashStable.each({ - 'an array': [0, 'a'], - 'an object': { '0': 'a' }, - 'a number': 0, - 'a string': '0' - }, - function(iteratee, key) { - it('`_.' + methodName + '` should work with ' + key + ' for `iteratee`', function() { - var actual = func([['a'], ['a'], ['b']], iteratee); - assert.deepStrictEqual(actual, [['a'], ['b']]); - }); - }); - }); -}); diff --git a/test/uniqBy-methods.spec.ts b/test/uniqBy-methods.spec.ts new file mode 100644 index 000000000..e8c227df9 --- /dev/null +++ b/test/uniqBy-methods.spec.ts @@ -0,0 +1,72 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, LARGE_ARRAY_SIZE, slice } from './utils'; +import sortBy from '../src/sortBy'; + +describe('uniqBy methods', () => { + lodashStable.each(['uniqBy', 'sortedUniqBy'], (methodName) => { + let func = _[methodName], + isSorted = methodName == 'sortedUniqBy', + objects = [{ a: 2 }, { a: 3 }, { a: 1 }, { a: 2 }, { a: 3 }, { a: 1 }]; + + if (isSorted) { + objects = sortBy(objects, 'a'); + } + it(`\`_.${methodName}\` should work with an \`iteratee\``, () => { + const expected = isSorted ? [{ a: 1 }, { a: 2 }, { a: 3 }] : objects.slice(0, 3); + + const actual = func(objects, (object) => object.a); + + assert.deepStrictEqual(actual, expected); + }); + + it('should work with large arrays', () => { + const largeArray = lodashStable.times(LARGE_ARRAY_SIZE, () => [1, 2]); + + const actual = func(largeArray, String); + assert.strictEqual(actual[0], largeArray[0]); + assert.deepStrictEqual(actual, [[1, 2]]); + }); + + it(`\`_.${methodName}\` should provide correct \`iteratee\` arguments`, () => { + let args; + + func(objects, function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [objects[0]]); + }); + + it(`\`_.${methodName}\` should work with \`_.property\` shorthands`, () => { + let expected = isSorted ? [{ a: 1 }, { a: 2 }, { a: 3 }] : objects.slice(0, 3), + actual = func(objects, 'a'); + + assert.deepStrictEqual(actual, expected); + + let arrays = [[2], [3], [1], [2], [3], [1]]; + if (isSorted) { + arrays = lodashStable.sortBy(arrays, 0); + } + expected = isSorted ? [[1], [2], [3]] : arrays.slice(0, 3); + actual = func(arrays, 0); + + assert.deepStrictEqual(actual, expected); + }); + + lodashStable.each( + { + 'an array': [0, 'a'], + 'an object': { '0': 'a' }, + 'a number': 0, + 'a string': '0', + }, + (iteratee, key) => { + it(`\`_.${methodName}\` should work with ${key} for \`iteratee\``, () => { + const actual = func([['a'], ['a'], ['b']], iteratee); + assert.deepStrictEqual(actual, [['a'], ['b']]); + }); + }, + ); + }); +}); diff --git a/test/uniqWith.spec.ts b/test/uniqWith.spec.ts new file mode 100644 index 000000000..60d03c5db --- /dev/null +++ b/test/uniqWith.spec.ts @@ -0,0 +1,32 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { LARGE_ARRAY_SIZE, isEven } from './utils'; +import uniqWith from '../src/uniqWith'; + +describe('uniqWith', () => { + it('should work with a `comparator`', () => { + const objects = [ + { x: 1, y: 2 }, + { x: 2, y: 1 }, + { x: 1, y: 2 }, + ], + actual = uniqWith(objects, lodashStable.isEqual); + + assert.deepStrictEqual(actual, [objects[0], objects[1]]); + }); + + it('should preserve the sign of `0`', () => { + const largeArray = lodashStable.times(LARGE_ARRAY_SIZE, (index) => + isEven(index) ? -0 : 0, + ); + + const arrays = [[-0, 0], largeArray], + expected = lodashStable.map(arrays, lodashStable.constant(['-0'])); + + const actual = lodashStable.map(arrays, (array) => + lodashStable.map(uniqWith(array, lodashStable.eq), lodashStable.toString), + ); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/uniqWith.test.js b/test/uniqWith.test.js deleted file mode 100644 index bb9e79873..000000000 --- a/test/uniqWith.test.js +++ /dev/null @@ -1,28 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { LARGE_ARRAY_SIZE, isEven } from './utils.js'; -import uniqWith from '../uniqWith.js'; - -describe('uniqWith', function() { - it('should work with a `comparator`', function() { - var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }], - actual = uniqWith(objects, lodashStable.isEqual); - - assert.deepStrictEqual(actual, [objects[0], objects[1]]); - }); - - it('should preserve the sign of `0`', function() { - var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { - return isEven(index) ? -0 : 0; - }); - - var arrays = [[-0, 0], largeArray], - expected = lodashStable.map(arrays, lodashStable.constant(['-0'])); - - var actual = lodashStable.map(arrays, function(array) { - return lodashStable.map(uniqWith(array, lodashStable.eq), lodashStable.toString); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/uniqueId.spec.ts b/test/uniqueId.spec.ts new file mode 100644 index 000000000..3bbacf2a6 --- /dev/null +++ b/test/uniqueId.spec.ts @@ -0,0 +1,20 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import uniqueId from '../src/uniqueId'; + +describe('uniqueId', () => { + it('should generate unique ids', () => { + const actual = lodashStable.times(1000, () => uniqueId()); + + assert.strictEqual(lodashStable.uniq(actual).length, actual.length); + }); + + it('should return a string value when not providing a `prefix`', () => { + assert.strictEqual(typeof uniqueId(), 'string'); + }); + + it('should coerce the prefix argument to a string', () => { + const actual = [uniqueId(3), uniqueId(2), uniqueId(1)]; + assert.ok(/3\d+,2\d+,1\d+/.test(actual)); + }); +}); diff --git a/test/uniqueId.test.js b/test/uniqueId.test.js deleted file mode 100644 index 4b0485b82..000000000 --- a/test/uniqueId.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import uniqueId from '../uniqueId.js'; - -describe('uniqueId', function() { - it('should generate unique ids', function() { - var actual = lodashStable.times(1000, function() { - return uniqueId(); - }); - - assert.strictEqual(lodashStable.uniq(actual).length, actual.length); - }); - - it('should return a string value when not providing a `prefix`', function() { - assert.strictEqual(typeof uniqueId(), 'string'); - }); - - it('should coerce the prefix argument to a string', function() { - var actual = [uniqueId(3), uniqueId(2), uniqueId(1)]; - assert.ok(/3\d+,2\d+,1\d+/.test(actual)); - }); -}); diff --git a/test/unset.js b/test/unset.js deleted file mode 100644 index 0aa2f5bd7..000000000 --- a/test/unset.js +++ /dev/null @@ -1,119 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { symbol, numberProto, stringProto, defineProperty } from './utils.js'; -import unset from '../unset.js'; - -describe('unset', function() { - it('should unset property values', function() { - lodashStable.each(['a', ['a']], function(path) { - var object = { 'a': 1, 'c': 2 }; - assert.strictEqual(unset(object, path), true); - assert.deepStrictEqual(object, { 'c': 2 }); - }); - }); - - it('should preserve the sign of `0`', function() { - var props = [-0, Object(-0), 0, Object(0)], - expected = lodashStable.map(props, lodashStable.constant([true, false])); - - var actual = lodashStable.map(props, function(key) { - var object = { '-0': 'a', '0': 'b' }; - return [unset(object, key), lodashStable.toString(key) in object]; - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should unset symbol keyed property values', function() { - if (Symbol) { - var object = {}; - object[symbol] = 1; - - assert.strictEqual(unset(object, symbol), true); - assert.ok(!(symbol in object)); - } - }); - - it('should unset deep property values', function() { - lodashStable.each(['a.b', ['a', 'b']], function(path) { - var object = { 'a': { 'b': null } }; - assert.strictEqual(unset(object, path), true); - assert.deepStrictEqual(object, { 'a': {} }); - }); - }); - - it('should handle complex paths', function() { - var paths = [ - 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', - ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'] - ]; - - lodashStable.each(paths, function(path) { - var object = { 'a': { '-1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } }; - assert.strictEqual(unset(object, path), true); - assert.ok(!('g' in object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f)); - }); - }); - - it('should return `true` for nonexistent paths', function() { - var object = { 'a': { 'b': { 'c': null } } }; - - lodashStable.each(['z', 'a.z', 'a.b.z', 'a.b.c.z'], function(path) { - assert.strictEqual(unset(object, path), true); - }); - - assert.deepStrictEqual(object, { 'a': { 'b': { 'c': null } } }); - }); - - it('should not error when `object` is nullish', function() { - var values = [null, undefined], - expected = [[true, true], [true, true]]; - - var actual = lodashStable.map(values, function(value) { - try { - return [unset(value, 'a.b'), unset(value, ['a', 'b'])]; - } catch (e) { - return e.message; - } - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should follow `path` over non-plain objects', function() { - var object = { 'a': '' }, - paths = ['constructor.prototype.a', ['constructor', 'prototype', 'a']]; - - lodashStable.each(paths, function(path) { - numberProto.a = 1; - - var actual = unset(0, path); - assert.strictEqual(actual, true); - assert.ok(!('a' in numberProto)); - - delete numberProto.a; - }); - - lodashStable.each(['a.replace.b', ['a', 'replace', 'b']], function(path) { - stringProto.replace.b = 1; - - var actual = unset(object, path); - assert.strictEqual(actual, true); - assert.ok(!('a' in stringProto.replace)); - - delete stringProto.replace.b; - }); - }); - - it('should return `false` for non-configurable properties', function() { - var object = {}; - - defineProperty(object, 'a', { - 'configurable': false, - 'enumerable': true, - 'writable': true, - 'value': 1, - }); - assert.strictEqual(unset(object, 'a'), false); - }); -}); diff --git a/test/unset.spec.ts b/test/unset.spec.ts new file mode 100644 index 000000000..2ea8b0f25 --- /dev/null +++ b/test/unset.spec.ts @@ -0,0 +1,124 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { symbol, numberProto, stringProto, defineProperty } from './utils'; +import unset from '../src/unset'; + +describe('unset', () => { + it('should unset property values', () => { + lodashStable.each(['a', ['a']], (path) => { + const object = { a: 1, c: 2 }; + assert.strictEqual(unset(object, path), true); + assert.deepStrictEqual(object, { c: 2 }); + }); + }); + + it('should preserve the sign of `0`', () => { + const props = [-0, Object(-0), 0, Object(0)], + expected = lodashStable.map(props, lodashStable.constant([true, false])); + + const actual = lodashStable.map(props, (key) => { + const object = { '-0': 'a', '0': 'b' }; + return [unset(object, key), lodashStable.toString(key) in object]; + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should unset symbol keyed property values', () => { + if (Symbol) { + const object = {}; + object[symbol] = 1; + + assert.strictEqual(unset(object, symbol), true); + assert.ok(!(symbol in object)); + } + }); + + it('should unset deep property values', () => { + lodashStable.each(['a.b', ['a', 'b']], (path) => { + const object = { a: { b: null } }; + assert.strictEqual(unset(object, path), true); + assert.deepStrictEqual(object, { a: {} }); + }); + }); + + it('should handle complex paths', () => { + const paths = [ + 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', + ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'], + ]; + + lodashStable.each(paths, (path) => { + const object = { + a: { '-1.23': { '["b"]': { c: { "['d']": { '\ne\n': { f: { g: 8 } } } } } } }, + }; + assert.strictEqual(unset(object, path), true); + assert.ok(!('g' in object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f)); + }); + }); + + it('should return `true` for nonexistent paths', () => { + const object = { a: { b: { c: null } } }; + + lodashStable.each(['z', 'a.z', 'a.b.z', 'a.b.c.z'], (path) => { + assert.strictEqual(unset(object, path), true); + }); + + assert.deepStrictEqual(object, { a: { b: { c: null } } }); + }); + + it('should not error when `object` is nullish', () => { + const values = [null, undefined], + expected = [ + [true, true], + [true, true], + ]; + + const actual = lodashStable.map(values, (value) => { + try { + return [unset(value, 'a.b'), unset(value, ['a', 'b'])]; + } catch (e) { + return e.message; + } + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should follow `path` over non-plain objects', () => { + const object = { a: '' }, + paths = ['constructor.prototype.a', ['constructor', 'prototype', 'a']]; + + lodashStable.each(paths, (path) => { + numberProto.a = 1; + + const actual = unset(0, path); + assert.strictEqual(actual, true); + assert.ok(!('a' in numberProto)); + + delete numberProto.a; + }); + + lodashStable.each(['a.replace.b', ['a', 'replace', 'b']], (path) => { + stringProto.replace.b = 1; + + const actual = unset(object, path); + assert.strictEqual(actual, true); + assert.ok(!('a' in stringProto.replace)); + + delete stringProto.replace.b; + }); + }); + + it('should return `false` for non-configurable properties', () => { + const object = {}; + + defineProperty(object, 'a', { + configurable: false, + enumerable: true, + writable: true, + value: 1, + }); + assert.strictEqual(unset(object, 'a'), false); + }); +}); diff --git a/test/unzip-and-zip.js b/test/unzip-and-zip.js deleted file mode 100644 index 57cdfd6ef..000000000 --- a/test/unzip-and-zip.js +++ /dev/null @@ -1,72 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, falsey, stubArray } from './utils.js'; - -describe('unzip and zip', function() { - lodashStable.each(['unzip', 'zip'], function(methodName, index) { - var func = _[methodName]; - func = lodashStable.bind(index ? func.apply : func.call, func, null); - - var object = { - 'an empty array': [ - [], - [] - ], - '0-tuples': [ - [[], []], - [] - ], - '2-tuples': [ - [['barney', 'fred'], [36, 40]], - [['barney', 36], ['fred', 40]] - ], - '3-tuples': [ - [['barney', 'fred'], [36, 40], [false, true]], - [['barney', 36, false], ['fred', 40, true]] - ] - }; - - lodashStable.forOwn(object, function(pair, key) { - it('`_.' + methodName + '` should work with ' + key, function() { - var actual = func(pair[0]); - assert.deepStrictEqual(actual, pair[1]); - assert.deepStrictEqual(func(actual), actual.length ? pair[0] : []); - }); - }); - - it('`_.' + methodName + '` should work with tuples of different lengths', function() { - var pair = [ - [['barney', 36], ['fred', 40, false]], - [['barney', 'fred'], [36, 40], [undefined, false]] - ]; - - var actual = func(pair[0]); - assert.ok('0' in actual[2]); - assert.deepStrictEqual(actual, pair[1]); - - actual = func(actual); - assert.ok('2' in actual[0]); - assert.deepStrictEqual(actual, [['barney', 36, undefined], ['fred', 40, false]]); - }); - - it('`_.' + methodName + '` should treat falsey values as empty arrays', function() { - var expected = lodashStable.map(falsey, stubArray); - - var actual = lodashStable.map(falsey, function(value) { - return func([value, value, value]); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should ignore values that are not arrays or `arguments` objects', function() { - var array = [[1, 2], [3, 4], null, undefined, { '0': 1 }]; - assert.deepStrictEqual(func(array), [[1, 3], [2, 4]]); - }); - - it('`_.' + methodName + '` should support consuming its return value', function() { - var expected = [['barney', 'fred'], [36, 40]]; - assert.deepStrictEqual(func(func(func(func(expected)))), expected); - }); - }); -}); diff --git a/test/unzip-and-zip.spec.ts b/test/unzip-and-zip.spec.ts new file mode 100644 index 000000000..2b60777a5 --- /dev/null +++ b/test/unzip-and-zip.spec.ts @@ -0,0 +1,93 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, falsey, stubArray } from './utils'; + +describe('unzip and zip', () => { + lodashStable.each(['unzip', 'zip'], (methodName, index) => { + let func = _[methodName]; + func = lodashStable.bind(index ? func.apply : func.call, func, null); + + const object = { + 'an empty array': [[], []], + '0-tuples': [[[], []], []], + '2-tuples': [ + [ + ['barney', 'fred'], + [36, 40], + ], + [ + ['barney', 36], + ['fred', 40], + ], + ], + '3-tuples': [ + [ + ['barney', 'fred'], + [36, 40], + [false, true], + ], + [ + ['barney', 36, false], + ['fred', 40, true], + ], + ], + }; + + lodashStable.forOwn(object, (pair, key) => { + it(`\`_.${methodName}\` should work with ${key}`, () => { + const actual = func(pair[0]); + assert.deepStrictEqual(actual, pair[1]); + assert.deepStrictEqual(func(actual), actual.length ? pair[0] : []); + }); + }); + + it(`\`_.${methodName}\` should work with tuples of different lengths`, () => { + const pair = [ + [ + ['barney', 36], + ['fred', 40, false], + ], + [ + ['barney', 'fred'], + [36, 40], + [undefined, false], + ], + ]; + + let actual = func(pair[0]); + assert.ok('0' in actual[2]); + assert.deepStrictEqual(actual, pair[1]); + + actual = func(actual); + assert.ok('2' in actual[0]); + assert.deepStrictEqual(actual, [ + ['barney', 36, undefined], + ['fred', 40, false], + ]); + }); + + it(`\`_.${methodName}\` should treat falsey values as empty arrays`, () => { + const expected = lodashStable.map(falsey, stubArray); + + const actual = lodashStable.map(falsey, (value) => func([value, value, value])); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should ignore values that are not arrays or \`arguments\` objects`, () => { + const array = [[1, 2], [3, 4], null, undefined, { '0': 1 }]; + assert.deepStrictEqual(func(array), [ + [1, 3], + [2, 4], + ]); + }); + + it(`\`_.${methodName}\` should support consuming its return value`, () => { + const expected = [ + ['barney', 'fred'], + [36, 40], + ]; + assert.deepStrictEqual(func(func(func(func(expected)))), expected); + }); + }); +}); diff --git a/test/unzipWith.js b/test/unzipWith.js deleted file mode 100644 index d02d1a76a..000000000 --- a/test/unzipWith.js +++ /dev/null @@ -1,39 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice } from './utils.js'; -import unzipWith from '../unzipWith.js'; -import unzip from '../unzip.js'; - -describe('unzipWith', function() { - it('should unzip arrays combining regrouped elements with `iteratee`', function() { - var array = [[1, 4], [2, 5], [3, 6]]; - - var actual = unzipWith(array, function(a, b, c) { - return a + b + c; - }); - - assert.deepStrictEqual(actual, [6, 15]); - }); - - it('should provide correct `iteratee` arguments', function() { - var args; - - unzipWith([[1, 3, 5], [2, 4, 6]], function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [1, 2]); - }); - - it('should perform a basic unzip when `iteratee` is nullish', function() { - var array = [[1, 3], [2, 4]], - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant(unzip(array))); - - var actual = lodashStable.map(values, function(value, index) { - return index ? unzipWith(array, value) : unzipWith(array); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/unzipWith.spec.ts b/test/unzipWith.spec.ts new file mode 100644 index 000000000..c1a9842d4 --- /dev/null +++ b/test/unzipWith.spec.ts @@ -0,0 +1,50 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice } from './utils'; +import unzipWith from '../src/unzipWith'; +import unzip from '../src/unzip'; + +describe('unzipWith', () => { + it('should unzip arrays combining regrouped elements with `iteratee`', () => { + const array = [ + [1, 4], + [2, 5], + [3, 6], + ]; + + const actual = unzipWith(array, (a, b, c) => a + b + c); + + assert.deepStrictEqual(actual, [6, 15]); + }); + + it('should provide correct `iteratee` arguments', () => { + let args; + + unzipWith( + [ + [1, 3, 5], + [2, 4, 6], + ], + function () { + args || (args = slice.call(arguments)); + }, + ); + + assert.deepStrictEqual(args, [1, 2]); + }); + + it('should perform a basic unzip when `iteratee` is nullish', () => { + const array = [ + [1, 3], + [2, 4], + ], + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant(unzip(array))); + + const actual = lodashStable.map(values, (value, index) => + index ? unzipWith(array, value) : unzipWith(array), + ); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/test/update-methods.js b/test/update-methods.js deleted file mode 100644 index 159f4008a..000000000 --- a/test/update-methods.js +++ /dev/null @@ -1,25 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _ } from './utils.js'; - -describe('update methods', function() { - lodashStable.each(['update', 'updateWith'], function(methodName) { - var func = _[methodName], - oldValue = 1; - - it('`_.' + methodName + '` should invoke `updater` with the value on `path` of `object`', function() { - var object = { 'a': [{ 'b': { 'c': oldValue } }] }, - expected = oldValue + 1; - - lodashStable.each(['a[0].b.c', ['a', '0', 'b', 'c']], function(path) { - func(object, path, function(n) { - assert.strictEqual(n, oldValue); - return ++n; - }); - - assert.strictEqual(object.a[0].b.c, expected); - object.a[0].b.c = oldValue; - }); - }); - }); -}); diff --git a/test/update-methods.spec.ts b/test/update-methods.spec.ts new file mode 100644 index 000000000..e3659d649 --- /dev/null +++ b/test/update-methods.spec.ts @@ -0,0 +1,25 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _ } from './utils'; + +describe('update methods', () => { + lodashStable.each(['update', 'updateWith'], (methodName) => { + const func = _[methodName], + oldValue = 1; + + it(`\`_.${methodName}\` should invoke \`updater\` with the value on \`path\` of \`object\``, () => { + const object = { a: [{ b: { c: oldValue } }] }, + expected = oldValue + 1; + + lodashStable.each(['a[0].b.c', ['a', '0', 'b', 'c']], (path) => { + func(object, path, (n) => { + assert.strictEqual(n, oldValue); + return ++n; + }); + + assert.strictEqual(object.a[0].b.c, expected); + object.a[0].b.c = oldValue; + }); + }); + }); +}); diff --git a/test/updateWith.js b/test/updateWith.js deleted file mode 100644 index 7c709f91d..000000000 --- a/test/updateWith.js +++ /dev/null @@ -1,19 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { stubThree, stubFour, noop } from './utils.js'; -import updateWith from '../updateWith.js'; - -describe('updateWith', function() { - it('should work with a `customizer` callback', function() { - var actual = updateWith({ '0': {} }, '[0][1][2]', stubThree, function(value) { - return lodashStable.isObject(value) ? undefined : {}; - }); - - assert.deepStrictEqual(actual, { '0': { '1': { '2': 3 } } }); - }); - - it('should work with a `customizer` that returns `undefined`', function() { - var actual = updateWith({}, 'a[0].b.c', stubFour, noop); - assert.deepStrictEqual(actual, { 'a': [{ 'b': { 'c': 4 } }] }); - }); -}); diff --git a/test/updateWith.spec.ts b/test/updateWith.spec.ts new file mode 100644 index 000000000..29af12d8c --- /dev/null +++ b/test/updateWith.spec.ts @@ -0,0 +1,19 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { stubThree, stubFour, noop } from './utils'; +import updateWith from '../src/updateWith'; + +describe('updateWith', () => { + it('should work with a `customizer` callback', () => { + const actual = updateWith({ '0': {} }, '[0][1][2]', stubThree, (value) => + lodashStable.isObject(value) ? undefined : {}, + ); + + assert.deepStrictEqual(actual, { '0': { '1': { '2': 3 } } }); + }); + + it('should work with a `customizer` that returns `undefined`', () => { + const actual = updateWith({}, 'a[0].b.c', stubFour, noop); + assert.deepStrictEqual(actual, { a: [{ b: { c: 4 } }] }); + }); +}); diff --git a/test/upperCase.spec.ts b/test/upperCase.spec.ts new file mode 100644 index 000000000..afaf4e323 --- /dev/null +++ b/test/upperCase.spec.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert'; +import upperCase from '../src/upperCase'; + +describe('upperCase', () => { + it('should uppercase as space-separated words', () => { + assert.strictEqual(upperCase('--foo-bar--'), 'FOO BAR'); + assert.strictEqual(upperCase('fooBar'), 'FOO BAR'); + assert.strictEqual(upperCase('__foo_bar__'), 'FOO BAR'); + }); +}); diff --git a/test/upperCase.test.js b/test/upperCase.test.js deleted file mode 100644 index 08c362a0a..000000000 --- a/test/upperCase.test.js +++ /dev/null @@ -1,10 +0,0 @@ -import assert from 'assert'; -import upperCase from '../upperCase.js'; - -describe('upperCase', function() { - it('should uppercase as space-separated words', function() { - assert.strictEqual(upperCase('--foo-bar--'), 'FOO BAR'); - assert.strictEqual(upperCase('fooBar'), 'FOO BAR'); - assert.strictEqual(upperCase('__foo_bar__'), 'FOO BAR'); - }); -}); diff --git a/test/upperFirst.spec.ts b/test/upperFirst.spec.ts new file mode 100644 index 000000000..56a47e739 --- /dev/null +++ b/test/upperFirst.spec.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert'; +import upperFirst from '../src/upperFirst'; + +describe('upperFirst', () => { + it('should uppercase only the first character', () => { + assert.strictEqual(upperFirst('fred'), 'Fred'); + assert.strictEqual(upperFirst('Fred'), 'Fred'); + assert.strictEqual(upperFirst('FRED'), 'FRED'); + }); +}); diff --git a/test/upperFirst.test.js b/test/upperFirst.test.js deleted file mode 100644 index b3833310a..000000000 --- a/test/upperFirst.test.js +++ /dev/null @@ -1,10 +0,0 @@ -import assert from 'assert'; -import upperFirst from '../upperFirst.js'; - -describe('upperFirst', function() { - it('should uppercase only the first character', function() { - assert.strictEqual(upperFirst('fred'), 'Fred'); - assert.strictEqual(upperFirst('Fred'), 'Fred'); - assert.strictEqual(upperFirst('FRED'), 'FRED'); - }); -}); diff --git a/test/utils.js b/test/utils.js deleted file mode 100644 index 19d327a03..000000000 --- a/test/utils.js +++ /dev/null @@ -1,799 +0,0 @@ -/** Used to detect when a function becomes hot. */ -var HOT_COUNT = 150; - -/** Used as the size to cover large array optimizations. */ -var LARGE_ARRAY_SIZE = 200; - -/** Used as the `TypeError` message for "Functions" methods. */ -var FUNC_ERROR_TEXT = 'Expected a function'; - -/** Used as the maximum memoize cache size. */ -var MAX_MEMOIZE_SIZE = 500; - -/** Used as references for various `Number` constants. */ -var MAX_SAFE_INTEGER = 9007199254740991, - MAX_INTEGER = 1.7976931348623157e+308; - -/** Used as references for the maximum length and index of an array. */ -var MAX_ARRAY_LENGTH = 4294967295, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1; - -/** `Object#toString` result references. */ -var funcTag = '[object Function]', - numberTag = '[object Number]', - objectTag = '[object Object]'; - -/** Used as a reference to the global object. */ -var root = (typeof global === 'object' && global) || this; - -/** Used to store lodash to test for bad extensions/shims. */ -var lodashBizarro = root.lodashBizarro; - -/** Used for native method references. */ -var arrayProto = Array.prototype, - funcProto = Function.prototype, - objectProto = Object.prototype, - numberProto = Number.prototype, - stringProto = String.prototype; - -/** Method and object shortcuts. */ -var phantom = root.phantom, - process = root.process, - amd = root.define ? define.amd : undefined, - args = toArgs([1, 2, 3]), - argv = process ? process.argv : undefined, - defineProperty = Object.defineProperty, - document = phantom ? undefined : root.document, - body = root.document ? root.document.body : undefined, - create = Object.create, - fnToString = funcProto.toString, - freeze = Object.freeze, - getSymbols = Object.getOwnPropertySymbols, - identity = function(value) { return value; }, - noop = function() {}, - objToString = objectProto.toString, - params = argv, - push = arrayProto.push, - realm = {}, - slice = arrayProto.slice, - strictArgs = (function() { 'use strict'; return arguments; }(1, 2, 3)); - -var ArrayBuffer = root.ArrayBuffer, - Buffer = root.Buffer, - Map = root.Map, - Promise = root.Promise, - Proxy = root.Proxy, - Set = root.Set, - Symbol = root.Symbol, - Uint8Array = root.Uint8Array, - WeakMap = root.WeakMap, - WeakSet = root.WeakSet; - -var arrayBuffer = ArrayBuffer ? new ArrayBuffer(2) : undefined, - map = Map ? new Map : undefined, - promise = Promise ? Promise.resolve(1) : undefined, - set = Set ? new Set : undefined, - symbol = Symbol ? Symbol('a') : undefined, - weakMap = WeakMap ? new WeakMap : undefined, - weakSet = WeakSet ? new WeakSet : undefined; - -/** Math helpers. */ -var add = function(x, y) { return x + y; }, - doubled = function(n) { return n * 2; }, - isEven = function(n) { return n % 2 == 0; }, - square = function(n) { return n * n; }; - -/** Stub functions. */ -var stubA = function() { return 'a'; }, - stubB = function() { return 'b'; }, - stubC = function() { return 'c'; }; - -var stubTrue = function() { return true; }, - stubFalse = function() { return false; }; - -var stubNaN = function() { return NaN; }, - stubNull = function() { return null; }; - -var stubZero = function() { return 0; }, - stubOne = function() { return 1; }, - stubTwo = function() { return 2; }, - stubThree = function() { return 3; }, - stubFour = function() { return 4; }; - -var stubArray = function() { return []; }, - stubObject = function() { return {}; }, - stubString = function() { return ''; }; - -/** List of Latin Unicode letters. */ -var burredLetters = [ - // Latin-1 Supplement letters. - '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', - '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', - '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', - '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', - // Latin Extended-A letters. - '\u0100', '\u0101', '\u0102', '\u0103', '\u0104', '\u0105', '\u0106', '\u0107', '\u0108', '\u0109', '\u010a', '\u010b', '\u010c', '\u010d', '\u010e', '\u010f', - '\u0110', '\u0111', '\u0112', '\u0113', '\u0114', '\u0115', '\u0116', '\u0117', '\u0118', '\u0119', '\u011a', '\u011b', '\u011c', '\u011d', '\u011e', '\u011f', - '\u0120', '\u0121', '\u0122', '\u0123', '\u0124', '\u0125', '\u0126', '\u0127', '\u0128', '\u0129', '\u012a', '\u012b', '\u012c', '\u012d', '\u012e', '\u012f', - '\u0130', '\u0131', '\u0132', '\u0133', '\u0134', '\u0135', '\u0136', '\u0137', '\u0138', '\u0139', '\u013a', '\u013b', '\u013c', '\u013d', '\u013e', '\u013f', - '\u0140', '\u0141', '\u0142', '\u0143', '\u0144', '\u0145', '\u0146', '\u0147', '\u0148', '\u0149', '\u014a', '\u014b', '\u014c', '\u014d', '\u014e', '\u014f', - '\u0150', '\u0151', '\u0152', '\u0153', '\u0154', '\u0155', '\u0156', '\u0157', '\u0158', '\u0159', '\u015a', '\u015b', '\u015c', '\u015d', '\u015e', '\u015f', - '\u0160', '\u0161', '\u0162', '\u0163', '\u0164', '\u0165', '\u0166', '\u0167', '\u0168', '\u0169', '\u016a', '\u016b', '\u016c', '\u016d', '\u016e', '\u016f', - '\u0170', '\u0171', '\u0172', '\u0173', '\u0174', '\u0175', '\u0176', '\u0177', '\u0178', '\u0179', '\u017a', '\u017b', '\u017c', '\u017d', '\u017e', '\u017f' -]; - -/** List of combining diacritical marks. */ -var comboMarks = [ - '\u0300', '\u0301', '\u0302', '\u0303', '\u0304', '\u0305', '\u0306', '\u0307', '\u0308', '\u0309', '\u030a', '\u030b', '\u030c', '\u030d', '\u030e', '\u030f', - '\u0310', '\u0311', '\u0312', '\u0313', '\u0314', '\u0315', '\u0316', '\u0317', '\u0318', '\u0319', '\u031a', '\u031b', '\u031c', '\u031d', '\u031e', '\u031f', - '\u0320', '\u0321', '\u0322', '\u0323', '\u0324', '\u0325', '\u0326', '\u0327', '\u0328', '\u0329', '\u032a', '\u032b', '\u032c', '\u032d', '\u032e', '\u032f', - '\u0330', '\u0331', '\u0332', '\u0333', '\u0334', '\u0335', '\u0336', '\u0337', '\u0338', '\u0339', '\u033a', '\u033b', '\u033c', '\u033d', '\u033e', '\u033f', - '\u0340', '\u0341', '\u0342', '\u0343', '\u0344', '\u0345', '\u0346', '\u0347', '\u0348', '\u0349', '\u034a', '\u034b', '\u034c', '\u034d', '\u034e', '\u034f', - '\u0350', '\u0351', '\u0352', '\u0353', '\u0354', '\u0355', '\u0356', '\u0357', '\u0358', '\u0359', '\u035a', '\u035b', '\u035c', '\u035d', '\u035e', '\u035f', - '\u0360', '\u0361', '\u0362', '\u0363', '\u0364', '\u0365', '\u0366', '\u0367', '\u0368', '\u0369', '\u036a', '\u036b', '\u036c', '\u036d', '\u036e', '\u036f', - '\ufe20', '\ufe21', '\ufe22', '\ufe23' -]; - -/** List of converted Latin Unicode letters. */ -var deburredLetters = [ - // Converted Latin-1 Supplement letters. - 'A', 'A', 'A', 'A', 'A', 'A', 'Ae', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', - 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 'Th', - 'ss', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', - 'i', 'd', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'th', 'y', - // Converted Latin Extended-A letters. - 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', - 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', - 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', - 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', - 'K', 'k', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', - 'N', 'n', 'N', 'n', 'N', 'n', "'n", 'N', 'n', - 'O', 'o', 'O', 'o', 'O', 'o', 'Oe', 'oe', - 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', - 'T', 't', 'T', 't', 'T', 't', - 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', - 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's' -]; - -/** Used to provide falsey values to methods. */ -var falsey = [, null, undefined, false, 0, NaN, '']; - -/** Used to specify the emoji style glyph variant of characters. */ -var emojiVar = '\ufe0f'; - -/** Used to provide empty values to methods. */ -var empties = [[], {}].concat(falsey.slice(1)); - -/** Used to test error objects. */ -var errors = [ - new Error, - new EvalError, - new RangeError, - new ReferenceError, - new SyntaxError, - new TypeError, - new URIError -]; - -/** List of fitzpatrick modifiers. */ -var fitzModifiers = [ - '\ud83c\udffb', - '\ud83c\udffc', - '\ud83c\udffd', - '\ud83c\udffe', - '\ud83c\udfff' -]; - -/** Used to provide primitive values to methods. */ -var primitives = [null, undefined, false, true, 1, NaN, 'a']; - -/** Used to check whether methods support typed arrays. */ -var typedArrays = [ - 'Float32Array', - 'Float64Array', - 'Int8Array', - 'Int16Array', - 'Int32Array', - 'Uint8Array', - 'Uint8ClampedArray', - 'Uint16Array', - 'Uint32Array' -]; - -/** Used to check whether methods support array views. */ -var arrayViews = typedArrays.concat('DataView'); - -/** The file path of the lodash file to test. */ -var filePath = (function() { - var min = 2, - result = params || []; - - if (phantom) { - min = 0; - result = params = phantom.args || require('system').args; - } - var last = result[result.length - 1]; - result = (result.length > min && !/test(?:\.js)?$/.test(last)) ? last : '../node_modules/lodash/lodash.js'; - - if (!amd) { - try { - result = require('fs').realpathSync(result); - } catch (e) {} - - try { - result = require.resolve(result); - } catch (e) {} - } - return result; -}()); - -/** The `ui` object. */ -var ui = root.ui || (root.ui = { - 'buildPath': filePath, - 'loaderPath': '', - 'isModularize': /\b(?:amd|commonjs|es|node|npm|(index|main)\.js)\b/.test(filePath), - 'isStrict': /\bes\b/.test(filePath) || 'default' in require(filePath), - 'urlParams': {} -}); - -/** The basename of the lodash file to test. */ -var basename = /[\w.-]+$/.exec(filePath)[0]; - -/** Used to indicate testing a modularized build. */ -var isModularize = ui.isModularize; - -/** Detect if testing `npm` modules. */ -var isNpm = isModularize && /\bnpm\b/.test([ui.buildPath, ui.urlParams.build]); - -/** Detect if running in PhantomJS. */ -var isPhantom = phantom || (typeof callPhantom === 'function'); - -/** Detect if lodash is in strict mode. */ -var isStrict = ui.isStrict; - -/*--------------------------------------------------------------------------*/ - -// Leak to avoid sporadic `noglobals` fails on Edge in Sauce Labs. -root.msWDfn = undefined; - -// Assign `setTimeout` to itself to avoid being flagged as a leak. -setProperty(root, 'setTimeout', setTimeout); - -/*--------------------------------------------------------------------------*/ - -/** Used to test Web Workers. */ -var Worker = !(ui.isForeign || ui.isSauceLabs || isModularize) && - (document && document.origin != 'null') && root.Worker; - -/** Poison the free variable `root` in Node.js */ -try { - defineProperty(global.root, 'root', { - 'configurable': false, - 'enumerable': false, - 'get': function() { throw new ReferenceError; } - }); -} catch (e) {} - -/** Load stable Lodash. */ -var lodashStable = root.lodashStable; -if (!lodashStable) { - try { - lodashStable = interopRequire('../node_modules/lodash/lodash.js'); - } catch (e) { - console.log('Error: The stable lodash dev dependency should be at least a version behind master branch.'); - } - lodashStable = lodashStable.noConflict(); -} - -/** The `lodash` function to test. */ -var _ = root._ || (root._ = interopRequire(filePath)); - -/** Used to test pseudo private map caches. */ -var mapCaches = (function() { - var MapCache = _.memoize.Cache; - var result = { - 'Hash': new MapCache().__data__.hash.constructor, - 'MapCache': MapCache - }; - _.isMatchWith({ 'a': 1 }, { 'a': 1 }, function() { - var stack = lodashStable.last(arguments); - result.ListCache = stack.__data__.constructor; - result.Stack = stack.constructor; - }); - return result; -}()); - -/** Used to detect instrumented istanbul code coverage runs. */ -var coverage = root.__coverage__ || root[lodashStable.find(lodashStable.keys(root), function(key) { - return /^(?:\$\$cov_\d+\$\$)$/.test(key); -})]; - -/** Used to test async functions. */ -var asyncFunc = lodashStable.attempt(function() { - return Function('return async () => {}'); -}); - -/** Used to test generator functions. */ -var genFunc = lodashStable.attempt(function() { - return Function('return function*(){}'); -}); - -/** Used to restore the `_` reference. */ -var oldDash = root._; - -/** - * Used to check for problems removing whitespace. For a whitespace reference, - * see [V8's unit test](https://code.google.com/p/v8/source/browse/branches/bleeding_edge/test/mjsunit/whitespaces.js). - */ -var whitespace = lodashStable.filter([ - // 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' -], -function(chr) { return /\s/.exec(chr); }) -.join(''); - -/** - * Creates a custom error object. - * - * @private - * @constructor - * @param {string} message The error message. - */ -function CustomError(message) { - this.name = 'CustomError'; - this.message = message; -} - -CustomError.prototype = lodashStable.create(Error.prototype, { - 'constructor': CustomError -}); - -/** - * Removes all own enumerable string keyed properties from a given object. - * - * @private - * @param {Object} object The object to empty. - */ -function emptyObject(object) { - lodashStable.forOwn(object, function(value, key, object) { - delete object[key]; - }); -} - -/** - * Extracts the unwrapped value from its wrapper. - * - * @private - * @param {Object} wrapper The wrapper to unwrap. - * @returns {*} Returns the unwrapped value. - */ -function getUnwrappedValue(wrapper) { - var index = -1, - actions = wrapper.__actions__, - length = actions.length, - result = wrapper.__wrapped__; - - while (++index < length) { - var args = [result], - action = actions[index]; - - push.apply(args, action.args); - result = action.func.apply(action.thisArg, args); - } - return result; -} - -/** - * Loads the module of `id`. If the module has an `exports.default`, the - * exported default value is returned as the resolved module. - * - * @private - * @param {string} id The identifier of the module to resolve. - * @returns {*} Returns the resolved module. - */ -function interopRequire(id) { - var result = require(id); - return 'default' in result ? result['default'] : result; -} - -/** - * Sets a non-enumerable property value on `object`. - * - * Note: This function is used to avoid a bug in older versions of V8 where - * overwriting non-enumerable built-ins makes them enumerable. - * See https://code.google.com/p/v8/issues/detail?id=1623 - * - * @private - * @param {Object} object The object modify. - * @param {string} key The name of the property to set. - * @param {*} value The property value. - */ -function setProperty(object, key, value) { - try { - defineProperty(object, key, { - 'configurable': true, - 'enumerable': false, - 'writable': true, - 'value': value - }); - } catch (e) { - object[key] = value; - } - return object; -} - -/** - * Skips a given number of tests with a passing result. - * - * @private - * @param {Object} assert The QUnit assert object. - * @param {number} [count=1] The number of tests to skip. - */ -function skipAssert(assert, count) { - count || (count = 1); - while (count--) { - assert.ok(true, 'test skipped'); - } -} - -/** - * Converts `array` to an `arguments` object. - * - * @private - * @param {Array} array The array to convert. - * @returns {Object} Returns the converted `arguments` object. - */ -function toArgs(array) { - return (function() { return arguments; }.apply(undefined, array)); -} - -/*--------------------------------------------------------------------------*/ - -// Add bizarro values. -(function() { - return; // fixme - if (document || (typeof require !== 'function')) { - return; - } - var nativeString = fnToString.call(toString), - reToString = /toString/g; - - function createToString(funcName) { - return lodashStable.constant(nativeString.replace(reToString, funcName)); - } - - // Allow bypassing native checks. - setProperty(funcProto, 'toString', function wrapper() { - setProperty(funcProto, 'toString', fnToString); - var result = lodashStable.has(this, 'toString') ? this.toString() : fnToString.call(this); - setProperty(funcProto, 'toString', wrapper); - return result; - }); - - // Add prototype extensions. - funcProto._method = noop; - - // Set bad shims. - setProperty(Object, 'create', undefined); - setProperty(Object, 'getOwnPropertySymbols', undefined); - - var _propertyIsEnumerable = objectProto.propertyIsEnumerable; - setProperty(objectProto, 'propertyIsEnumerable', function(key) { - return !(key == 'valueOf' && this && this.valueOf === 1) && _propertyIsEnumerable.call(this, key); - }); - - if (Buffer) { - defineProperty(root, 'Buffer', { - 'configurable': true, - 'enumerable': true, - 'get': function get() { - var caller = get.caller, - name = caller ? caller.name : ''; - - if (!(name == 'runInContext' || name.length == 1 || /\b_\.isBuffer\b/.test(caller))) { - return Buffer; - } - } - }); - } - if (Map) { - setProperty(root, 'Map', (function() { - var count = 0; - return function() { - if (count++) { - return new Map; - } - setProperty(root, 'Map', Map); - return {}; - }; - }())); - - setProperty(root.Map, 'toString', createToString('Map')); - } - setProperty(root, 'Promise', noop); - setProperty(root, 'Set', noop); - setProperty(root, 'Symbol', undefined); - setProperty(root, 'WeakMap', noop); - - // Fake `WinRTError`. - setProperty(root, 'WinRTError', Error); - - // Clear cache so lodash can be reloaded. - emptyObject(require.cache); - - // Load lodash and expose it to the bad extensions/shims. - lodashBizarro = interopRequire(filePath); - root._ = oldDash; - - // Restore built-in methods. - setProperty(Object, 'create', create); - setProperty(objectProto, 'propertyIsEnumerable', _propertyIsEnumerable); - setProperty(root, 'Buffer', Buffer); - - if (getSymbols) { - Object.getOwnPropertySymbols = getSymbols; - } else { - delete Object.getOwnPropertySymbols; - } - if (Map) { - setProperty(root, 'Map', Map); - } else { - delete root.Map; - } - if (Promise) { - setProperty(root, 'Promise', Promise); - } else { - delete root.Promise; - } - if (Set) { - setProperty(root, 'Set', Set); - } else { - delete root.Set; - } - if (Symbol) { - setProperty(root, 'Symbol', Symbol); - } else { - delete root.Symbol; - } - if (WeakMap) { - setProperty(root, 'WeakMap', WeakMap); - } else { - delete root.WeakMap; - } - delete root.WinRTError; - delete funcProto._method; -}()); - -// Add other realm values from the `vm` module. -lodashStable.attempt(function() { - lodashStable.assign(realm, require('vm').runInNewContext([ - '(function() {', - ' var noop = function() {},', - ' root = this;', - '', - ' var object = {', - " 'ArrayBuffer': root.ArrayBuffer,", - " 'arguments': (function() { return arguments; }(1, 2, 3)),", - " 'array': [1],", - " 'arrayBuffer': root.ArrayBuffer ? new root.ArrayBuffer : undefined,", - " 'boolean': Object(false),", - " 'date': new Date,", - " 'errors': [new Error, new EvalError, new RangeError, new ReferenceError, new SyntaxError, new TypeError, new URIError],", - " 'function': noop,", - " 'map': root.Map ? new root.Map : undefined,", - " 'nan': NaN,", - " 'null': null,", - " 'number': Object(0),", - " 'object': { 'a': 1 },", - " 'promise': root.Promise ? Promise.resolve(1) : undefined,", - " 'regexp': /x/,", - " 'set': root.Set ? new root.Set : undefined,", - " 'string': Object('a'),", - " 'symbol': root.Symbol ? root.Symbol() : undefined,", - " 'undefined': undefined,", - " 'weakMap': root.WeakMap ? new root.WeakMap : undefined,", - " 'weakSet': root.WeakSet ? new root.WeakSet : undefined", - ' };', - '', - " ['" + arrayViews.join("', '") + "'].forEach(function(type) {", - ' var Ctor = root[type]', - ' object[type] = Ctor;', - ' object[type.toLowerCase()] = Ctor ? new Ctor(new ArrayBuffer(24)) : undefined;', - ' });', - '', - ' return object;', - '}());' - ].join('\n'))); -}); - -// Add other realm values from an iframe. -lodashStable.attempt(function() { - _._realm = realm; - - var iframe = document.createElement('iframe'); - iframe.frameBorder = iframe.height = iframe.width = 0; - body.appendChild(iframe); - - var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc; - idoc.write([ - '', - '', - '', - '', - '' - ].join('\n')); - - idoc.close(); - delete _._realm; -}); - -// Add a web worker. -lodashStable.attempt(function() { - var worker = new Worker('./asset/worker.js?t=' + (+new Date)); - worker.addEventListener('message', function(e) { - _._VERSION = e.data || ''; - }, false); - - worker.postMessage(ui.buildPath); -}); - -// Expose internal modules for better code coverage. -lodashStable.attempt(function() { - var path = require('path'), - basePath = path.dirname(filePath); - - if (isModularize && !(amd || isNpm)) { - lodashStable.each([ - 'baseEach', - 'isIndex', - 'isIterateeCall', - 'memoizeCapped' - ], function(funcName) { - _['_' + funcName] = interopRequire(path.join(basePath, '_' + funcName)); - }); - } -}); - -export { - HOT_COUNT, - LARGE_ARRAY_SIZE, - FUNC_ERROR_TEXT, - MAX_MEMOIZE_SIZE, - MAX_SAFE_INTEGER, - MAX_INTEGER, - MAX_ARRAY_LENGTH, - MAX_ARRAY_INDEX, - funcTag, - numberTag, - objectTag, - lodashBizarro, - arrayProto, - funcProto, - objectProto, - numberProto, - stringProto, - phantom, - amd, - args, - argv, - defineProperty, - document, - body, - create, - fnToString, - freeze, - getSymbols, - identity, - noop, - objToString, - params, - push, - realm, - root, - slice, - strictArgs, - arrayBuffer, - map, - promise, - set, - symbol, - weakMap, - weakSet, - add, - doubled, - isEven, - square, - stubA, - stubB, - stubC, - stubTrue, - stubFalse, - stubNaN, - stubNull, - stubZero, - stubOne, - stubTwo, - stubThree, - stubFour, - stubArray, - stubObject, - stubString, - burredLetters, - comboMarks, - deburredLetters, - falsey, - emojiVar, - empties, - errors, - fitzModifiers, - primitives, - typedArrays, - arrayViews, - filePath, - ui, - basename, - isModularize, - isNpm, - isPhantom, - isStrict, - Worker, - lodashStable, - _, - mapCaches, - coverage, - asyncFunc, - genFunc, - oldDash, - whitespace, - CustomError, - emptyObject, - getUnwrappedValue, - interopRequire, - setProperty, - skipAssert, - toArgs -}; diff --git a/test/utils.ts b/test/utils.ts new file mode 100644 index 000000000..558f44b97 --- /dev/null +++ b/test/utils.ts @@ -0,0 +1,1357 @@ +/** Used to detect when a function becomes hot. */ +const HOT_COUNT = 150; + +/** Used as the size to cover large array optimizations. */ +const LARGE_ARRAY_SIZE = 200; + +/** Used as the `TypeError` message for "Functions" methods. */ +const FUNC_ERROR_TEXT = 'Expected a function'; + +/** Used as the maximum memoize cache size. */ +const MAX_MEMOIZE_SIZE = 500; + +/** Used as references for various `Number` constants. */ +const MAX_SAFE_INTEGER = 9007199254740991, + MAX_INTEGER = 1.7976931348623157e308; + +/** Used as references for the maximum length and index of an array. */ +const MAX_ARRAY_LENGTH = 4294967295, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1; + +/** `Object#toString` result references. */ +const funcTag = '[object Function]', + numberTag = '[object Number]', + objectTag = '[object Object]'; + +/** Used as a reference to the global object. */ +const root = (typeof global === 'object' && global) || this; + +/** Used to store lodash to test for bad extensions/shims. */ +let lodashBizarro = root.lodashBizarro; + +/** Used for native method references. */ +const arrayProto = Array.prototype, + funcProto = Function.prototype, + objectProto = Object.prototype, + numberProto = Number.prototype, + stringProto = String.prototype; + +/** Method and object shortcuts. */ +let phantom = root.phantom, + process = root.process, + amd = root.define ? define.amd : undefined, + args = toArgs([1, 2, 3]), + argv = process ? process.argv : undefined, + defineProperty = Object.defineProperty, + document = phantom ? undefined : root.document, + body = root.document ? root.document.body : undefined, + create = Object.create, + fnToString = funcProto.toString, + freeze = Object.freeze, + getSymbols = Object.getOwnPropertySymbols, + identity = function (value) { + return value; + }, + noop = function () {}, + objToString = objectProto.toString, + params = argv, + push = arrayProto.push, + realm = {}, + slice = arrayProto.slice, + strictArgs = (function () { + 'use strict'; + + return arguments; + })(1, 2, 3); + +const ArrayBuffer = root.ArrayBuffer, + Buffer = root.Buffer, + Map = root.Map, + Promise = root.Promise, + Proxy = root.Proxy, + Set = root.Set, + Symbol = root.Symbol, + Uint8Array = root.Uint8Array, + WeakMap = root.WeakMap, + WeakSet = root.WeakSet; + +const arrayBuffer = ArrayBuffer ? new ArrayBuffer(2) : undefined, + map = Map ? new Map() : undefined, + promise = Promise ? Promise.resolve(1) : undefined, + set = Set ? new Set() : undefined, + symbol = Symbol ? Symbol('a') : undefined, + weakMap = WeakMap ? new WeakMap() : undefined, + weakSet = WeakSet ? new WeakSet() : undefined; + +/** Math helpers. */ +const add = function (x, y) { + return x + y; + }, + doubled = function (n) { + return n * 2; + }, + isEven = function (n) { + return n % 2 == 0; + }, + square = function (n) { + return n * n; + }; + +/** Stub functions. */ +const stubA = function () { + return 'a'; + }, + stubB = function () { + return 'b'; + }, + stubC = function () { + return 'c'; + }; + +const stubTrue = function () { + return true; + }, + stubFalse = function () { + return false; + }; + +const stubNaN = function () { + return NaN; + }, + stubNull = function () { + return null; + }; + +const stubZero = function () { + return 0; + }, + stubOne = function () { + return 1; + }, + stubTwo = function () { + return 2; + }, + stubThree = function () { + return 3; + }, + stubFour = function () { + return 4; + }; + +const stubArray = function () { + return []; + }, + stubObject = function () { + return {}; + }, + stubString = function () { + return ''; + }; + +/** List of Latin Unicode letters. */ +const burredLetters = [ + // Latin-1 Supplement letters. + '\xc0', + '\xc1', + '\xc2', + '\xc3', + '\xc4', + '\xc5', + '\xc6', + '\xc7', + '\xc8', + '\xc9', + '\xca', + '\xcb', + '\xcc', + '\xcd', + '\xce', + '\xcf', + '\xd0', + '\xd1', + '\xd2', + '\xd3', + '\xd4', + '\xd5', + '\xd6', + '\xd8', + '\xd9', + '\xda', + '\xdb', + '\xdc', + '\xdd', + '\xde', + '\xdf', + '\xe0', + '\xe1', + '\xe2', + '\xe3', + '\xe4', + '\xe5', + '\xe6', + '\xe7', + '\xe8', + '\xe9', + '\xea', + '\xeb', + '\xec', + '\xed', + '\xee', + '\xef', + '\xf0', + '\xf1', + '\xf2', + '\xf3', + '\xf4', + '\xf5', + '\xf6', + '\xf8', + '\xf9', + '\xfa', + '\xfb', + '\xfc', + '\xfd', + '\xfe', + '\xff', + // Latin Extended-A letters. + '\u0100', + '\u0101', + '\u0102', + '\u0103', + '\u0104', + '\u0105', + '\u0106', + '\u0107', + '\u0108', + '\u0109', + '\u010a', + '\u010b', + '\u010c', + '\u010d', + '\u010e', + '\u010f', + '\u0110', + '\u0111', + '\u0112', + '\u0113', + '\u0114', + '\u0115', + '\u0116', + '\u0117', + '\u0118', + '\u0119', + '\u011a', + '\u011b', + '\u011c', + '\u011d', + '\u011e', + '\u011f', + '\u0120', + '\u0121', + '\u0122', + '\u0123', + '\u0124', + '\u0125', + '\u0126', + '\u0127', + '\u0128', + '\u0129', + '\u012a', + '\u012b', + '\u012c', + '\u012d', + '\u012e', + '\u012f', + '\u0130', + '\u0131', + '\u0132', + '\u0133', + '\u0134', + '\u0135', + '\u0136', + '\u0137', + '\u0138', + '\u0139', + '\u013a', + '\u013b', + '\u013c', + '\u013d', + '\u013e', + '\u013f', + '\u0140', + '\u0141', + '\u0142', + '\u0143', + '\u0144', + '\u0145', + '\u0146', + '\u0147', + '\u0148', + '\u0149', + '\u014a', + '\u014b', + '\u014c', + '\u014d', + '\u014e', + '\u014f', + '\u0150', + '\u0151', + '\u0152', + '\u0153', + '\u0154', + '\u0155', + '\u0156', + '\u0157', + '\u0158', + '\u0159', + '\u015a', + '\u015b', + '\u015c', + '\u015d', + '\u015e', + '\u015f', + '\u0160', + '\u0161', + '\u0162', + '\u0163', + '\u0164', + '\u0165', + '\u0166', + '\u0167', + '\u0168', + '\u0169', + '\u016a', + '\u016b', + '\u016c', + '\u016d', + '\u016e', + '\u016f', + '\u0170', + '\u0171', + '\u0172', + '\u0173', + '\u0174', + '\u0175', + '\u0176', + '\u0177', + '\u0178', + '\u0179', + '\u017a', + '\u017b', + '\u017c', + '\u017d', + '\u017e', + '\u017f', +]; + +/** List of combining diacritical marks. */ +const comboMarks = [ + '\u0300', + '\u0301', + '\u0302', + '\u0303', + '\u0304', + '\u0305', + '\u0306', + '\u0307', + '\u0308', + '\u0309', + '\u030a', + '\u030b', + '\u030c', + '\u030d', + '\u030e', + '\u030f', + '\u0310', + '\u0311', + '\u0312', + '\u0313', + '\u0314', + '\u0315', + '\u0316', + '\u0317', + '\u0318', + '\u0319', + '\u031a', + '\u031b', + '\u031c', + '\u031d', + '\u031e', + '\u031f', + '\u0320', + '\u0321', + '\u0322', + '\u0323', + '\u0324', + '\u0325', + '\u0326', + '\u0327', + '\u0328', + '\u0329', + '\u032a', + '\u032b', + '\u032c', + '\u032d', + '\u032e', + '\u032f', + '\u0330', + '\u0331', + '\u0332', + '\u0333', + '\u0334', + '\u0335', + '\u0336', + '\u0337', + '\u0338', + '\u0339', + '\u033a', + '\u033b', + '\u033c', + '\u033d', + '\u033e', + '\u033f', + '\u0340', + '\u0341', + '\u0342', + '\u0343', + '\u0344', + '\u0345', + '\u0346', + '\u0347', + '\u0348', + '\u0349', + '\u034a', + '\u034b', + '\u034c', + '\u034d', + '\u034e', + '\u034f', + '\u0350', + '\u0351', + '\u0352', + '\u0353', + '\u0354', + '\u0355', + '\u0356', + '\u0357', + '\u0358', + '\u0359', + '\u035a', + '\u035b', + '\u035c', + '\u035d', + '\u035e', + '\u035f', + '\u0360', + '\u0361', + '\u0362', + '\u0363', + '\u0364', + '\u0365', + '\u0366', + '\u0367', + '\u0368', + '\u0369', + '\u036a', + '\u036b', + '\u036c', + '\u036d', + '\u036e', + '\u036f', + '\ufe20', + '\ufe21', + '\ufe22', + '\ufe23', +]; + +/** List of converted Latin Unicode letters. */ +const deburredLetters = [ + // Converted Latin-1 Supplement letters. + 'A', + 'A', + 'A', + 'A', + 'A', + 'A', + 'Ae', + 'C', + 'E', + 'E', + 'E', + 'E', + 'I', + 'I', + 'I', + 'I', + 'D', + 'N', + 'O', + 'O', + 'O', + 'O', + 'O', + 'O', + 'U', + 'U', + 'U', + 'U', + 'Y', + 'Th', + 'ss', + 'a', + 'a', + 'a', + 'a', + 'a', + 'a', + 'ae', + 'c', + 'e', + 'e', + 'e', + 'e', + 'i', + 'i', + 'i', + 'i', + 'd', + 'n', + 'o', + 'o', + 'o', + 'o', + 'o', + 'o', + 'u', + 'u', + 'u', + 'u', + 'y', + 'th', + 'y', + // Converted Latin Extended-A letters. + 'A', + 'a', + 'A', + 'a', + 'A', + 'a', + 'C', + 'c', + 'C', + 'c', + 'C', + 'c', + 'C', + 'c', + 'D', + 'd', + 'D', + 'd', + 'E', + 'e', + 'E', + 'e', + 'E', + 'e', + 'E', + 'e', + 'E', + 'e', + 'G', + 'g', + 'G', + 'g', + 'G', + 'g', + 'G', + 'g', + 'H', + 'h', + 'H', + 'h', + 'I', + 'i', + 'I', + 'i', + 'I', + 'i', + 'I', + 'i', + 'I', + 'i', + 'IJ', + 'ij', + 'J', + 'j', + 'K', + 'k', + 'k', + 'L', + 'l', + 'L', + 'l', + 'L', + 'l', + 'L', + 'l', + 'L', + 'l', + 'N', + 'n', + 'N', + 'n', + 'N', + 'n', + "'n", + 'N', + 'n', + 'O', + 'o', + 'O', + 'o', + 'O', + 'o', + 'Oe', + 'oe', + 'R', + 'r', + 'R', + 'r', + 'R', + 'r', + 'S', + 's', + 'S', + 's', + 'S', + 's', + 'S', + 's', + 'T', + 't', + 'T', + 't', + 'T', + 't', + 'U', + 'u', + 'U', + 'u', + 'U', + 'u', + 'U', + 'u', + 'U', + 'u', + 'U', + 'u', + 'W', + 'w', + 'Y', + 'y', + 'Y', + 'Z', + 'z', + 'Z', + 'z', + 'Z', + 'z', + 's', +]; + +/** Used to provide falsey values to methods. */ +const falsey = [, null, undefined, false, 0, NaN, '']; + +/** Used to specify the emoji style glyph variant of characters. */ +const emojiVar = '\ufe0f'; + +/** Used to provide empty values to methods. */ +const empties = [[], {}].concat(falsey.slice(1)); + +/** Used to test error objects. */ +const errors = [ + new Error(), + new EvalError(), + new RangeError(), + new ReferenceError(), + new SyntaxError(), + new TypeError(), + new URIError(), +]; + +/** List of fitzpatrick modifiers. */ +const fitzModifiers = [ + '\ud83c\udffb', + '\ud83c\udffc', + '\ud83c\udffd', + '\ud83c\udffe', + '\ud83c\udfff', +]; + +/** Used to provide primitive values to methods. */ +const primitives = [null, undefined, false, true, 1, NaN, 'a']; + +/** Used to check whether methods support typed arrays. */ +const typedArrays = [ + 'Float32Array', + 'Float64Array', + 'Int8Array', + 'Int16Array', + 'Int32Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'Uint16Array', + 'Uint32Array', +]; + +/** Used to check whether methods support array views. */ +const arrayViews = typedArrays.concat('DataView'); + +/** The file path of the lodash file to test. */ +const filePath = (function () { + let min = 2, + result = params || []; + + if (phantom) { + min = 0; + result = params = phantom.args || require('system').args; + } + const last = result[result.length - 1]; + result = + result.length > min && !/test(?:\.js)?$/.test(last) + ? last + : '../node_modules/lodash/lodash'; + + if (!amd) { + try { + result = require('fs').realpathSync(result); + } catch (e) {} + + try { + result = require.resolve(result); + } catch (e) {} + } + return result; +})(); + +/** The `ui` object. */ +const ui = + root.ui || + (root.ui = { + buildPath: filePath, + loaderPath: '', + isModularize: /\b(?:amd|commonjs|es|node|npm|(index|main)\.js)\b/.test(filePath), + isStrict: /\bes\b/.test(filePath) || 'default' in require(filePath), + urlParams: {}, + }); + +/** The basename of the lodash file to test. */ +const basename = /[\w.-]+$/.exec(filePath)[0]; + +/** Used to indicate testing a modularized build. */ +const isModularize = ui.isModularize; + +/** Detect if testing `npm` modules. */ +const isNpm = isModularize && /\bnpm\b/.test([ui.buildPath, ui.urlParams.build]); + +/** Detect if running in PhantomJS. */ +const isPhantom = phantom || typeof callPhantom === 'function'; + +/** Detect if lodash is in strict mode. */ +const isStrict = ui.isStrict; + +/*--------------------------------------------------------------------------*/ + +// Leak to avoid sporadic `noglobals` fails on Edge in Sauce Labs. +root.msWDfn = undefined; + +// Assign `setTimeout` to itself to avoid being flagged as a leak. +setProperty(root, 'setTimeout', setTimeout); + +/*--------------------------------------------------------------------------*/ + +/** Used to test Web Workers. */ +const Worker = + !(ui.isForeign || ui.isSauceLabs || isModularize) && + document && + document.origin != 'null' && + root.Worker; + +/** Poison the free variable `root` in Node.js */ +try { + defineProperty(global.root, 'root', { + configurable: false, + enumerable: false, + get: function () { + throw new ReferenceError(); + }, + }); +} catch (e) {} + +/** Load stable Lodash. */ +let lodashStable = root.lodashStable; +if (!lodashStable) { + try { + lodashStable = interopRequire('../node_modules/lodash/lodash'); + } catch (e) { + console.log( + 'Error: The stable lodash dev dependency should be at least a version behind master branch.', + ); + } + lodashStable = lodashStable.noConflict(); +} + +/** The `lodash` function to test. */ +const _ = root._ || (root._ = interopRequire(filePath)); + +/** Used to test pseudo private map caches. */ +const mapCaches = (function () { + const MapCache = _.memoize.Cache; + const result = { + Hash: new MapCache().__data__.hash.constructor, + MapCache: MapCache, + }; + _.isMatchWith({ a: 1 }, { a: 1 }, function () { + const stack = lodashStable.last(arguments); + result.ListCache = stack.__data__.constructor; + result.Stack = stack.constructor; + }); + return result; +})(); + +/** Used to detect instrumented istanbul code coverage runs. */ +const coverage = + root.__coverage__ || + root[lodashStable.find(lodashStable.keys(root), (key) => /^(?:\$\$cov_\d+\$\$)$/.test(key))]; + +/** Used to test async functions. */ +const asyncFunc = lodashStable.attempt(() => Function('return async () => {}')); + +/** Used to test generator functions. */ +const genFunc = lodashStable.attempt(() => Function('return function*(){}')); + +/** Used to restore the `_` reference. */ +const oldDash = root._; + +/** + * Used to check for problems removing whitespace. For a whitespace reference, + * see [V8's unit test](https://code.google.com/p/v8/source/browse/branches/bleeding_edge/test/mjsunit/whitespaces.js). + */ +const whitespace = lodashStable + .filter( + [ + // 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', + ], + (chr) => /\s/.exec(chr), + ) + .join(''); + +/** + * Creates a custom error object. + * + * @private + * @constructor + * @param {string} message The error message. + */ +function CustomError(message) { + this.name = 'CustomError'; + this.message = message; +} + +CustomError.prototype = lodashStable.create(Error.prototype, { + constructor: CustomError, +}); + +/** + * Removes all own enumerable string keyed properties from a given object. + * + * @private + * @param {Object} object The object to empty. + */ +function emptyObject(object) { + lodashStable.forOwn(object, (value, key, object) => { + delete object[key]; + }); +} + +/** + * Extracts the unwrapped value from its wrapper. + * + * @private + * @param {Object} wrapper The wrapper to unwrap. + * @returns {*} Returns the unwrapped value. + */ +function getUnwrappedValue(wrapper) { + let index = -1, + actions = wrapper.__actions__, + length = actions.length, + result = wrapper.__wrapped__; + + while (++index < length) { + const args = [result], + action = actions[index]; + + push.apply(args, action.args); + result = action.func.apply(action.thisArg, args); + } + return result; +} + +/** + * Loads the module of `id`. If the module has an `exports.default`, the + * exported default value is returned as the resolved module. + * + * @private + * @param {string} id The identifier of the module to resolve. + * @returns {*} Returns the resolved module. + */ +function interopRequire(id) { + const result = require(id); + return 'default' in result ? result.default : result; +} + +/** + * Sets a non-enumerable property value on `object`. + * + * Note: This function is used to avoid a bug in older versions of V8 where + * overwriting non-enumerable built-ins makes them enumerable. + * See https://code.google.com/p/v8/issues/detail?id=1623 + * + * @private + * @param {Object} object The object modify. + * @param {string} key The name of the property to set. + * @param {*} value The property value. + */ +function setProperty(object, key, value) { + try { + defineProperty(object, key, { + configurable: true, + enumerable: false, + writable: true, + value: value, + }); + } catch (e) { + object[key] = value; + } + return object; +} + +/** + * Skips a given number of tests with a passing result. + * + * @private + * @param {Object} assert The QUnit assert object. + * @param {number} [count=1] The number of tests to skip. + */ +function skipAssert(assert, count) { + count || (count = 1); + while (count--) { + assert.ok(true, 'test skipped'); + } +} + +/** + * Converts `array` to an `arguments` object. + * + * @private + * @param {Array} array The array to convert. + * @returns {Object} Returns the converted `arguments` object. + */ +function toArgs(array) { + return function () { + return arguments; + }.apply(undefined, array); +} + +/*--------------------------------------------------------------------------*/ + +// Add bizarro values. +(function () { + return; // fixme + if (document || typeof require !== 'function') { + return; + } + const nativeString = fnToString.call(toString), + reToString = /toString/g; + + function createToString(funcName) { + return lodashStable.constant(nativeString.replace(reToString, funcName)); + } + + // Allow bypassing native checks. + setProperty(funcProto, 'toString', function wrapper() { + setProperty(funcProto, 'toString', fnToString); + const result = lodashStable.has(this, 'toString') ? this.toString() : fnToString.call(this); + setProperty(funcProto, 'toString', wrapper); + return result; + }); + + // Add prototype extensions. + funcProto._method = noop; + + // Set bad shims. + setProperty(Object, 'create', undefined); + setProperty(Object, 'getOwnPropertySymbols', undefined); + + const _propertyIsEnumerable = objectProto.propertyIsEnumerable; + setProperty(objectProto, 'propertyIsEnumerable', function (key) { + return ( + !(key == 'valueOf' && this && this.valueOf === 1) && + _propertyIsEnumerable.call(this, key) + ); + }); + + if (Buffer) { + defineProperty(root, 'Buffer', { + configurable: true, + enumerable: true, + get: function get() { + const caller = get.caller, + name = caller ? caller.name : ''; + + if ( + !(name == 'runInContext' || name.length == 1 || /\b_\.isBuffer\b/.test(caller)) + ) { + return Buffer; + } + }, + }); + } + if (Map) { + setProperty( + root, + 'Map', + (function () { + let count = 0; + return function () { + if (count++) { + return new Map(); + } + setProperty(root, 'Map', Map); + return {}; + }; + })(), + ); + + setProperty(root.Map, 'toString', createToString('Map')); + } + setProperty(root, 'Promise', noop); + setProperty(root, 'Set', noop); + setProperty(root, 'Symbol', undefined); + setProperty(root, 'WeakMap', noop); + + // Fake `WinRTError`. + setProperty(root, 'WinRTError', Error); + + // Clear cache so lodash can be reloaded. + emptyObject(require.cache); + + // Load lodash and expose it to the bad extensions/shims. + lodashBizarro = interopRequire(filePath); + root._ = oldDash; + + // Restore built-in methods. + setProperty(Object, 'create', create); + setProperty(objectProto, 'propertyIsEnumerable', _propertyIsEnumerable); + setProperty(root, 'Buffer', Buffer); + + if (getSymbols) { + Object.getOwnPropertySymbols = getSymbols; + } else { + delete Object.getOwnPropertySymbols; + } + if (Map) { + setProperty(root, 'Map', Map); + } else { + delete root.Map; + } + if (Promise) { + setProperty(root, 'Promise', Promise); + } else { + delete root.Promise; + } + if (Set) { + setProperty(root, 'Set', Set); + } else { + delete root.Set; + } + if (Symbol) { + setProperty(root, 'Symbol', Symbol); + } else { + delete root.Symbol; + } + if (WeakMap) { + setProperty(root, 'WeakMap', WeakMap); + } else { + delete root.WeakMap; + } + delete root.WinRTError; + delete funcProto._method; +})(); + +// Add other realm values from the `vm` module. +lodashStable.attempt(() => { + lodashStable.assign( + realm, + require('vm').runInNewContext( + [ + '(function() {', + ' var noop = function() {},', + ' root = this;', + '', + ' var object = {', + " 'ArrayBuffer': root.ArrayBuffer,", + " 'arguments': (function() { return arguments; }(1, 2, 3)),", + " 'array': [1],", + " 'arrayBuffer': root.ArrayBuffer ? new root.ArrayBuffer : undefined,", + " 'boolean': Object(false),", + " 'date': new Date,", + " 'errors': [new Error, new EvalError, new RangeError, new ReferenceError, new SyntaxError, new TypeError, new URIError],", + " 'function': noop,", + " 'map': root.Map ? new root.Map : undefined,", + " 'nan': NaN,", + " 'null': null,", + " 'number': Object(0),", + " 'object': { 'a': 1 },", + " 'promise': root.Promise ? Promise.resolve(1) : undefined,", + " 'regexp': /x/,", + " 'set': root.Set ? new root.Set : undefined,", + " 'string': Object('a'),", + " 'symbol': root.Symbol ? root.Symbol() : undefined,", + " 'undefined': undefined,", + " 'weakMap': root.WeakMap ? new root.WeakMap : undefined,", + " 'weakSet': root.WeakSet ? new root.WeakSet : undefined", + ' };', + '', + ` ['${arrayViews.join("', '")}'].forEach(function(type) {`, + ' var Ctor = root[type]', + ' object[type] = Ctor;', + ' object[type.toLowerCase()] = Ctor ? new Ctor(new ArrayBuffer(24)) : undefined;', + ' });', + '', + ' return object;', + '}());', + ].join('\n'), + ), + ); +}); + +// Add other realm values from an iframe. +lodashStable.attempt(() => { + _._realm = realm; + + const iframe = document.createElement('iframe'); + iframe.frameBorder = iframe.height = iframe.width = 0; + body.appendChild(iframe); + + var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc; + idoc.write( + [ + '', + '', + '', + '', + '', + ].join('\n'), + ); + + idoc.close(); + delete _._realm; +}); + +// Add a web worker. +lodashStable.attempt(() => { + const worker = new Worker(`./asset/worker.js?t=${+new Date()}`); + worker.addEventListener( + 'message', + (e) => { + _._VERSION = e.data || ''; + }, + false, + ); + + worker.postMessage(ui.buildPath); +}); + +// Expose internal modules for better code coverage. +lodashStable.attempt(() => { + const path = require('path'), + basePath = path.dirname(filePath); + + if (isModularize && !(amd || isNpm)) { + lodashStable.each( + ['baseEach', 'isIndex', 'isIterateeCall', 'memoizeCapped'], + (funcName) => { + _[`_${funcName}`] = interopRequire(path.join(basePath, `_${funcName}`)); + }, + ); + } +}); + +export { + HOT_COUNT, + LARGE_ARRAY_SIZE, + FUNC_ERROR_TEXT, + MAX_MEMOIZE_SIZE, + MAX_SAFE_INTEGER, + MAX_INTEGER, + MAX_ARRAY_LENGTH, + MAX_ARRAY_INDEX, + funcTag, + numberTag, + objectTag, + lodashBizarro, + arrayProto, + funcProto, + objectProto, + numberProto, + stringProto, + phantom, + amd, + args, + argv, + defineProperty, + document, + body, + create, + fnToString, + freeze, + getSymbols, + identity, + noop, + objToString, + params, + push, + realm, + root, + slice, + strictArgs, + arrayBuffer, + map, + promise, + set, + symbol, + weakMap, + weakSet, + add, + doubled, + isEven, + square, + stubA, + stubB, + stubC, + stubTrue, + stubFalse, + stubNaN, + stubNull, + stubZero, + stubOne, + stubTwo, + stubThree, + stubFour, + stubArray, + stubObject, + stubString, + burredLetters, + comboMarks, + deburredLetters, + falsey, + emojiVar, + empties, + errors, + fitzModifiers, + primitives, + typedArrays, + arrayViews, + filePath, + ui, + basename, + isModularize, + isNpm, + isPhantom, + isStrict, + Worker, + lodashStable, + _, + mapCaches, + coverage, + asyncFunc, + genFunc, + oldDash, + whitespace, + CustomError, + emptyObject, + getUnwrappedValue, + interopRequire, + setProperty, + skipAssert, + toArgs, +}; diff --git a/test/values-methods.js b/test/values-methods.js deleted file mode 100644 index b17f3c48b..000000000 --- a/test/values-methods.js +++ /dev/null @@ -1,47 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, args, strictArgs } from './utils.js'; - -describe('values methods', function() { - lodashStable.each(['values', 'valuesIn'], function(methodName) { - var func = _[methodName], - isValues = methodName == 'values'; - - it('`_.' + methodName + '` should get string keyed values of `object`', function() { - var object = { 'a': 1, 'b': 2 }, - actual = func(object).sort(); - - assert.deepStrictEqual(actual, [1, 2]); - }); - - it('`_.' + methodName + '` should work with an object that has a `length` property', function() { - var object = { '0': 'a', '1': 'b', 'length': 2 }, - actual = func(object).sort(); - - assert.deepStrictEqual(actual, [2, 'a', 'b']); - }); - - it('`_.' + methodName + '` should ' + (isValues ? 'not ' : '') + 'include inherited string keyed property values', function() { - function Foo() { - this.a = 1; - } - Foo.prototype.b = 2; - - var expected = isValues ? [1] : [1, 2], - actual = func(new Foo).sort(); - - assert.deepStrictEqual(actual, expected); - }); - - it('`_.' + methodName + '` should work with `arguments` objects', function() { - var values = [args, strictArgs], - expected = lodashStable.map(values, lodashStable.constant([1, 2, 3])); - - var actual = lodashStable.map(values, function(value) { - return func(value).sort(); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); -}); diff --git a/test/values-methods.spec.ts b/test/values-methods.spec.ts new file mode 100644 index 000000000..58faa1c8d --- /dev/null +++ b/test/values-methods.spec.ts @@ -0,0 +1,47 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, args, strictArgs } from './utils'; + +describe('values methods', () => { + lodashStable.each(['values', 'valuesIn'], (methodName) => { + const func = _[methodName], + isValues = methodName == 'values'; + + it(`\`_.${methodName}\` should get string keyed values of \`object\``, () => { + const object = { a: 1, b: 2 }, + actual = func(object).sort(); + + assert.deepStrictEqual(actual, [1, 2]); + }); + + it(`\`_.${methodName}\` should work with an object that has a \`length\` property`, () => { + const object = { '0': 'a', '1': 'b', length: 2 }, + actual = func(object).sort(); + + assert.deepStrictEqual(actual, [2, 'a', 'b']); + }); + + it(`\`_.${methodName}\` should ${ + isValues ? 'not ' : '' + }include inherited string keyed property values`, () => { + function Foo() { + this.a = 1; + } + Foo.prototype.b = 2; + + const expected = isValues ? [1] : [1, 2], + actual = func(new Foo()).sort(); + + assert.deepStrictEqual(actual, expected); + }); + + it(`\`_.${methodName}\` should work with \`arguments\` objects`, () => { + const values = [args, strictArgs], + expected = lodashStable.map(values, lodashStable.constant([1, 2, 3])); + + const actual = lodashStable.map(values, (value) => func(value).sort()); + + assert.deepStrictEqual(actual, expected); + }); + }); +}); diff --git a/test/without.spec.ts b/test/without.spec.ts new file mode 100644 index 000000000..f760005d9 --- /dev/null +++ b/test/without.spec.ts @@ -0,0 +1,23 @@ +import assert from 'node:assert'; +import without from '../src/without'; + +describe('without', () => { + it('should return the difference of values', () => { + const actual = without([2, 1, 2, 3], 1, 2); + assert.deepStrictEqual(actual, [3]); + }); + + it('should use strict equality to determine the values to reject', () => { + const object1 = { a: 1 }, + object2 = { b: 2 }, + array = [object1, object2]; + + assert.deepStrictEqual(without(array, { a: 1 }), array); + assert.deepStrictEqual(without(array, object1), [object2]); + }); + + it('should remove all occurrences of each value from an array', () => { + const array = [1, 2, 3, 1, 2, 3]; + assert.deepStrictEqual(without(array, 1, 2), [3, 3]); + }); +}); diff --git a/test/without.test.js b/test/without.test.js deleted file mode 100644 index bad332941..000000000 --- a/test/without.test.js +++ /dev/null @@ -1,23 +0,0 @@ -import assert from 'assert'; -import without from '../without.js'; - -describe('without', function() { - it('should return the difference of values', function() { - var actual = without([2, 1, 2, 3], 1, 2); - assert.deepStrictEqual(actual, [3]); - }); - - it('should use strict equality to determine the values to reject', function() { - var object1 = { 'a': 1 }, - object2 = { 'b': 2 }, - array = [object1, object2]; - - assert.deepStrictEqual(without(array, { 'a': 1 }), array); - assert.deepStrictEqual(without(array, object1), [object2]); - }); - - it('should remove all occurrences of each value from an array', function() { - var array = [1, 2, 3, 1, 2, 3]; - assert.deepStrictEqual(without(array, 1, 2), [3, 3]); - }); -}); diff --git a/test/words.spec.ts b/test/words.spec.ts new file mode 100644 index 000000000..fc8acc2dd --- /dev/null +++ b/test/words.spec.ts @@ -0,0 +1,127 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { burredLetters, _, stubArray } from './utils'; +import words from '../src/words'; + +describe('words', () => { + it('should match words containing Latin Unicode letters', () => { + const expected = lodashStable.map(burredLetters, (letter) => [letter]); + + const actual = lodashStable.map(burredLetters, (letter) => words(letter)); + + assert.deepStrictEqual(actual, expected); + }); + + it('should support a `pattern`', () => { + assert.deepStrictEqual(words('abcd', /ab|cd/g), ['ab', 'cd']); + assert.deepStrictEqual(Array.from(words('abcd', 'ab|cd')), ['ab']); + }); + + it('should work with compound words', () => { + assert.deepStrictEqual(words('12ft'), ['12', 'ft']); + assert.deepStrictEqual(words('aeiouAreVowels'), ['aeiou', 'Are', 'Vowels']); + assert.deepStrictEqual(words('enable 6h format'), ['enable', '6', 'h', 'format']); + assert.deepStrictEqual(words('enable 24H format'), ['enable', '24', 'H', 'format']); + assert.deepStrictEqual(words('isISO8601'), ['is', 'ISO', '8601']); + assert.deepStrictEqual(words('LETTERSAeiouAreVowels'), [ + 'LETTERS', + 'Aeiou', + 'Are', + 'Vowels', + ]); + assert.deepStrictEqual(words('tooLegit2Quit'), ['too', 'Legit', '2', 'Quit']); + assert.deepStrictEqual(words('walk500Miles'), ['walk', '500', 'Miles']); + assert.deepStrictEqual(words('xhr2Request'), ['xhr', '2', 'Request']); + assert.deepStrictEqual(words('XMLHttp'), ['XML', 'Http']); + assert.deepStrictEqual(words('XmlHTTP'), ['Xml', 'HTTP']); + assert.deepStrictEqual(words('XmlHttp'), ['Xml', 'Http']); + }); + + it('should work with compound words containing diacritical marks', () => { + assert.deepStrictEqual(words('LETTERSÆiouAreVowels'), ['LETTERS', 'Æiou', 'Are', 'Vowels']); + assert.deepStrictEqual(words('æiouAreVowels'), ['æiou', 'Are', 'Vowels']); + assert.deepStrictEqual(words('æiou2Consonants'), ['æiou', '2', 'Consonants']); + }); + + it('should not treat contractions as separate words', () => { + const postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; + + lodashStable.each(["'", '\u2019'], (apos) => { + lodashStable.times(2, (index) => { + const actual = lodashStable.map(postfixes, (postfix) => { + const string = `a b${apos}${postfix} c`; + return words(string[index ? 'toUpperCase' : 'toLowerCase']()); + }); + + const expected = lodashStable.map(postfixes, (postfix) => { + const words = ['a', `b${apos}${postfix}`, 'c']; + return lodashStable.map(words, (word) => + word[index ? 'toUpperCase' : 'toLowerCase'](), + ); + }); + + assert.deepStrictEqual(actual, expected); + }); + }); + }); + + it('should not treat ordinal numbers as separate words', () => { + const ordinals = ['1st', '2nd', '3rd', '4th']; + + lodashStable.times(2, (index) => { + const expected = lodashStable.map(ordinals, (ordinal) => [ + ordinal[index ? 'toUpperCase' : 'toLowerCase'](), + ]); + + const actual = lodashStable.map(expected, (expectedWords) => words(expectedWords[0])); + + assert.deepStrictEqual(actual, expected); + }); + }); + + it('should not treat mathematical operators as words', () => { + const operators = ['\xac', '\xb1', '\xd7', '\xf7'], + expected = lodashStable.map(operators, stubArray), + actual = lodashStable.map(operators, words); + + assert.deepStrictEqual(actual, expected); + }); + + it('should not treat punctuation as words', () => { + const marks = [ + '\u2012', + '\u2013', + '\u2014', + '\u2015', + '\u2024', + '\u2025', + '\u2026', + '\u205d', + '\u205e', + ]; + + const expected = lodashStable.map(marks, stubArray), + actual = lodashStable.map(marks, words); + + assert.deepStrictEqual(actual, expected); + }); + + it('should prevent ReDoS', () => { + const largeWordLen = 50000, + largeWord = 'A'.repeat(largeWordLen), + maxMs = 1000, + startTime = lodashStable.now(); + + assert.deepStrictEqual(words(`${largeWord}ÆiouAreVowels`), [ + largeWord, + 'Æiou', + 'Are', + 'Vowels', + ]); + + const endTime = lodashStable.now(), + timeSpent = endTime - startTime; + + assert.ok(timeSpent < maxMs, `operation took ${timeSpent}ms`); + }); +}); diff --git a/test/words.test.js b/test/words.test.js deleted file mode 100644 index 5eb1043be..000000000 --- a/test/words.test.js +++ /dev/null @@ -1,117 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { burredLetters, _, stubArray } from './utils.js'; -import words from '../words.js' - -describe('words', function() { - it('should match words containing Latin Unicode letters', function() { - var expected = lodashStable.map(burredLetters, function(letter) { - return [letter]; - }); - - var actual = lodashStable.map(burredLetters, function(letter) { - return words(letter); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should support a `pattern`', function() { - assert.deepStrictEqual(words('abcd', /ab|cd/g), ['ab', 'cd']); - assert.deepStrictEqual(Array.from(words('abcd', 'ab|cd')), ['ab']); - }); - - it('should work with compound words', function() { - assert.deepStrictEqual(words('12ft'), ['12', 'ft']); - assert.deepStrictEqual(words('aeiouAreVowels'), ['aeiou', 'Are', 'Vowels']); - assert.deepStrictEqual(words('enable 6h format'), ['enable', '6', 'h', 'format']); - assert.deepStrictEqual(words('enable 24H format'), ['enable', '24', 'H', 'format']); - assert.deepStrictEqual(words('isISO8601'), ['is', 'ISO', '8601']); - assert.deepStrictEqual(words('LETTERSAeiouAreVowels'), ['LETTERS', 'Aeiou', 'Are', 'Vowels']); - assert.deepStrictEqual(words('tooLegit2Quit'), ['too', 'Legit', '2', 'Quit']); - assert.deepStrictEqual(words('walk500Miles'), ['walk', '500', 'Miles']); - assert.deepStrictEqual(words('xhr2Request'), ['xhr', '2', 'Request']); - assert.deepStrictEqual(words('XMLHttp'), ['XML', 'Http']); - assert.deepStrictEqual(words('XmlHTTP'), ['Xml', 'HTTP']); - assert.deepStrictEqual(words('XmlHttp'), ['Xml', 'Http']); - }); - - it('should work with compound words containing diacritical marks', function() { - assert.deepStrictEqual(words('LETTERSÆiouAreVowels'), ['LETTERS', 'Æiou', 'Are', 'Vowels']); - assert.deepStrictEqual(words('æiouAreVowels'), ['æiou', 'Are', 'Vowels']); - assert.deepStrictEqual(words('æiou2Consonants'), ['æiou', '2', 'Consonants']); - }); - - it('should not treat contractions as separate words', function() { - var postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; - - lodashStable.each(["'", '\u2019'], function(apos) { - lodashStable.times(2, function(index) { - var actual = lodashStable.map(postfixes, function(postfix) { - var string = 'a b' + apos + postfix + ' c'; - return words(string[index ? 'toUpperCase' : 'toLowerCase']()); - }); - - var expected = lodashStable.map(postfixes, function(postfix) { - var words = ['a', 'b' + apos + postfix, 'c']; - return lodashStable.map(words, function(word) { - return word[index ? 'toUpperCase' : 'toLowerCase'](); - }); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - }); - - it('should not treat ordinal numbers as separate words', function() { - var ordinals = ['1st', '2nd', '3rd', '4th']; - - lodashStable.times(2, function(index) { - var expected = lodashStable.map(ordinals, function(ordinal) { - return [ordinal[index ? 'toUpperCase' : 'toLowerCase']()]; - }); - - var actual = lodashStable.map(expected, function(expectedWords) { - return words(expectedWords[0]); - }); - - assert.deepStrictEqual(actual, expected); - }); - }); - - it('should not treat mathematical operators as words', function() { - var operators = ['\xac', '\xb1', '\xd7', '\xf7'], - expected = lodashStable.map(operators, stubArray), - actual = lodashStable.map(operators, words); - - assert.deepStrictEqual(actual, expected); - }); - - it('should not treat punctuation as words', function() { - var marks = [ - '\u2012', '\u2013', '\u2014', '\u2015', - '\u2024', '\u2025', '\u2026', - '\u205d', '\u205e' - ]; - - var expected = lodashStable.map(marks, stubArray), - actual = lodashStable.map(marks, words); - - assert.deepStrictEqual(actual, expected); - }); - - it('should prevent ReDoS', function() { - var largeWordLen = 50000, - largeWord = 'A'.repeat(largeWordLen), - maxMs = 1000, - startTime = lodashStable.now(); - - assert.deepStrictEqual(words(largeWord + 'ÆiouAreVowels'), [largeWord, 'Æiou', 'Are', 'Vowels']); - - var endTime = lodashStable.now(), - timeSpent = endTime - startTime; - - assert.ok(timeSpent < maxMs, 'operation took ' + timeSpent + 'ms'); - }); -}); diff --git a/test/wrap.js b/test/wrap.js deleted file mode 100644 index 7a6bd5a45..000000000 --- a/test/wrap.js +++ /dev/null @@ -1,46 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { noop, slice, stubA } from './utils.js'; -import wrap from '../wrap.js'; - -describe('wrap', function() { - it('should create a wrapped function', function() { - var p = wrap(lodashStable.escape, function(func, text) { - return '

' + func(text) + '

'; - }); - - assert.strictEqual(p('fred, barney, & pebbles'), '

fred, barney, & pebbles

'); - }); - - it('should provide correct `wrapper` arguments', function() { - var args; - - var wrapped = wrap(noop, function() { - args || (args = slice.call(arguments)); - }); - - wrapped(1, 2, 3); - assert.deepStrictEqual(args, [noop, 1, 2, 3]); - }); - - it('should use `_.identity` when `wrapper` is nullish', function() { - var values = [, null, undefined], - expected = lodashStable.map(values, stubA); - - var actual = lodashStable.map(values, function(value, index) { - var wrapped = index ? wrap('a', value) : wrap('a'); - return wrapped('b', 'c'); - }); - - assert.deepStrictEqual(actual, expected); - }); - - it('should use `this` binding of function', function() { - var p = wrap(lodashStable.escape, function(func) { - return '

' + func(this.text) + '

'; - }); - - var object = { 'p': p, 'text': 'fred, barney, & pebbles' }; - assert.strictEqual(object.p(), '

fred, barney, & pebbles

'); - }); -}); diff --git a/test/wrap.spec.ts b/test/wrap.spec.ts new file mode 100644 index 000000000..40d6ca085 --- /dev/null +++ b/test/wrap.spec.ts @@ -0,0 +1,44 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { noop, slice, stubA } from './utils'; +import wrap from '../src/wrap'; + +describe('wrap', () => { + it('should create a wrapped function', () => { + const p = wrap(lodashStable.escape, (func, text) => `

${func(text)}

`); + + assert.strictEqual(p('fred, barney, & pebbles'), '

fred, barney, & pebbles

'); + }); + + it('should provide correct `wrapper` arguments', () => { + let args; + + const wrapped = wrap(noop, function () { + args || (args = slice.call(arguments)); + }); + + wrapped(1, 2, 3); + assert.deepStrictEqual(args, [noop, 1, 2, 3]); + }); + + it('should use `_.identity` when `wrapper` is nullish', () => { + const values = [, null, undefined], + expected = lodashStable.map(values, stubA); + + const actual = lodashStable.map(values, (value, index) => { + const wrapped = index ? wrap('a', value) : wrap('a'); + return wrapped('b', 'c'); + }); + + assert.deepStrictEqual(actual, expected); + }); + + it('should use `this` binding of function', () => { + const p = wrap(lodashStable.escape, function (func) { + return `

${func(this.text)}

`; + }); + + const object = { p: p, text: 'fred, barney, & pebbles' }; + assert.strictEqual(object.p(), '

fred, barney, & pebbles

'); + }); +}); diff --git a/test/xor-methods.js b/test/xor-methods.js deleted file mode 100644 index 11c31b07a..000000000 --- a/test/xor-methods.js +++ /dev/null @@ -1,70 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, args, LARGE_ARRAY_SIZE } from './utils.js'; - -describe('xor methods', function() { - lodashStable.each(['xor', 'xorBy', 'xorWith'], function(methodName) { - var func = _[methodName]; - - it('`_.' + methodName + '` should return the symmetric difference of two arrays', function() { - var actual = func([2, 1], [2, 3]); - assert.deepStrictEqual(actual, [1, 3]); - }); - - it('`_.' + methodName + '` should return the symmetric difference of multiple arrays', function() { - var actual = func([2, 1], [2, 3], [3, 4]); - assert.deepStrictEqual(actual, [1, 4]); - - actual = func([1, 2], [2, 1], [1, 2]); - assert.deepStrictEqual(actual, []); - }); - - it('`_.' + methodName + '` should return an empty array when comparing the same array', function() { - var array = [1], - actual = func(array, array, array); - - assert.deepStrictEqual(actual, []); - }); - - it('`_.' + methodName + '` should return an array of unique values', function() { - var actual = func([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]); - assert.deepStrictEqual(actual, [1, 4]); - - actual = func([1, 1]); - assert.deepStrictEqual(actual, [1]); - }); - - it('`_.' + methodName + '` should return a new array when a single array is given', function() { - var array = [1]; - assert.notStrictEqual(func(array), array); - }); - - it('`_.' + methodName + '` should ignore individual secondary arguments', function() { - var array = [0]; - assert.deepStrictEqual(func(array, 3, null, { '0': 1 }), array); - }); - - it('`_.' + methodName + '` should ignore values that are not arrays or `arguments` objects', function() { - var array = [1, 2]; - assert.deepStrictEqual(func(array, 3, { '0': 1 }, null), array); - assert.deepStrictEqual(func(null, array, null, [2, 3]), [1, 3]); - assert.deepStrictEqual(func(array, null, args, null), [3]); - }); - - it('`_.' + methodName + '` should return a wrapped value when chaining', function() { - var wrapped = _([1, 2, 3])[methodName]([5, 2, 1, 4]); - assert.ok(wrapped instanceof _); - }); - - it('`_.' + methodName + '` should work when in a lazy sequence before `head` or `last`', function() { - var array = lodashStable.range(LARGE_ARRAY_SIZE + 1), - wrapped = _(array).slice(1)[methodName]([LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE + 1]); - - var actual = lodashStable.map(['head', 'last'], function(methodName) { - return wrapped[methodName](); - }); - - assert.deepEqual(actual, [1, LARGE_ARRAY_SIZE + 1]); - }); - }); -}); diff --git a/test/xor-methods.spec.ts b/test/xor-methods.spec.ts new file mode 100644 index 000000000..1a57b4399 --- /dev/null +++ b/test/xor-methods.spec.ts @@ -0,0 +1,72 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, args, LARGE_ARRAY_SIZE } from './utils'; + +describe('xor methods', () => { + lodashStable.each(['xor', 'xorBy', 'xorWith'], (methodName) => { + const func = _[methodName]; + + it(`\`_.${methodName}\` should return the symmetric difference of two arrays`, () => { + const actual = func([2, 1], [2, 3]); + assert.deepStrictEqual(actual, [1, 3]); + }); + + it(`\`_.${methodName}\` should return the symmetric difference of multiple arrays`, () => { + let actual = func([2, 1], [2, 3], [3, 4]); + assert.deepStrictEqual(actual, [1, 4]); + + actual = func([1, 2], [2, 1], [1, 2]); + assert.deepStrictEqual(actual, []); + }); + + it(`\`_.${methodName}\` should return an empty array when comparing the same array`, () => { + const array = [1], + actual = func(array, array, array); + + assert.deepStrictEqual(actual, []); + }); + + it(`\`_.${methodName}\` should return an array of unique values`, () => { + let actual = func([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]); + assert.deepStrictEqual(actual, [1, 4]); + + actual = func([1, 1]); + assert.deepStrictEqual(actual, [1]); + }); + + it(`\`_.${methodName}\` should return a new array when a single array is given`, () => { + const array = [1]; + assert.notStrictEqual(func(array), array); + }); + + it(`\`_.${methodName}\` should ignore individual secondary arguments`, () => { + const array = [0]; + assert.deepStrictEqual(func(array, 3, null, { '0': 1 }), array); + }); + + it(`\`_.${methodName}\` should ignore values that are not arrays or \`arguments\` objects`, () => { + const array = [1, 2]; + assert.deepStrictEqual(func(array, 3, { '0': 1 }, null), array); + assert.deepStrictEqual(func(null, array, null, [2, 3]), [1, 3]); + assert.deepStrictEqual(func(array, null, args, null), [3]); + }); + + it(`\`_.${methodName}\` should return a wrapped value when chaining`, () => { + const wrapped = _([1, 2, 3])[methodName]([5, 2, 1, 4]); + assert.ok(wrapped instanceof _); + }); + + it(`\`_.${methodName}\` should work when in a lazy sequence before \`head\` or \`last\``, () => { + const array = lodashStable.range(LARGE_ARRAY_SIZE + 1), + wrapped = _(array) + .slice(1) + [methodName]([LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE + 1]); + + const actual = lodashStable.map(['head', 'last'], (methodName) => + wrapped[methodName](), + ); + + assert.deepEqual(actual, [1, LARGE_ARRAY_SIZE + 1]); + }); + }); +}); diff --git a/test/xorBy.js b/test/xorBy.js deleted file mode 100644 index 02b9250c6..000000000 --- a/test/xorBy.js +++ /dev/null @@ -1,23 +0,0 @@ -import assert from 'assert'; -import { slice } from './utils.js'; -import xorBy from '../xorBy.js'; - -describe('xorBy', function() { - it('should accept an `iteratee`', function() { - var actual = xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); - assert.deepStrictEqual(actual, [1.2, 3.4]); - - actual = xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - assert.deepStrictEqual(actual, [{ 'x': 2 }]); - }); - - it('should provide correct `iteratee` arguments', function() { - var args; - - xorBy([2.1, 1.2], [2.3, 3.4], function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [2.3]); - }); -}); diff --git a/test/xorBy.spec.ts b/test/xorBy.spec.ts new file mode 100644 index 000000000..465430ee4 --- /dev/null +++ b/test/xorBy.spec.ts @@ -0,0 +1,23 @@ +import assert from 'node:assert'; +import { slice } from './utils'; +import xorBy from '../src/xorBy'; + +describe('xorBy', () => { + it('should accept an `iteratee`', () => { + let actual = xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); + assert.deepStrictEqual(actual, [1.2, 3.4]); + + actual = xorBy([{ x: 1 }], [{ x: 2 }, { x: 1 }], 'x'); + assert.deepStrictEqual(actual, [{ x: 2 }]); + }); + + it('should provide correct `iteratee` arguments', () => { + let args; + + xorBy([2.1, 1.2], [2.3, 3.4], function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [2.3]); + }); +}); diff --git a/test/xorWith.spec.ts b/test/xorWith.spec.ts new file mode 100644 index 000000000..9904062a9 --- /dev/null +++ b/test/xorWith.spec.ts @@ -0,0 +1,19 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import xorWith from '../src/xorWith'; + +describe('xorWith', () => { + it('should work with a `comparator`', () => { + const objects = [ + { x: 1, y: 2 }, + { x: 2, y: 1 }, + ], + others = [ + { x: 1, y: 1 }, + { x: 1, y: 2 }, + ], + actual = xorWith(objects, others, lodashStable.isEqual); + + assert.deepStrictEqual(actual, [objects[1], others[0]]); + }); +}); diff --git a/test/xorWith.test.js b/test/xorWith.test.js deleted file mode 100644 index 83551e2cd..000000000 --- a/test/xorWith.test.js +++ /dev/null @@ -1,13 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import xorWith from '../xorWith.js'; - -describe('xorWith', function() { - it('should work with a `comparator`', function() { - var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }], - others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }], - actual = xorWith(objects, others, lodashStable.isEqual); - - assert.deepStrictEqual(actual, [objects[1], others[0]]); - }); -}); diff --git a/test/zipObject-methods.js b/test/zipObject-methods.js deleted file mode 100644 index 02c4fbaa7..000000000 --- a/test/zipObject-methods.js +++ /dev/null @@ -1,39 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { _, LARGE_ARRAY_SIZE, square, isEven } from './utils.js'; - -describe('zipObject methods', function() { - lodashStable.each(['zipObject', 'zipObjectDeep'], function(methodName) { - var func = _[methodName], - object = { 'barney': 36, 'fred': 40 }, - isDeep = methodName == 'zipObjectDeep'; - - it('`_.' + methodName + '` should zip together key/value arrays into an object', function() { - var actual = func(['barney', 'fred'], [36, 40]); - assert.deepStrictEqual(actual, object); - }); - - it('`_.' + methodName + '` should ignore extra `values`', function() { - assert.deepStrictEqual(func(['a'], [1, 2]), { 'a': 1 }); - }); - - it('`_.' + methodName + '` should assign `undefined` values for extra `keys`', function() { - assert.deepStrictEqual(func(['a', 'b'], [1]), { 'a': 1, 'b': undefined }); - }); - - it('`_.' + methodName + '` should ' + (isDeep ? '' : 'not ') + 'support deep paths', function() { - lodashStable.each(['a.b.c', ['a', 'b', 'c']], function(path, index) { - var expected = isDeep ? ({ 'a': { 'b': { 'c': 1 } } }) : (index ? { 'a,b,c': 1 } : { 'a.b.c': 1 }); - assert.deepStrictEqual(func([path], [1]), expected); - }); - }); - - it('`_.' + methodName + '` should work in a lazy sequence', function() { - var values = lodashStable.range(LARGE_ARRAY_SIZE), - props = lodashStable.map(values, function(value) { return 'key' + value; }), - actual = _(props)[methodName](values).map(square).filter(isEven).take().value(); - - assert.deepEqual(actual, _.take(_.filter(_.map(func(props, values), square), isEven))); - }); - }); -}); diff --git a/test/zipObject-methods.spec.ts b/test/zipObject-methods.spec.ts new file mode 100644 index 000000000..32a682fc4 --- /dev/null +++ b/test/zipObject-methods.spec.ts @@ -0,0 +1,43 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { _, LARGE_ARRAY_SIZE, square, isEven } from './utils'; + +describe('zipObject methods', () => { + lodashStable.each(['zipObject', 'zipObjectDeep'], (methodName) => { + const func = _[methodName], + object = { barney: 36, fred: 40 }, + isDeep = methodName == 'zipObjectDeep'; + + it(`\`_.${methodName}\` should zip together key/value arrays into an object`, () => { + const actual = func(['barney', 'fred'], [36, 40]); + assert.deepStrictEqual(actual, object); + }); + + it(`\`_.${methodName}\` should ignore extra \`values\``, () => { + assert.deepStrictEqual(func(['a'], [1, 2]), { a: 1 }); + }); + + it(`\`_.${methodName}\` should assign \`undefined\` values for extra \`keys\``, () => { + assert.deepStrictEqual(func(['a', 'b'], [1]), { a: 1, b: undefined }); + }); + + it(`\`_.${methodName}\` should ${isDeep ? '' : 'not '}support deep paths`, () => { + lodashStable.each(['a.b.c', ['a', 'b', 'c']], (path, index) => { + const expected = isDeep + ? { a: { b: { c: 1 } } } + : index + ? { 'a,b,c': 1 } + : { 'a.b.c': 1 }; + assert.deepStrictEqual(func([path], [1]), expected); + }); + }); + + it(`\`_.${methodName}\` should work in a lazy sequence`, () => { + const values = lodashStable.range(LARGE_ARRAY_SIZE), + props = lodashStable.map(values, (value) => `key${value}`), + actual = _(props)[methodName](values).map(square).filter(isEven).take().value(); + + assert.deepEqual(actual, _.take(_.filter(_.map(func(props, values), square), isEven))); + }); + }); +}); diff --git a/test/zipWith.js b/test/zipWith.js deleted file mode 100644 index f6faaa460..000000000 --- a/test/zipWith.js +++ /dev/null @@ -1,48 +0,0 @@ -import assert from 'assert'; -import lodashStable from 'lodash'; -import { slice } from './utils.js'; -import zipWith from '../zipWith.js'; -import zip from '../zip.js'; - -describe('zipWith', function() { - it('should zip arrays combining grouped elements with `iteratee`', function() { - var array1 = [1, 2, 3], - array2 = [4, 5, 6], - array3 = [7, 8, 9]; - - var actual = zipWith(array1, array2, array3, function(a, b, c) { - return a + b + c; - }); - - assert.deepStrictEqual(actual, [12, 15, 18]); - - var actual = zipWith(array1, [], function(a, b) { - return a + (b || 0); - }); - - assert.deepStrictEqual(actual, [1, 2, 3]); - }); - - it('should provide correct `iteratee` arguments', function() { - var args; - - zipWith([1, 2], [3, 4], [5, 6], function() { - args || (args = slice.call(arguments)); - }); - - assert.deepStrictEqual(args, [1, 3, 5]); - }); - - it('should perform a basic zip when `iteratee` is nullish', function() { - var array1 = [1, 2], - array2 = [3, 4], - values = [, null, undefined], - expected = lodashStable.map(values, lodashStable.constant(zip(array1, array2))); - - var actual = lodashStable.map(values, function(value, index) { - return index ? zipWith(array1, array2, value) : zipWith(array1, array2); - }); - - assert.deepStrictEqual(actual, expected); - }); -}); diff --git a/test/zipWith.spec.ts b/test/zipWith.spec.ts new file mode 100644 index 000000000..ea8af1879 --- /dev/null +++ b/test/zipWith.spec.ts @@ -0,0 +1,44 @@ +import assert from 'node:assert'; +import lodashStable from 'lodash'; +import { slice } from './utils'; +import zipWith from '../src/zipWith'; +import zip from '../src/zip'; + +describe('zipWith', () => { + it('should zip arrays combining grouped elements with `iteratee`', () => { + const array1 = [1, 2, 3], + array2 = [4, 5, 6], + array3 = [7, 8, 9]; + + var actual = zipWith(array1, array2, array3, (a, b, c) => a + b + c); + + assert.deepStrictEqual(actual, [12, 15, 18]); + + var actual = zipWith(array1, [], (a, b) => a + (b || 0)); + + assert.deepStrictEqual(actual, [1, 2, 3]); + }); + + it('should provide correct `iteratee` arguments', () => { + let args; + + zipWith([1, 2], [3, 4], [5, 6], function () { + args || (args = slice.call(arguments)); + }); + + assert.deepStrictEqual(args, [1, 3, 5]); + }); + + it('should perform a basic zip when `iteratee` is nullish', () => { + const array1 = [1, 2], + array2 = [3, 4], + values = [, null, undefined], + expected = lodashStable.map(values, lodashStable.constant(zip(array1, array2))); + + const actual = lodashStable.map(values, (value, index) => + index ? zipWith(array1, array2, value) : zipWith(array1, array2), + ); + + assert.deepStrictEqual(actual, expected); + }); +}); diff --git a/toArray.js b/toArray.js deleted file mode 100644 index 48c132b4d..000000000 --- a/toArray.js +++ /dev/null @@ -1,55 +0,0 @@ -import copyArray from './.internal/copyArray.js' -import getTag from './.internal/getTag.js' -import isArrayLike from './isArrayLike.js' -import isString from './isString.js' -import iteratorToArray from './.internal/iteratorToArray.js' -import mapToArray from './.internal/mapToArray.js' -import setToArray from './.internal/setToArray.js' -import stringToArray from './.internal/stringToArray.js' -import values from './values.js' - -/** `Object#toString` result references. */ -const mapTag = '[object Map]' -const setTag = '[object Set]' - -/** Built-in value references. */ -const symIterator = Symbol.iterator - -/** - * Converts `value` to an array. - * - * @since 0.1.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * toArray({ 'a': 1, 'b': 2 }) - * // => [1, 2] - * - * toArray('abc') - * // => ['a', 'b', 'c'] - * - * toArray(1) - * // => [] - * - * toArray(null) - * // => [] - */ -function toArray(value) { - if (!value) { - return [] - } - if (isArrayLike(value)) { - return isString(value) ? stringToArray(value) : copyArray(value) - } - if (symIterator && value[symIterator]) { - return iteratorToArray(value[symIterator]()) - } - const tag = getTag(value) - const func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values) - - return func(value) -} - -export default toArray diff --git a/toNumber.js b/toNumber.js deleted file mode 100644 index d4bbca4d1..000000000 --- a/toNumber.js +++ /dev/null @@ -1,65 +0,0 @@ -import isObject from './isObject.js' -import isSymbol from './isSymbol.js' - -/** Used as references for various `Number` constants. */ -const NAN = 0 / 0 - -/** Used to match leading and trailing whitespace. */ -const reTrim = /^\s+|\s+$/g - -/** Used to detect bad signed hexadecimal string values. */ -const reIsBadHex = /^[-+]0x[0-9a-f]+$/i - -/** Used to detect binary string values. */ -const reIsBinary = /^0b[01]+$/i - -/** Used to detect octal string values. */ -const reIsOctal = /^0o[0-7]+$/i - -/** Built-in method references without a dependency on `root`. */ -const freeParseInt = parseInt - -/** - * Converts `value` to a number. - * - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @see isInteger, toInteger, isNumber - * @example - * - * toNumber(3.2) - * // => 3.2 - * - * toNumber(Number.MIN_VALUE) - * // => 5e-324 - * - * toNumber(Infinity) - * // => Infinity - * - * toNumber('3.2') - * // => 3.2 - */ -function toNumber(value) { - if (typeof value === 'number') { - return value - } - if (isSymbol(value)) { - return NAN - } - if (isObject(value)) { - const other = typeof value.valueOf === 'function' ? value.valueOf() : value - value = isObject(other) ? `${other}` : other - } - if (typeof value !== 'string') { - return value === 0 ? value : +value - } - value = value.replace(reTrim, '') - const isBinary = reIsBinary.test(value) - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value) -} - -export default toNumber diff --git a/toPath.js b/toPath.js deleted file mode 100644 index 193793781..000000000 --- a/toPath.js +++ /dev/null @@ -1,29 +0,0 @@ -import map from './map.js' -import copyArray from './.internal/copyArray.js' -import isSymbol from './isSymbol.js' -import stringToPath from './.internal/stringToPath.js' -import toKey from './.internal/toKey.js' - -/** - * Converts `value` to a property path array. - * - * @since 4.0.0 - * @category Util - * @param {*} value The value to convert. - * @returns {Array} Returns the new property path array. - * @example - * - * toPath('a.b.c') - * // => ['a', 'b', 'c'] - * - * toPath('a[0].b.c') - * // => ['a', '0', 'b', 'c'] - */ -function toPath(value) { - if (Array.isArray(value)) { - return map(value, toKey) - } - return isSymbol(value) ? [value] : copyArray(stringToPath(value)) -} - -export default toPath diff --git a/toString.js b/toString.js deleted file mode 100644 index 6ba676506..000000000 --- a/toString.js +++ /dev/null @@ -1,44 +0,0 @@ -import isSymbol from './isSymbol.js' - -/** Used as references for various `Number` constants. */ -const INFINITY = 1 / 0 - -/** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - * @example - * - * toString(null) - * // => '' - * - * toString(-0) - * // => '-0' - * - * toString([1, 2, 3]) - * // => '1,2,3' - */ -function toString(value) { - if (value == null) { - return '' - } - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value === 'string') { - return value - } - if (Array.isArray(value)) { - // Recursively convert values (susceptible to call stack limits). - return `${value.map((other) => other == null ? other : toString(other))}` - } - if (isSymbol(value)) { - return value.toString() - } - const result = `${value}` - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result -} - -export default toString diff --git a/trim.js b/trim.js deleted file mode 100644 index b7ac73171..000000000 --- a/trim.js +++ /dev/null @@ -1,38 +0,0 @@ -import castSlice from './.internal/castSlice.js' -import charsEndIndex from './.internal/charsEndIndex.js' -import charsStartIndex from './.internal/charsStartIndex.js' -import stringToArray from './.internal/stringToArray.js' - -/** - * Removes leading and trailing whitespace or specified characters from `string`. - * - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to trim. - * @param {string} [chars=whitespace] The characters to trim. - * @returns {string} Returns the trimmed string. - * @see trimEnd, trimStart - * @example - * - * trim(' abc ') - * // => 'abc' - * - * trim('-_-abc-_-', '_-') - * // => 'abc' - */ -function trim(string, chars) { - if (string && chars === undefined) { - return string.trim() - } - if (!string || !chars) { - return (string || '') - } - const strSymbols = stringToArray(string) - const chrSymbols = stringToArray(chars) - const start = charsStartIndex(strSymbols, chrSymbols) - const end = charsEndIndex(strSymbols, chrSymbols) + 1 - - return castSlice(strSymbols, start, end).join('') -} - -export default trim diff --git a/trimEnd.js b/trimEnd.js deleted file mode 100644 index b802521ba..000000000 --- a/trimEnd.js +++ /dev/null @@ -1,36 +0,0 @@ -import castSlice from './.internal/castSlice.js' -import charsEndIndex from './.internal/charsEndIndex.js' -import stringToArray from './.internal/stringToArray.js' - -const methodName = ''.trimRight ? 'trimRight': 'trimEnd' - -/** - * Removes trailing whitespace or specified characters from `string`. - * - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to trim. - * @param {string} [chars=whitespace] The characters to trim. - * @returns {string} Returns the trimmed string. - * @see trim, trimStart - * @example - * - * trimEnd(' abc ') - * // => ' abc' - * - * trimEnd('-_-abc-_-', '_-') - * // => '-_-abc' - */ -function trimEnd(string, chars) { - if (string && chars === undefined) { - return string[methodName]() - } - if (!string || !chars) { - return (string || '') - } - const strSymbols = stringToArray(string) - const end = charsEndIndex(strSymbols, stringToArray(chars)) + 1 - return castSlice(strSymbols, 0, end).join('') -} - -export default trimEnd diff --git a/trimStart.js b/trimStart.js deleted file mode 100644 index 6138a88e8..000000000 --- a/trimStart.js +++ /dev/null @@ -1,36 +0,0 @@ -import castSlice from './.internal/castSlice.js' -import charsStartIndex from './.internal/charsStartIndex.js' -import stringToArray from './.internal/stringToArray.js' - -const methodName = ''.trimLeft ? 'trimLeft' : 'trimStart' - -/** - * Removes leading whitespace or specified characters from `string`. - * - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to trim. - * @param {string} [chars=whitespace] The characters to trim. - * @returns {string} Returns the trimmed string. - * @see trim, trimEnd - * @example - * - * trimStart(' abc ') - * // => 'abc ' - * - * trimStart('-_-abc-_-', '_-') - * // => 'abc-_-' - */ -function trimStart(string, chars) { - if (string && chars === undefined) { - return string[methodName]() - } - if (!string || !chars) { - return (string || '') - } - const strSymbols = stringToArray(string) - const start = charsStartIndex(strSymbols, stringToArray(chars)) - return castSlice(strSymbols, start).join('') -} - -export default trimStart diff --git a/truncate.js b/truncate.js deleted file mode 100644 index f3a928cdc..000000000 --- a/truncate.js +++ /dev/null @@ -1,113 +0,0 @@ -import baseToString from './.internal/baseToString.js' -import castSlice from './.internal/castSlice.js' -import hasUnicode from './.internal/hasUnicode.js' -import isObject from './isObject.js' -import isRegExp from './isRegExp.js' -import stringSize from './.internal/stringSize.js' -import stringToArray from './.internal/stringToArray.js' -import toString from './toString.js' - -/** Used as default options for `truncate`. */ -const DEFAULT_TRUNC_LENGTH = 30 -const DEFAULT_TRUNC_OMISSION = '...' - -/** Used to match `RegExp` flags from their coerced string values. */ -const reFlags = /\w*$/ - -/** - * Truncates `string` if it's longer than the given maximum string length. - * The last characters of the truncated string are replaced with the omission - * string which defaults to "...". - * - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to truncate. - * @param {Object} [options={}] The options object. - * @param {number} [options.length=30] The maximum string length. - * @param {string} [options.omission='...'] The string to indicate text is omitted. - * @param {RegExp|string} [options.separator] The separator pattern to truncate to. - * @returns {string} Returns the truncated string. - * @see replace - * @example - * - * truncate('hi-diddly-ho there, neighborino') - * // => 'hi-diddly-ho there, neighbo...' - * - * truncate('hi-diddly-ho there, neighborino', { - * 'length': 24, - * 'separator': ' ' - * }) - * // => 'hi-diddly-ho there,...' - * - * truncate('hi-diddly-ho there, neighborino', { - * 'length': 24, - * 'separator': /,? +/ - * }) - * // => 'hi-diddly-ho there...' - * - * truncate('hi-diddly-ho there, neighborino', { - * 'omission': ' [...]' - * }) - * // => 'hi-diddly-ho there, neig [...]' - */ -function truncate(string, options) { - let separator - let length = DEFAULT_TRUNC_LENGTH - let omission = DEFAULT_TRUNC_OMISSION - - if (isObject(options)) { - separator = 'separator' in options ? options.separator : separator - length = 'length' in options ? options.length : length - omission = 'omission' in options ? baseToString(options.omission) : omission - } - - string = toString(string) - - let strSymbols - let strLength = string.length - if (hasUnicode(string)) { - strSymbols = stringToArray(string) - strLength = strSymbols.length - } - if (length >= strLength) { - return string - } - let end = length - stringSize(omission) - if (end < 1) { - return omission - } - let result = strSymbols - ? castSlice(strSymbols, 0, end).join('') - : string.slice(0, end) - - if (separator === undefined) { - return result + omission - } - if (strSymbols) { - end += (result.length - end) - } - if (isRegExp(separator)) { - if (string.slice(end).search(separator)) { - let match - let newEnd - const substring = result - - if (!separator.global) { - separator = RegExp(separator.source, `${reFlags.exec(separator) || ''}g`) - } - separator.lastIndex = 0 - while ((match = separator.exec(substring))) { - newEnd = match.index - } - result = result.slice(0, newEnd === undefined ? end : newEnd) - } - } else if (string.indexOf(baseToString(separator), end) != end) { - const index = result.lastIndexOf(separator) - if (index > -1) { - result = result.slice(0, index) - } - } - return result + omission -} - -export default truncate diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..1983db0b6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "esModuleInterop": true, + "lib": ["dom", "es2015", "es2016", "es2017", "es2018", "es2019", "es2020"], + "module": "commonjs", + "moduleResolution": "node", + "target": "es2020", + // Enhance strictness. + "noImplicitReturns": true, + "noUnusedLocals": true, + "strict": true, + } +} diff --git a/unzip.js b/unzip.js deleted file mode 100644 index a49220be0..000000000 --- a/unzip.js +++ /dev/null @@ -1,43 +0,0 @@ -import filter from './filter.js' -import map from './map.js' -import baseProperty from './.internal/baseProperty.js' -import isArrayLikeObject from './isArrayLikeObject.js' - -/** - * 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. - * - * @since 1.2.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @returns {Array} Returns the new array of regrouped elements. - * @see unzipWith, zip, zipObject, zipObjectDeep, zipWith - * @example - * - * const zipped = zip(['a', 'b'], [1, 2], [true, false]) - * // => [['a', 1, true], ['b', 2, false]] - * - * unzip(zipped) - * // => [['a', 'b'], [1, 2], [true, false]] - */ -function unzip(array) { - if (!(array != null && array.length)) { - return [] - } - let length = 0 - array = filter(array, (group) => { - if (isArrayLikeObject(group)) { - length = Math.max(group.length, length) - return true - } - }) - let index = -1 - const result = new Array(length) - while (++index < length) { - result[index] = map(array, baseProperty(index)) - } - return result -} - -export default unzip diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..32374e182 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,3233 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 +# bun ./bun.lockb --hash: C8812AE368610E54-9dac5adbe1ebc8d1-86E500A8ADF52048-e1ff1073fb6922a8 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": + version "7.22.13" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz" + integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== + dependencies: + "@babel/highlight" "^7.22.13" + chalk "^2.4.2" + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/highlight@^7.22.13": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz" + integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@commitlint/cli@17.7.1": + version "17.7.1" + resolved "https://registry.npmjs.org/@commitlint/cli/-/cli-17.7.1.tgz" + integrity sha512-BCm/AT06SNCQtvFv921iNhudOHuY16LswT0R3OeolVGLk8oP+Rk9TfQfgjH7QPMjhvp76bNqGFEcpKojxUNW1g== + dependencies: + "@commitlint/format" "^17.4.4" + "@commitlint/lint" "^17.7.0" + "@commitlint/load" "^17.7.1" + "@commitlint/read" "^17.5.1" + "@commitlint/types" "^17.4.4" + execa "^5.0.0" + lodash.isfunction "^3.0.9" + resolve-from "5.0.0" + resolve-global "1.0.0" + yargs "^17.0.0" + +"@commitlint/config-conventional@17.7.0": + version "17.7.0" + resolved "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.7.0.tgz" + integrity sha512-iicqh2o6et+9kWaqsQiEYZzfLbtoWv9uZl8kbI8EGfnc0HeGafQBF7AJ0ylN9D/2kj6txltsdyQs8+2fTMwWEw== + dependencies: + conventional-changelog-conventionalcommits "^6.1.0" + +"@commitlint/config-validator@^17.6.7": + version "17.6.7" + resolved "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.6.7.tgz" + integrity sha512-vJSncmnzwMvpr3lIcm0I8YVVDJTzyjy7NZAeXbTXy+MPUdAr9pKyyg7Tx/ebOQ9kqzE6O9WT6jg2164br5UdsQ== + dependencies: + "@commitlint/types" "^17.4.4" + ajv "^8.11.0" + +"@commitlint/ensure@^17.6.7": + version "17.6.7" + resolved "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.6.7.tgz" + integrity sha512-mfDJOd1/O/eIb/h4qwXzUxkmskXDL9vNPnZ4AKYKiZALz4vHzwMxBSYtyL2mUIDeU9DRSpEUins8SeKtFkYHSw== + dependencies: + "@commitlint/types" "^17.4.4" + lodash.camelcase "^4.3.0" + lodash.kebabcase "^4.1.1" + lodash.snakecase "^4.1.1" + lodash.startcase "^4.4.0" + lodash.upperfirst "^4.3.1" + +"@commitlint/execute-rule@^17.4.0": + version "17.4.0" + resolved "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-17.4.0.tgz" + integrity sha512-LIgYXuCSO5Gvtc0t9bebAMSwd68ewzmqLypqI2Kke1rqOqqDbMpYcYfoPfFlv9eyLIh4jocHWwCK5FS7z9icUA== + +"@commitlint/format@^17.4.4": + version "17.4.4" + resolved "https://registry.npmjs.org/@commitlint/format/-/format-17.4.4.tgz" + integrity sha512-+IS7vpC4Gd/x+uyQPTAt3hXs5NxnkqAZ3aqrHd5Bx/R9skyCAWusNlNbw3InDbAK6j166D9asQM8fnmYIa+CXQ== + dependencies: + "@commitlint/types" "^17.4.4" + chalk "^4.1.0" + +"@commitlint/is-ignored@^17.7.0": + version "17.7.0" + resolved "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.7.0.tgz" + integrity sha512-043rA7m45tyEfW7Zv2vZHF++176MLHH9h70fnPoYlB1slKBeKl8BwNIlnPg4xBdRBVNPaCqvXxWswx2GR4c9Hw== + dependencies: + "@commitlint/types" "^17.4.4" + semver "7.5.4" + +"@commitlint/lint@^17.7.0": + version "17.7.0" + resolved "https://registry.npmjs.org/@commitlint/lint/-/lint-17.7.0.tgz" + integrity sha512-TCQihm7/uszA5z1Ux1vw+Nf3yHTgicus/+9HiUQk+kRSQawByxZNESeQoX9ujfVd3r4Sa+3fn0JQAguG4xvvbA== + dependencies: + "@commitlint/is-ignored" "^17.7.0" + "@commitlint/parse" "^17.7.0" + "@commitlint/rules" "^17.7.0" + "@commitlint/types" "^17.4.4" + +"@commitlint/load@^17.7.1": + version "17.7.1" + resolved "https://registry.npmjs.org/@commitlint/load/-/load-17.7.1.tgz" + integrity sha512-S/QSOjE1ztdogYj61p6n3UbkUvweR17FQ0zDbNtoTLc+Hz7vvfS7ehoTMQ27hPSjVBpp7SzEcOQu081RLjKHJQ== + dependencies: + "@commitlint/config-validator" "^17.6.7" + "@commitlint/execute-rule" "^17.4.0" + "@commitlint/resolve-extends" "^17.6.7" + "@commitlint/types" "^17.4.4" + "@types/node" "20.4.7" + chalk "^4.1.0" + cosmiconfig "^8.0.0" + cosmiconfig-typescript-loader "^4.0.0" + lodash.isplainobject "^4.0.6" + lodash.merge "^4.6.2" + lodash.uniq "^4.5.0" + resolve-from "^5.0.0" + ts-node "^10.8.1" + typescript "^4.6.4 || ^5.0.0" + +"@commitlint/message@^17.4.2": + version "17.4.2" + resolved "https://registry.npmjs.org/@commitlint/message/-/message-17.4.2.tgz" + integrity sha512-3XMNbzB+3bhKA1hSAWPCQA3lNxR4zaeQAQcHj0Hx5sVdO6ryXtgUBGGv+1ZCLMgAPRixuc6en+iNAzZ4NzAa8Q== + +"@commitlint/parse@^17.7.0": + version "17.7.0" + resolved "https://registry.npmjs.org/@commitlint/parse/-/parse-17.7.0.tgz" + integrity sha512-dIvFNUMCUHqq5Abv80mIEjLVfw8QNuA4DS7OWip4pcK/3h5wggmjVnlwGCDvDChkw2TjK1K6O+tAEV78oxjxag== + dependencies: + "@commitlint/types" "^17.4.4" + conventional-changelog-angular "^6.0.0" + conventional-commits-parser "^4.0.0" + +"@commitlint/read@^17.5.1": + version "17.5.1" + resolved "https://registry.npmjs.org/@commitlint/read/-/read-17.5.1.tgz" + integrity sha512-7IhfvEvB//p9aYW09YVclHbdf1u7g7QhxeYW9ZHSO8Huzp8Rz7m05aCO1mFG7G8M+7yfFnXB5xOmG18brqQIBg== + dependencies: + "@commitlint/top-level" "^17.4.0" + "@commitlint/types" "^17.4.4" + fs-extra "^11.0.0" + git-raw-commits "^2.0.11" + minimist "^1.2.6" + +"@commitlint/resolve-extends@^17.6.7": + version "17.6.7" + resolved "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.6.7.tgz" + integrity sha512-PfeoAwLHtbOaC9bGn/FADN156CqkFz6ZKiVDMjuC2N5N0740Ke56rKU7Wxdwya8R8xzLK9vZzHgNbuGhaOVKIg== + dependencies: + "@commitlint/config-validator" "^17.6.7" + "@commitlint/types" "^17.4.4" + import-fresh "^3.0.0" + lodash.mergewith "^4.6.2" + resolve-from "^5.0.0" + resolve-global "^1.0.0" + +"@commitlint/rules@^17.7.0": + version "17.7.0" + resolved "https://registry.npmjs.org/@commitlint/rules/-/rules-17.7.0.tgz" + integrity sha512-J3qTh0+ilUE5folSaoK91ByOb8XeQjiGcdIdiB/8UT1/Rd1itKo0ju/eQVGyFzgTMYt8HrDJnGTmNWwcMR1rmA== + dependencies: + "@commitlint/ensure" "^17.6.7" + "@commitlint/message" "^17.4.2" + "@commitlint/to-lines" "^17.4.0" + "@commitlint/types" "^17.4.4" + execa "^5.0.0" + +"@commitlint/to-lines@^17.4.0": + version "17.4.0" + resolved "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-17.4.0.tgz" + integrity sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg== + +"@commitlint/top-level@^17.4.0": + version "17.4.0" + resolved "https://registry.npmjs.org/@commitlint/top-level/-/top-level-17.4.0.tgz" + integrity sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g== + dependencies: + find-up "^5.0.0" + +"@commitlint/types@^17.4.4": + version "17.4.4" + resolved "https://registry.npmjs.org/@commitlint/types/-/types-17.4.4.tgz" + integrity sha512-amRN8tRLYOsxRr6mTnGGGvB5EmW/4DDjLMgiwK3CCVEmN6Sr/6xePGEpWaspKkckILuUORCwe6VfDBw6uj4axQ== + dependencies: + chalk "^4.1.0" + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.8.1" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz" + integrity sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ== + +"@eslint/eslintrc@^2.1.2": + version "2.1.2" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz" + integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.49.0": + version "8.49.0" + resolved "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz" + integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== + +"@humanwhocodes/config-array@^0.11.11": + version "0.11.11" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz" + integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.1" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgr/utils@^2.3.1": + version "2.4.2" + resolved "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz" + integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw== + dependencies: + cross-spawn "^7.0.3" + fast-glob "^3.3.0" + is-glob "^4.0.3" + open "^9.1.0" + picocolors "^1.0.0" + tslib "^2.6.0" + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/eslint@8.44.2", "@types/eslint@>=8.0.0": + version "8.44.2" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz" + integrity sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "1.0.1" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@29.5.5": + version "29.5.5" + resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz" + integrity sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@*", "@types/json-schema@^7.0.12": + version "7.0.13" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz" + integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/minimist@^1.2.0": + version "1.2.2" + resolved "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz" + integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== + +"@types/node@*", "@types/node@20.4.7": + version "20.4.7" + resolved "https://registry.npmjs.org/@types/node/-/node-20.4.7.tgz" + integrity sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g== + +"@types/node@*": + version "20.6.2" + resolved "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz" + integrity sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw== + +"@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + +"@types/semver@^7.5.0": + version "7.5.2" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz" + integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/yargs@^17.0.8": + version "17.0.24" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@typescript-eslint/eslint-plugin@6.7.0", "@typescript-eslint/eslint-plugin@^5.13.0 || ^6.0.0": + version "6.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.0.tgz" + integrity sha512-gUqtknHm0TDs1LhY12K2NA3Rmlmp88jK9Tx8vGZMfHeNMLE3GH2e9TRub+y+SOjuYgtOmok+wt1AyDPZqxbNag== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.7.0" + "@typescript-eslint/type-utils" "6.7.0" + "@typescript-eslint/utils" "6.7.0" + "@typescript-eslint/visitor-keys" "6.7.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@6.7.0", "@typescript-eslint/parser@^5.0.0 || ^6.0.0", "@typescript-eslint/parser@^6.0.0 || ^6.0.0-alpha": + version "6.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.0.tgz" + integrity sha512-jZKYwqNpNm5kzPVP5z1JXAuxjtl2uG+5NpaMocFPTNC2EdYIgbXIPImObOkhbONxtFTTdoZstLZefbaK+wXZng== + dependencies: + "@typescript-eslint/scope-manager" "6.7.0" + "@typescript-eslint/types" "6.7.0" + "@typescript-eslint/typescript-estree" "6.7.0" + "@typescript-eslint/visitor-keys" "6.7.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@6.7.0": + version "6.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.0.tgz" + integrity sha512-lAT1Uau20lQyjoLUQ5FUMSX/dS07qux9rYd5FGzKz/Kf8W8ccuvMyldb8hadHdK/qOI7aikvQWqulnEq2nCEYA== + dependencies: + "@typescript-eslint/types" "6.7.0" + "@typescript-eslint/visitor-keys" "6.7.0" + +"@typescript-eslint/type-utils@6.7.0": + version "6.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.0.tgz" + integrity sha512-f/QabJgDAlpSz3qduCyQT0Fw7hHpmhOzY/Rv6zO3yO+HVIdPfIWhrQoAyG+uZVtWAIS85zAyzgAFfyEr+MgBpg== + dependencies: + "@typescript-eslint/typescript-estree" "6.7.0" + "@typescript-eslint/utils" "6.7.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/types@6.7.0": + version "6.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.0.tgz" + integrity sha512-ihPfvOp7pOcN/ysoj0RpBPOx3HQTJTrIN8UZK+WFd3/iDeFHHqeyYxa4hQk4rMhsz9H9mXpR61IzwlBVGXtl9Q== + +"@typescript-eslint/typescript-estree@6.7.0": + version "6.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.0.tgz" + integrity sha512-dPvkXj3n6e9yd/0LfojNU8VMUGHWiLuBZvbM6V6QYD+2qxqInE7J+J/ieY2iGwR9ivf/R/haWGkIj04WVUeiSQ== + dependencies: + "@typescript-eslint/types" "6.7.0" + "@typescript-eslint/visitor-keys" "6.7.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.7.0": + version "6.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.0.tgz" + integrity sha512-MfCq3cM0vh2slSikQYqK2Gq52gvOhe57vD2RM3V4gQRZYX4rDPnKLu5p6cm89+LJiGlwEXU8hkYxhqqEC/V3qA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.7.0" + "@typescript-eslint/types" "6.7.0" + "@typescript-eslint/typescript-estree" "6.7.0" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@6.7.0": + version "6.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.0.tgz" + integrity sha512-/C1RVgKFDmGMcVGeD8HjKv2bd72oI1KxQDeY8uc66gw9R0OK0eMq48cA+jv9/2Ag6cdrsUGySm1yzYmfz0hxwQ== + dependencies: + "@typescript-eslint/types" "6.7.0" + eslint-visitor-keys "^3.4.1" + +JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.4.1, acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.11.0: + version "8.12.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-escapes@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz" + integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA== + dependencies: + type-fest "^1.0.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansi-styles@^6.0.0, ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-ify@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz" + integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== + +array-includes@^3.1.6: + version "3.1.7" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.findlastindex@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz" + integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.2.1" + +array.prototype.flat@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +big-integer@^1.6.44: + version "1.6.51" + resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + +bplist-parser@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz" + integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== + dependencies: + big-integer "^1.6.44" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +bundle-name@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz" + integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== + dependencies: + run-applescript "^5.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase-keys@^6.2.2: + version "6.2.2" + resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz" + integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== + dependencies: + camelcase "^5.3.1" + map-obj "^4.0.0" + quick-lru "^4.0.1" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + +cli-truncate@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz" + integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== + dependencies: + slice-ansi "^5.0.0" + string-width "^5.0.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@11.0.0: + version "11.0.0" + resolved "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz" + integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== + +compare-func@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz" + integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== + dependencies: + array-ify "^1.0.0" + dot-prop "^5.1.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +confusing-browser-globals@^1.0.10: + version "1.0.11" + resolved "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz" + integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== + +conventional-changelog-angular@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz" + integrity sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg== + dependencies: + compare-func "^2.0.0" + +conventional-changelog-conventionalcommits@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz" + integrity sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw== + dependencies: + compare-func "^2.0.0" + +conventional-commits-parser@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz" + integrity sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg== + dependencies: + JSONStream "^1.3.5" + is-text-path "^1.0.1" + meow "^8.1.2" + split2 "^3.2.2" + +cosmiconfig@>=7, cosmiconfig@^8.0.0: + version "8.3.6" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== + dependencies: + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" + +cosmiconfig-typescript-loader@^4.0.0: + version "4.4.0" + resolved "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.4.0.tgz" + integrity sha512-BabizFdC3wBHhbI4kJh0VkQP9GkBfoHPydD0COMce1nJ1kJAB3F2TmJ/I7diULBKtmEWSwEbuN/KDtgnmUUVmw== + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +dargs@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz" + integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@4.3.4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decamelize@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +decamelize-keys@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz" + integrity sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg== + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +default-browser@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz" + integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== + dependencies: + bundle-name "^3.0.0" + default-browser-id "^3.0.0" + execa "^7.1.1" + titleize "^3.0.0" + +default-browser-id@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz" + integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== + dependencies: + bplist-parser "^0.2.0" + untildify "^4.0.0" + +define-data-property@^1.0.1: + version "1.1.0" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz" + integrity sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== + +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: + version "1.2.1" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dot-prop@^5.1.0: + version "5.3.0" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.22.1: + version "1.22.2" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz" + integrity sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.1" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.12.3" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.11" + +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint@8.49.0: + version "8.49.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz" + integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.2" + "@eslint/js" "8.49.0" + "@humanwhocodes/config-array" "^0.11.11" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +eslint-config-airbnb-base@15.0.0, eslint-config-airbnb-base@^15.0.0: + version "15.0.0" + resolved "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz" + integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig== + dependencies: + confusing-browser-globals "^1.0.10" + object.assign "^4.1.2" + object.entries "^1.1.5" + semver "^6.3.0" + +eslint-config-airbnb-typescript@17.1.0: + version "17.1.0" + resolved "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz" + integrity sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig== + dependencies: + eslint-config-airbnb-base "^15.0.0" + +eslint-config-prettier@9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz" + integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw== + +eslint-import-resolver-node@^0.3.7: + version "0.3.9" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-module-utils@^2.8.0: + version "2.8.0" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@2.28.1: + version "2.28.1" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz" + integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== + dependencies: + array-includes "^3.1.6" + array.prototype.findlastindex "^1.2.2" + array.prototype.flat "^1.3.1" + array.prototype.flatmap "^1.3.1" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.7" + eslint-module-utils "^2.8.0" + has "^1.0.3" + is-core-module "^2.13.0" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.6" + object.groupby "^1.0.0" + object.values "^1.1.6" + semver "^6.3.1" + tsconfig-paths "^3.14.2" + +eslint-plugin-prettier@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz" + integrity sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.8.5" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +execa@7.2.0, execa@^7.1.1: + version "7.2.0" + resolved "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz" + integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + +expect@^29.0.0: + version "29.7.0" + resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +fast-glob@^3.2.9, fast-glob@^3.3.0: + version "3.3.1" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.1.0" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz" + integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew== + dependencies: + flatted "^3.2.7" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.7: + version "3.2.9" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +fs-extra@^11.0.0: + version "11.1.1" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz" + integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +get-stream@^6.0.0, get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +git-raw-commits@^2.0.11: + version "2.0.11" + resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz" + integrity sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A== + dependencies: + dargs "^7.0.0" + lodash "^4.17.15" + meow "^8.0.0" + split2 "^3.0.0" + through2 "^4.0.0" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +global-dirs@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz" + integrity sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg== + dependencies: + ini "^1.3.4" + +globals@^13.19.0: + version "13.21.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz" + integrity sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +hard-rejection@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz" + integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +hosted-git-info@^4.0.1: + version "4.1.0" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== + dependencies: + lru-cache "^6.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== + +husky@8.0.3: + version "8.0.3" + resolved "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz" + integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== + +ignore@^5.2.0, ignore@^5.2.4: + version "5.2.4" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1, import-fresh@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^1.3.4: + version "1.3.8" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-slot@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + dependencies: + get-intrinsic "^1.2.0" + has "^1.0.3" + side-channel "^1.0.4" + +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.13.0, is-core-module@^2.5.0: + version "2.13.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz" + integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-text-path@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz" + integrity sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w== + dependencies: + text-extensions "^1.0.0" + +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: + version "1.1.12" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + +keyv@^4.5.3: + version "4.5.3" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz" + integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== + dependencies: + json-buffer "3.0.1" + +kind-of@^6.0.3: + version "6.0.3" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lint-staged@14.0.1: + version "14.0.1" + resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.1.tgz" + integrity sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw== + dependencies: + chalk "5.3.0" + commander "11.0.0" + debug "4.3.4" + execa "7.2.0" + lilconfig "2.1.0" + listr2 "6.6.1" + micromatch "4.0.5" + pidtree "0.6.0" + string-argv "0.3.2" + yaml "2.3.1" + +listr2@6.6.1: + version "6.6.1" + resolved "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz" + integrity sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg== + dependencies: + cli-truncate "^3.1.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^5.0.1" + rfdc "^1.3.0" + wrap-ansi "^8.1.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash@4.17.21, lodash@^4.17.15: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +lodash.isfunction@^3.0.9: + version "3.0.9" + resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz" + integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz" + integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + +lodash.snakecase@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz" + integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw== + +lodash.startcase@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz" + integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg== + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== + +lodash.upperfirst@^4.3.1: + version "4.3.1" + resolved "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz" + integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== + +log-update@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz" + integrity sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw== + dependencies: + ansi-escapes "^5.0.0" + cli-cursor "^4.0.0" + slice-ansi "^5.0.0" + strip-ansi "^7.0.1" + wrap-ansi "^8.0.1" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +map-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz" + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== + +map-obj@^4.0.0: + version "4.3.0" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== + +meow@^8.0.0, meow@^8.1.2: + version "8.1.2" + resolved "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz" + integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== + dependencies: + "@types/minimist" "^1.2.0" + camelcase-keys "^6.2.2" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "4.1.0" + normalize-package-data "^3.0.0" + read-pkg-up "^7.0.1" + redent "^3.0.0" + trim-newlines "^3.0.0" + type-fest "^0.18.0" + yargs-parser "^20.2.3" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@4.0.5, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@^3.0.5: + version "3.0.8" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minimist-options@4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz" + integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + kind-of "^6.0.3" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-package-data@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== + dependencies: + hosted-git-info "^4.0.1" + is-core-module "^2.5.0" + semver "^7.3.4" + validate-npm-package-license "^3.0.1" + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + +object-inspect@^1.12.3, object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.2, object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.entries@^1.1.5: + version "1.1.7" + resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz" + integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.fromentries@^2.0.6: + version "2.0.7" + resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz" + integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.groupby@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz" + integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + +object.values@^1.1.6: + version "1.1.7" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz" + integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +open@^9.1.0: + version "9.1.0" + resolved "https://registry.npmjs.org/open/-/open-9.1.0.tgz" + integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== + dependencies: + default-browser "^4.0.0" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + is-wsl "^2.2.0" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + prelude-ls "^1.2.1" + deep-is "^0.1.3" + "@aashutoshrathi/word-wrap" "^1.2.3" + type-check "^0.4.0" + levn "^0.4.1" + fast-levenshtein "^2.0.6" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0, parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pidtree@0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz" + integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-lru@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz" + integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +readable-stream@3, readable-stream@^3.0.0: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve@^1.10.0, resolve@^1.22.4: + version "1.22.6" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz" + integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@5.0.0, resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-global@1.0.0, resolve-global@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz" + integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw== + dependencies: + global-dirs "^0.1.1" + +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-applescript@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz" + integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== + dependencies: + execa "^5.0.0" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +"semver@2 || 3 || 4 || 5": + version "5.7.2" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@7.5.4, semver@^7.3.4, semver@^7.5.4: + version "7.5.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +set-function-name@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.13" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== + +split2@^3.0.0, split2@^3.2.2: + version "3.2.2" + resolved "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +string-argv@0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.0, string-width@^5.0.1: + version "5.1.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +synckit@^0.8.5: + version "0.8.5" + resolved "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz" + integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q== + dependencies: + "@pkgr/utils" "^2.3.1" + tslib "^2.5.0" + +text-extensions@^1.0.0: + version "1.9.0" + resolved "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz" + integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +"through@>=2.2.7 <3": + version "2.3.8" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +through2@^4.0.0: + version "4.0.2" + resolved "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== + dependencies: + readable-stream "3" + +titleize@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz" + integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +trim-newlines@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz" + integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== + +ts-api-utils@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz" + integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + +ts-node@>=10, ts-node@^10.8.1: + version "10.9.1" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tsconfig-paths@^3.14.2: + version "3.14.2" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.5.0, tslib@^2.6.0: + version "2.6.2" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +type-check@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-fest@^0.18.0: + version "0.18.1" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz" + integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^1.0.2: + version "1.4.0" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz" + integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== + +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +typescript@>=2.7, typescript@>=4, typescript@>=4.2.0, typescript@>=4.9.5, "typescript@^4.6.4 || ^5.0.0": + version "5.2.2" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.11: + version "1.1.11" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz" + integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz" + integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== + +yargs@^17.0.0: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yargs-parser@^20.2.3: + version "20.2.9" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==