@ezez/utils 3.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/cap.js.map +1 -1
- package/dist/coalesce.d.ts.map +1 -1
- package/dist/coalesce.js.map +1 -1
- package/dist/compareArrays.d.ts.map +1 -1
- package/dist/compareProps.d.ts.map +1 -1
- package/dist/compareProps.js.map +1 -1
- package/dist/deserialize.d.ts.map +1 -1
- package/dist/deserialize.js.map +1 -1
- package/dist/ensureArray.d.ts.map +1 -1
- package/dist/ensureArray.js.map +1 -1
- package/dist/ensureDate.js.map +1 -1
- package/dist/ensureError.js.map +1 -1
- package/dist/ensurePrefix.js.map +1 -1
- package/dist/ensureSuffix.js.map +1 -1
- package/dist/ensureTimestamp.js.map +1 -1
- package/dist/escapeRegExp.d.ts.map +1 -1
- package/dist/escapeRegExp.js +1 -1
- package/dist/escapeRegExp.js.map +1 -1
- package/dist/formatDate.js +1 -1
- package/dist/formatDate.js.map +1 -1
- package/dist/get.js.map +1 -1
- package/dist/getMultiple.d.ts.map +1 -1
- package/dist/getMultiple.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/insertSeparator.d.ts.map +1 -1
- package/dist/insertSeparator.js.map +1 -1
- package/dist/isEmpty.js.map +1 -1
- package/dist/isNumericString.js +1 -1
- package/dist/isNumericString.js.map +1 -1
- package/dist/last.d.ts.map +1 -1
- package/dist/later.d.ts.map +1 -1
- package/dist/mapAsync.d.ts.map +1 -1
- package/dist/mapAsync.js.map +1 -1
- package/dist/mapValues.d.ts.map +1 -1
- package/dist/mapValues.js.map +1 -1
- package/dist/match.d.ts.map +1 -1
- package/dist/match.js.map +1 -1
- package/dist/memoize.d.ts +3 -0
- package/dist/memoize.d.ts.map +1 -0
- package/dist/memoize.js +19 -0
- package/dist/memoize.js.map +1 -0
- package/dist/merge.d.ts +11 -7
- package/dist/merge.d.ts.map +1 -1
- package/dist/merge.js.map +1 -1
- package/dist/mostFrequent.d.ts.map +1 -1
- package/dist/mostFrequent.js.map +1 -1
- package/dist/occurrences.js.map +1 -1
- package/dist/omit.d.ts +1 -1
- package/dist/omit.d.ts.map +1 -1
- package/dist/omit.js.map +1 -1
- package/dist/pick.d.ts.map +1 -1
- package/dist/pick.js.map +1 -1
- package/dist/pull.d.ts.map +1 -1
- package/dist/pull.js.map +1 -1
- package/dist/remove.d.ts.map +1 -1
- package/dist/remove.js +1 -1
- package/dist/remove.js.map +1 -1
- package/dist/removeCommonProperties.d.ts.map +1 -1
- package/dist/removeCommonProperties.js +3 -1
- package/dist/removeCommonProperties.js.map +1 -1
- package/dist/replace.js +1 -1
- package/dist/replace.js.map +1 -1
- package/dist/replaceDeep.d.ts +5 -1
- package/dist/replaceDeep.d.ts.map +1 -1
- package/dist/replaceDeep.js +3 -20
- package/dist/replaceDeep.js.map +1 -1
- package/dist/replaceDeepByFn.d.ts +7 -0
- package/dist/replaceDeepByFn.d.ts.map +1 -0
- package/dist/replaceDeepByFn.js +47 -0
- package/dist/replaceDeepByFn.js.map +1 -0
- package/dist/safe.js.map +1 -1
- package/dist/sample.d.ts +3 -1
- package/dist/sample.d.ts.map +1 -1
- package/dist/sample.js.map +1 -1
- package/dist/samples.d.ts.map +1 -1
- package/dist/samples.js.map +1 -1
- package/dist/seq.d.ts.map +1 -1
- package/dist/seq.js +1 -1
- package/dist/seq.js.map +1 -1
- package/dist/serialize.d.ts.map +1 -1
- package/dist/serialize.js +56 -18
- package/dist/serialize.js.map +1 -1
- package/dist/set.js.map +1 -1
- package/dist/setImmutable.js.map +1 -1
- package/dist/shuffle.d.ts.map +1 -1
- package/dist/sortBy.d.ts.map +1 -1
- package/dist/sortBy.js.map +1 -1
- package/dist/sortProps.d.ts.map +1 -1
- package/dist/sortProps.js.map +1 -1
- package/dist/stripPrefix.js.map +1 -1
- package/dist/stripSuffix.js.map +1 -1
- package/dist/throttle.d.ts.map +1 -1
- package/dist/throttle.js.map +1 -1
- package/dist/toggle.d.ts.map +1 -1
- package/dist/toggle.js.map +1 -1
- package/dist/trim.d.ts +3 -0
- package/dist/trim.d.ts.map +1 -0
- package/dist/trim.js +10 -0
- package/dist/trim.js.map +1 -0
- package/dist/trimEnd.d.ts +3 -0
- package/dist/trimEnd.d.ts.map +1 -0
- package/dist/trimEnd.js +12 -0
- package/dist/trimEnd.js.map +1 -0
- package/dist/trimStart.d.ts +3 -0
- package/dist/trimStart.d.ts.map +1 -0
- package/dist/trimStart.js +12 -0
- package/dist/trimStart.js.map +1 -0
- package/dist/truthy.d.ts +1 -1
- package/dist/truthy.d.ts.map +1 -1
- package/dist/unique.d.ts.map +1 -1
- package/dist/utils/utils.d.ts +6 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +10 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/waitFor.d.ts.map +1 -1
- package/dist/waitFor.js +1 -1
- package/dist/waitFor.js.map +1 -1
- package/dist/waitSync.js.map +1 -1
- package/docs/assets/icons.js +15 -0
- package/docs/assets/icons.svg +1 -0
- package/docs/assets/main.js +4 -3
- package/docs/assets/navigation.js +1 -0
- package/docs/assets/search.js +1 -1
- package/docs/assets/style.css +544 -394
- package/docs/documents/CHANGELOG.html +337 -0
- package/docs/functions/index.cap.html +5 -0
- package/docs/functions/index.capitalize.html +13 -0
- package/docs/functions/index.coalesce.html +16 -0
- package/docs/functions/index.compareArrays.html +8 -0
- package/docs/functions/index.compareProps.html +11 -0
- package/docs/functions/index.deserialize.html +6 -0
- package/docs/functions/index.ensureArray.html +3 -0
- package/docs/functions/index.ensureDate.html +10 -0
- package/docs/functions/index.ensureError.html +14 -0
- package/docs/functions/index.ensurePrefix.html +10 -0
- package/docs/functions/index.ensureSuffix.html +10 -0
- package/docs/functions/index.ensureTimestamp.html +10 -0
- package/docs/functions/index.escapeRegExp.html +7 -0
- package/docs/functions/index.formatDate.html +6 -0
- package/docs/functions/index.get.html +26 -0
- package/docs/functions/index.getMultiple.html +16 -0
- package/docs/functions/index.insertSeparator.html +7 -0
- package/docs/functions/index.isEmpty.html +33 -0
- package/docs/functions/index.isNumericString.html +5 -0
- package/docs/functions/index.isPlainObject.html +18 -0
- package/docs/functions/index.last.html +15 -0
- package/docs/functions/index.later-1.html +6 -0
- package/docs/functions/index.mapAsync.html +8 -0
- package/docs/functions/index.mapValues.html +14 -0
- package/docs/functions/index.match.html +4 -0
- package/docs/functions/index.memoize.html +8 -0
- package/docs/functions/index.merge.html +13 -0
- package/docs/functions/index.mostFrequent.html +2 -0
- package/docs/functions/index.noop.html +2 -0
- package/docs/functions/index.occurrences.html +14 -0
- package/docs/functions/index.omit.html +18 -0
- package/docs/functions/index.pick.html +13 -0
- package/docs/functions/index.pull.html +2 -0
- package/docs/functions/index.remove.html +2 -0
- package/docs/functions/index.removeCommonProperties.html +18 -0
- package/docs/functions/index.replace.html +10 -0
- package/docs/functions/index.replaceDeep.html +15 -0
- package/docs/functions/index.rethrow.html +2 -0
- package/docs/functions/index.round.html +7 -0
- package/docs/functions/index.safe.html +7 -0
- package/docs/functions/index.sample.html +6 -0
- package/docs/functions/index.samples.html +7 -0
- package/docs/functions/index.scale.html +5 -0
- package/docs/functions/index.seq.html +17 -0
- package/docs/functions/index.seqEarlyBreak.html +12 -0
- package/docs/functions/index.serialize.html +14 -0
- package/docs/functions/index.set.html +26 -0
- package/docs/functions/index.setImmutable.html +25 -0
- package/docs/functions/index.shuffle.html +3 -0
- package/docs/functions/index.sortBy.html +6 -0
- package/docs/functions/index.sortProps.html +10 -0
- package/docs/functions/index.stripPrefix.html +4 -0
- package/docs/functions/index.stripSuffix.html +4 -0
- package/docs/functions/index.throttle.html +14 -0
- package/docs/functions/index.toggle.html +5 -0
- package/docs/functions/index.trim.html +8 -0
- package/docs/functions/index.trimEnd.html +8 -0
- package/docs/functions/index.trimStart.html +8 -0
- package/docs/functions/index.truthy.html +7 -0
- package/docs/functions/index.unique.html +6 -0
- package/docs/functions/index.wait.html +3 -0
- package/docs/functions/index.waitFor.html +10 -0
- package/docs/functions/index.waitSync.html +3 -0
- package/docs/index.html +18 -204
- package/docs/interfaces/index.ComparePropsOptions.html +5 -0
- package/docs/interfaces/index.GetMultipleSource.html +3 -0
- package/docs/interfaces/index.GetSource.html +3 -0
- package/docs/interfaces/index.IsNumericStringOptions.html +5 -0
- package/docs/interfaces/index.OccurencesOptions.html +3 -0
- package/docs/interfaces/index.SetImmutableSource.html +3 -0
- package/docs/interfaces/index.SetSource.html +3 -0
- package/docs/interfaces/index.ThrottleOptions.html +5 -0
- package/docs/interfaces/index.ThrottledFunctionExtras.html +5 -0
- package/docs/modules/index.html +86 -0
- package/docs/types/index.CustomDeserializers.html +1 -0
- package/docs/types/index.CustomSerializers.html +1 -0
- package/docs/types/index.Later.html +4 -0
- package/docs/types/index.MapValuesFn.html +14 -0
- package/docs/types/index.MatchCallback.html +1 -0
- package/docs/types/index.MergeTwo.html +3 -0
- package/docs/types/index.SeqEarlyBreaker.html +4 -0
- package/docs/types/index.SeqFn.html +3 -0
- package/docs/types/index.SeqFunctions.html +4 -0
- package/docs/types/index.SetImmutablePath.html +4 -0
- package/docs/types/index.ThrottledFunction.html +1 -0
- package/docs/variables/index.mapValuesUNSET.html +2 -0
- package/docs/variables/index.mergeUNSET.html +4 -0
- package/esm/cap.js.map +1 -1
- package/esm/coalesce.d.ts.map +1 -1
- package/esm/coalesce.js.map +1 -1
- package/esm/compareArrays.d.ts.map +1 -1
- package/esm/compareProps.d.ts.map +1 -1
- package/esm/compareProps.js.map +1 -1
- package/esm/deserialize.d.ts.map +1 -1
- package/esm/deserialize.js.map +1 -1
- package/esm/ensureArray.d.ts.map +1 -1
- package/esm/ensureArray.js.map +1 -1
- package/esm/ensureDate.js.map +1 -1
- package/esm/ensureError.js.map +1 -1
- package/esm/ensurePrefix.js.map +1 -1
- package/esm/ensureSuffix.js.map +1 -1
- package/esm/ensureTimestamp.js.map +1 -1
- package/esm/escapeRegExp.d.ts.map +1 -1
- package/esm/escapeRegExp.js +1 -1
- package/esm/escapeRegExp.js.map +1 -1
- package/esm/formatDate.js +1 -1
- package/esm/formatDate.js.map +1 -1
- package/esm/get.js.map +1 -1
- package/esm/getMultiple.d.ts.map +1 -1
- package/esm/getMultiple.js.map +1 -1
- package/esm/index.d.ts +4 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +4 -0
- package/esm/index.js.map +1 -1
- package/esm/insertSeparator.d.ts.map +1 -1
- package/esm/insertSeparator.js.map +1 -1
- package/esm/isEmpty.js.map +1 -1
- package/esm/isNumericString.js +1 -1
- package/esm/isNumericString.js.map +1 -1
- package/esm/last.d.ts.map +1 -1
- package/esm/later.d.ts.map +1 -1
- package/esm/mapAsync.d.ts.map +1 -1
- package/esm/mapAsync.js.map +1 -1
- package/esm/mapValues.d.ts.map +1 -1
- package/esm/mapValues.js.map +1 -1
- package/esm/match.d.ts.map +1 -1
- package/esm/match.js.map +1 -1
- package/esm/memoize.d.ts +3 -0
- package/esm/memoize.d.ts.map +1 -0
- package/esm/memoize.js +16 -0
- package/esm/memoize.js.map +1 -0
- package/esm/merge.d.ts +11 -7
- package/esm/merge.d.ts.map +1 -1
- package/esm/merge.js.map +1 -1
- package/esm/mostFrequent.d.ts.map +1 -1
- package/esm/mostFrequent.js.map +1 -1
- package/esm/occurrences.js.map +1 -1
- package/esm/omit.d.ts +1 -1
- package/esm/omit.d.ts.map +1 -1
- package/esm/omit.js.map +1 -1
- package/esm/pick.d.ts.map +1 -1
- package/esm/pick.js.map +1 -1
- package/esm/pull.d.ts.map +1 -1
- package/esm/pull.js.map +1 -1
- package/esm/remove.d.ts.map +1 -1
- package/esm/remove.js +1 -1
- package/esm/remove.js.map +1 -1
- package/esm/removeCommonProperties.d.ts.map +1 -1
- package/esm/removeCommonProperties.js +3 -1
- package/esm/removeCommonProperties.js.map +1 -1
- package/esm/replace.js +1 -1
- package/esm/replace.js.map +1 -1
- package/esm/replaceDeep.d.ts +5 -1
- package/esm/replaceDeep.d.ts.map +1 -1
- package/esm/replaceDeep.js +3 -20
- package/esm/replaceDeep.js.map +1 -1
- package/esm/replaceDeepByFn.d.ts +7 -0
- package/esm/replaceDeepByFn.d.ts.map +1 -0
- package/esm/replaceDeepByFn.js +44 -0
- package/esm/replaceDeepByFn.js.map +1 -0
- package/esm/safe.js.map +1 -1
- package/esm/sample.d.ts +3 -1
- package/esm/sample.d.ts.map +1 -1
- package/esm/sample.js.map +1 -1
- package/esm/samples.d.ts.map +1 -1
- package/esm/samples.js.map +1 -1
- package/esm/seq.d.ts.map +1 -1
- package/esm/seq.js +1 -1
- package/esm/seq.js.map +1 -1
- package/esm/serialize.d.ts.map +1 -1
- package/esm/serialize.js +56 -18
- package/esm/serialize.js.map +1 -1
- package/esm/set.js.map +1 -1
- package/esm/setImmutable.js.map +1 -1
- package/esm/shuffle.d.ts.map +1 -1
- package/esm/sortBy.d.ts.map +1 -1
- package/esm/sortBy.js.map +1 -1
- package/esm/sortProps.d.ts.map +1 -1
- package/esm/sortProps.js.map +1 -1
- package/esm/stripPrefix.js.map +1 -1
- package/esm/stripSuffix.js.map +1 -1
- package/esm/throttle.d.ts.map +1 -1
- package/esm/throttle.js.map +1 -1
- package/esm/toggle.d.ts.map +1 -1
- package/esm/toggle.js.map +1 -1
- package/esm/trim.d.ts +3 -0
- package/esm/trim.d.ts.map +1 -0
- package/esm/trim.js +7 -0
- package/esm/trim.js.map +1 -0
- package/esm/trimEnd.d.ts +3 -0
- package/esm/trimEnd.d.ts.map +1 -0
- package/esm/trimEnd.js +9 -0
- package/esm/trimEnd.js.map +1 -0
- package/esm/trimStart.d.ts +3 -0
- package/esm/trimStart.d.ts.map +1 -0
- package/esm/trimStart.js +9 -0
- package/esm/trimStart.js.map +1 -0
- package/esm/truthy.d.ts +1 -1
- package/esm/truthy.d.ts.map +1 -1
- package/esm/unique.d.ts.map +1 -1
- package/esm/utils/utils.d.ts +6 -0
- package/esm/utils/utils.d.ts.map +1 -0
- package/esm/utils/utils.js +7 -0
- package/esm/utils/utils.js.map +1 -0
- package/esm/waitFor.d.ts.map +1 -1
- package/esm/waitFor.js +1 -1
- package/esm/waitFor.js.map +1 -1
- package/esm/waitSync.js.map +1 -1
- package/package.json +10 -17
- package/pnpm-lock.yaml +661 -386
- package/src/compareProps.ts +9 -2
- package/src/deserialize.spec.ts +13 -0
- package/src/escapeRegExp.spec.ts +5 -3
- package/src/escapeRegExp.ts +3 -2
- package/src/formatDate.ts +2 -2
- package/src/get.spec.ts +1 -0
- package/src/getMultiple.ts +1 -0
- package/src/index.ts +4 -0
- package/src/isNumericString.ts +3 -3
- package/src/memoize.spec.ts +90 -0
- package/src/memoize.ts +35 -0
- package/src/merge.ts +30 -8
- package/src/mostFrequent.ts +1 -0
- package/src/omit.ts +8 -2
- package/src/pick.ts +1 -1
- package/src/remove.ts +1 -1
- package/src/removeCommonProperties.ts +4 -2
- package/src/replace.ts +1 -1
- package/src/replaceDeep.spec.ts +91 -0
- package/src/replaceDeep.ts +22 -27
- package/src/replaceDeepByFn.spec.ts +162 -0
- package/src/replaceDeepByFn.ts +93 -0
- package/src/rethrow.ts +1 -1
- package/src/sample.spec.ts +1 -0
- package/src/sample.ts +18 -2
- package/src/samples.ts +1 -1
- package/src/seq.spec.ts +6 -3
- package/src/seq.ts +1 -1
- package/src/serialize.spec.ts +43 -0
- package/src/serialize.ts +66 -19
- package/src/set.ts +1 -1
- package/src/setImmutable.ts +1 -1
- package/src/sortBy.ts +1 -1
- package/src/throttle.ts +1 -1
- package/src/trim.spec.ts +22 -0
- package/src/trim.ts +23 -0
- package/src/trimEnd.spec.ts +20 -0
- package/src/trimEnd.ts +22 -0
- package/src/trimStart.spec.ts +20 -0
- package/src/trimStart.ts +22 -0
- package/src/utils/utils.ts +11 -0
- package/src/waitFor.spec.ts +7 -2
- package/src/waitFor.ts +1 -1
- package/typedoc.cjs +2 -4
- package/docs/assets/pages.css +0 -14
- package/docs/functions/cap.html +0 -149
- package/docs/functions/capitalize.html +0 -154
- package/docs/functions/coalesce.html +0 -159
- package/docs/functions/compareArrays.html +0 -162
- package/docs/functions/compareProps.html +0 -161
- package/docs/functions/deserialize.html +0 -153
- package/docs/functions/ensureArray.html +0 -147
- package/docs/functions/ensureDate.html +0 -149
- package/docs/functions/ensureError.html +0 -153
- package/docs/functions/ensurePrefix.html +0 -151
- package/docs/functions/ensureSuffix.html +0 -151
- package/docs/functions/ensureTimestamp.html +0 -149
- package/docs/functions/escapeRegExp.html +0 -145
- package/docs/functions/formatDate.html +0 -147
- package/docs/functions/get.html +0 -171
- package/docs/functions/getMultiple.html +0 -162
- package/docs/functions/insertSeparator.html +0 -156
- package/docs/functions/isEmpty.html +0 -172
- package/docs/functions/isNumericString.html +0 -146
- package/docs/functions/isPlainObject.html +0 -156
- package/docs/functions/last.html +0 -159
- package/docs/functions/later-1.html +0 -144
- package/docs/functions/mapAsync.html +0 -177
- package/docs/functions/mapValues.html +0 -163
- package/docs/functions/match.html +0 -155
- package/docs/functions/merge.html +0 -497
- package/docs/functions/mostFrequent.html +0 -144
- package/docs/functions/noop.html +0 -134
- package/docs/functions/occurrences.html +0 -158
- package/docs/functions/omit.html +0 -162
- package/docs/functions/pick.html +0 -162
- package/docs/functions/pull.html +0 -146
- package/docs/functions/remove.html +0 -162
- package/docs/functions/removeCommonProperties.html +0 -161
- package/docs/functions/replace.html +0 -151
- package/docs/functions/replaceDeep.html +0 -158
- package/docs/functions/rethrow.html +0 -139
- package/docs/functions/round.html +0 -148
- package/docs/functions/safe.html +0 -189
- package/docs/functions/sample.html +0 -146
- package/docs/functions/samples.html +0 -156
- package/docs/functions/scale.html +0 -150
- package/docs/functions/seq.html +0 -161
- package/docs/functions/seqEarlyBreak.html +0 -159
- package/docs/functions/serialize.html +0 -158
- package/docs/functions/set.html +0 -171
- package/docs/functions/setImmutable.html +0 -170
- package/docs/functions/shuffle.html +0 -146
- package/docs/functions/sortBy.html +0 -168
- package/docs/functions/sortProps.html +0 -156
- package/docs/functions/stripPrefix.html +0 -145
- package/docs/functions/stripSuffix.html +0 -145
- package/docs/functions/throttle.html +0 -164
- package/docs/functions/toggle.html +0 -151
- package/docs/functions/truthy.html +0 -151
- package/docs/functions/unique.html +0 -149
- package/docs/functions/wait.html +0 -142
- package/docs/functions/waitFor.html +0 -161
- package/docs/functions/waitSync.html +0 -142
- package/docs/interfaces/ComparePropsOptions.html +0 -70
- package/docs/interfaces/GetMultipleSource.html +0 -139
- package/docs/interfaces/GetSource.html +0 -139
- package/docs/interfaces/IsNumericStringOptions.html +0 -91
- package/docs/interfaces/OccurencesOptions.html +0 -72
- package/docs/interfaces/SetImmutableSource.html +0 -139
- package/docs/interfaces/SetSource.html +0 -139
- package/docs/interfaces/ThrottleOptions.html +0 -81
- package/docs/interfaces/ThrottledFunctionExtras.html +0 -97
- package/docs/modules.html +0 -217
- package/docs/pages/CHANGELOG.html +0 -924
- package/docs/pages/Introduction.html +0 -127
- package/docs/types/CustomDeserializers.html +0 -156
- package/docs/types/CustomSerializers.html +0 -156
- package/docs/types/Later.html +0 -170
- package/docs/types/MapValuesFn.html +0 -167
- package/docs/types/MatchCallback.html +0 -146
- package/docs/types/SeqEarlyBreaker.html +0 -147
- package/docs/types/SeqFn.html +0 -145
- package/docs/types/SeqFunctions.html +0 -138
- package/docs/types/SetImmutablePath.html +0 -132
- package/docs/types/ThrottledFunction.html +0 -146
- package/docs/variables/mapValuesUNSET.html +0 -134
- package/docs/variables/mergeUNSET.html +0 -136
- package/tutorials/Introduction.md +0 -1
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { replaceDeepByFn } from "./replaceDeepByFn";
|
|
2
|
+
|
|
3
|
+
class MyClass {
|
|
4
|
+
public value: number;
|
|
5
|
+
|
|
6
|
+
public constructor(value: number) {
|
|
7
|
+
this.value = value;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe("replaceDeepByFn", () => {
|
|
12
|
+
it("should replace given value in a deep object", () => {
|
|
13
|
+
const source = [
|
|
14
|
+
99,
|
|
15
|
+
100,
|
|
16
|
+
{
|
|
17
|
+
favouriteBook: {
|
|
18
|
+
title: "The Ring of The Lord",
|
|
19
|
+
price: 100,
|
|
20
|
+
},
|
|
21
|
+
otherBooks: [
|
|
22
|
+
{
|
|
23
|
+
title: "Parry Hotter",
|
|
24
|
+
price: 50,
|
|
25
|
+
tag: "100",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
title: "The Hobbyte 100",
|
|
29
|
+
price: [100],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
must(replaceDeepByFn(source, v => v === 100, () => 200)).eql([
|
|
36
|
+
99,
|
|
37
|
+
200,
|
|
38
|
+
{
|
|
39
|
+
favouriteBook: {
|
|
40
|
+
title: "The Ring of The Lord",
|
|
41
|
+
price: 200,
|
|
42
|
+
},
|
|
43
|
+
otherBooks: [
|
|
44
|
+
{
|
|
45
|
+
title: "Parry Hotter",
|
|
46
|
+
price: 50,
|
|
47
|
+
tag: "100",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
title: "The Hobbyte 100",
|
|
51
|
+
price: [200],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should leave primitives as-is unless they equal to the search value", () => {
|
|
59
|
+
must(replaceDeepByFn(100, v => v === 200, () => 300)).equal(100);
|
|
60
|
+
must(replaceDeepByFn(200, v => v === 200, () => 300)).equal(300);
|
|
61
|
+
must(replaceDeepByFn("100", v => v === 200, () => 300)).equal("100");
|
|
62
|
+
// ESLINT BUG: (see replaceDeep.spec.ts)
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
|
64
|
+
must(replaceDeepByFn(undefined, v => v === 200, () => 300)).equal(undefined);
|
|
65
|
+
must(replaceDeepByFn(null, v => v === 200, () => 300)).equal(null);
|
|
66
|
+
must(replaceDeepByFn(true, v => v === 200, () => 300)).equal(true);
|
|
67
|
+
must(replaceDeepByFn(666n, v => v === 200, () => 300)).equal(666n);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should work with nans", async () => {
|
|
71
|
+
must(replaceDeepByFn({
|
|
72
|
+
a: NaN,
|
|
73
|
+
b: 123,
|
|
74
|
+
}, v => Number.isNaN(v), () => 300)).eql({
|
|
75
|
+
a: 300,
|
|
76
|
+
b: 123,
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should allow to replace nils", async () => {
|
|
81
|
+
must(replaceDeepByFn(null, v => v === null, () => 300)).equal(300);
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
|
83
|
+
must(replaceDeepByFn(undefined, v => v === undefined, () => 300)).equal(300);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("does not mutate the original object", () => {
|
|
87
|
+
const source = {
|
|
88
|
+
a: 1,
|
|
89
|
+
b: {
|
|
90
|
+
c: 2,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
const result = replaceDeepByFn(source, v => v === 2, () => 3);
|
|
94
|
+
must(result).not.equal(source);
|
|
95
|
+
must(result.b).not.equal(source.b);
|
|
96
|
+
must(result).eql({
|
|
97
|
+
a: 1,
|
|
98
|
+
b: {
|
|
99
|
+
c: 3,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("does not mutate original array", async () => {
|
|
105
|
+
const source = [1, 2, 3, [2, 3]];
|
|
106
|
+
const result = replaceDeepByFn(source, v => v === 2, () => 4);
|
|
107
|
+
must(result).not.equal(source);
|
|
108
|
+
must(result[3]).not.equal(source[3]);
|
|
109
|
+
must(result).eql([1, 4, 3, [4, 3]]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("mutates the original object when enabled", () => {
|
|
113
|
+
const source = {
|
|
114
|
+
a: 1,
|
|
115
|
+
b: {
|
|
116
|
+
c: 2,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
const result = replaceDeepByFn(source, v => v === 2, () => 3, { mutate: true });
|
|
120
|
+
must(result).equal(source);
|
|
121
|
+
must(result.b).equal(source.b);
|
|
122
|
+
must(result).eql({
|
|
123
|
+
a: 1,
|
|
124
|
+
b: {
|
|
125
|
+
c: 3,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("mutates original array when enabled", async () => {
|
|
131
|
+
const source = [1, 2, 3, [2, 3]];
|
|
132
|
+
const result = replaceDeepByFn(source, v => v === 2, () => 4, { mutate: true });
|
|
133
|
+
must(result).equal(source);
|
|
134
|
+
must(result[3]).equal(source[3]);
|
|
135
|
+
must(result).eql([1, 4, 3, [4, 3]]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("does not get into instances by default", async () => {
|
|
139
|
+
const source = new MyClass(100);
|
|
140
|
+
const result = replaceDeepByFn(source, v => v === 100, () => 200);
|
|
141
|
+
must(result).equal(source);
|
|
142
|
+
must(source.value).equal(100);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("gets into instances when allowed", async () => {
|
|
146
|
+
const source = new MyClass(100);
|
|
147
|
+
const result = replaceDeepByFn(source, v => v === 100, () => 200, {
|
|
148
|
+
replaceInstancesProps: true,
|
|
149
|
+
mutate: true,
|
|
150
|
+
});
|
|
151
|
+
must(result).equal(source);
|
|
152
|
+
must(source.value).equal(200);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("requires `mutate` option if `replaceInstancesProps` is defined", async () => {
|
|
156
|
+
const source = new MyClass(100);
|
|
157
|
+
must(() => replaceDeepByFn(source, v => v === 100, () => 200, {
|
|
158
|
+
replaceInstancesProps: true,
|
|
159
|
+
mutate: false,
|
|
160
|
+
})).throw("`replaceInstancesProps` option requires `mutate` to be enabled");
|
|
161
|
+
});
|
|
162
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { isPlainObject } from "./isPlainObject";
|
|
2
|
+
|
|
3
|
+
type Options = {
|
|
4
|
+
/**
|
|
5
|
+
* If true, the source objects and arrays will be mutated. Default is false.
|
|
6
|
+
*/
|
|
7
|
+
mutate?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* If true, the function will go into instances for replacement. Otherwise, it will only replace properties of plain
|
|
10
|
+
* objects. Default is false.
|
|
11
|
+
* Warning: This option requires `mutate` to be enabled, because we can't clone instances.
|
|
12
|
+
*/
|
|
13
|
+
replaceInstancesProps?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Replaces all occurrences of `search` with `value` in `source` object/array. You do comparison by yourself by providing a callback function.
|
|
18
|
+
*
|
|
19
|
+
* Warnings:
|
|
20
|
+
* - By default, it does not mutate the `source`/deep objects/arrays, but it can be enabled with `mutate` option.
|
|
21
|
+
* - By default, it does not go into instances for replacement, only plain objects.
|
|
22
|
+
* - If your instances are cross-referenced, you may end up in an infinite loop.
|
|
23
|
+
*
|
|
24
|
+
* TypeScript users: This is way too dynamic to type properly, therefore, typing assumes the most basic form of
|
|
25
|
+
* replacement where search and value are of the same type. If that's not the case for you - you'll have to typecast.
|
|
26
|
+
*
|
|
27
|
+
* @param source - source object/array/value
|
|
28
|
+
* @param search - value to search for
|
|
29
|
+
* @param replaceWith - value to replace with
|
|
30
|
+
* @param options - optional options
|
|
31
|
+
*/
|
|
32
|
+
const replaceDeepByFn = <T>( // eslint-disable-line max-statements
|
|
33
|
+
source: T, search: (value: unknown) => boolean, replaceWith: (value: unknown) => unknown, options?: Options,
|
|
34
|
+
): T => {
|
|
35
|
+
if (options?.replaceInstancesProps && !options.mutate) {
|
|
36
|
+
throw new Error("`replaceInstancesProps` option requires `mutate` to be enabled");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const searchResult = search(source);
|
|
40
|
+
|
|
41
|
+
if (typeof searchResult !== "boolean") {
|
|
42
|
+
throw new Error("search function must return a boolean");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (searchResult) {
|
|
46
|
+
return replaceWith(source) as T;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (source == null) {
|
|
50
|
+
return source;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof source === "object") {
|
|
54
|
+
if (Array.isArray(source)) {
|
|
55
|
+
if (options?.mutate) {
|
|
56
|
+
for (let i = 0; i < source.length; i++) {
|
|
57
|
+
// eslint-disable-next-line no-param-reassign,@typescript-eslint/no-unsafe-assignment
|
|
58
|
+
source[i] = replaceDeepByFn(source[i], search, replaceWith, options);
|
|
59
|
+
}
|
|
60
|
+
return source;
|
|
61
|
+
}
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
63
|
+
return source.map((item) => replaceDeepByFn(item, search, replaceWith, options)) as unknown as T;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (options?.mutate) {
|
|
67
|
+
if (isPlainObject(source) || options.replaceInstancesProps) {
|
|
68
|
+
for (const key of Object.keys(source)) {
|
|
69
|
+
// eslint-disable-next-line no-param-reassign
|
|
70
|
+
(source as Record<string, unknown>)[key] = replaceDeepByFn(
|
|
71
|
+
(source as Record<string, unknown>)[key], search, replaceWith, options,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return source;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (isPlainObject(source)) {
|
|
80
|
+
return Object.keys(source).reduce<Record<string, unknown>>((acc, key) => {
|
|
81
|
+
// eslint-disable-next-line no-param-reassign
|
|
82
|
+
acc[key] = replaceDeepByFn((source as Record<string, unknown>)[key], search, replaceWith, options);
|
|
83
|
+
return acc;
|
|
84
|
+
}, {}) as T;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return source;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export {
|
|
92
|
+
replaceDeepByFn,
|
|
93
|
+
};
|
package/src/rethrow.ts
CHANGED
package/src/sample.spec.ts
CHANGED
|
@@ -25,6 +25,7 @@ describe("sample", () => {
|
|
|
25
25
|
|
|
26
26
|
it("should work with 0 items array", async () => {
|
|
27
27
|
const array: never[] = [];
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
|
28
29
|
const item = sample(array);
|
|
29
30
|
must(item).equal(undefined);
|
|
30
31
|
});
|
package/src/sample.ts
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2
|
+
type IsTuple<T> = T extends readonly [infer A, ...(infer B)] ? true : false;
|
|
3
|
+
type MaybeTupleReturn<T> = IsTuple<T> extends true
|
|
4
|
+
? (T extends readonly (infer U)[] ? U : never)
|
|
5
|
+
: (T extends (infer U)[] ? U | undefined : never);
|
|
6
|
+
|
|
1
7
|
/**
|
|
2
8
|
* Picks a random element from an array.
|
|
3
9
|
* @param array - source array
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* sample([1, 2, 3]); // 2 (type: number | undefined)
|
|
13
|
+
* sample(["a", "b", "c"]); // "c" (type: string | undefined)
|
|
14
|
+
* sample([]); // undefined (type: undefined)
|
|
15
|
+
*
|
|
16
|
+
* const a = [1, 2, 3] as const;
|
|
17
|
+
* sample(a); // 2 (type: 1 | 2 | 3)
|
|
18
|
+
*
|
|
19
|
+
* sample([1, 1, 1] as [number, number, number]); // 1 (type: number)
|
|
4
20
|
*/
|
|
5
|
-
const sample = <T>(array: T
|
|
6
|
-
return array[Math.floor(Math.random() * array.length)]
|
|
21
|
+
const sample = <X, T extends readonly X[]>(array: T): MaybeTupleReturn<T> => {
|
|
22
|
+
return array[Math.floor(Math.random() * array.length)] as MaybeTupleReturn<T>;
|
|
7
23
|
};
|
|
8
24
|
|
|
9
25
|
export {
|
package/src/samples.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @param elementsToPick - number of elements to pick
|
|
9
9
|
* @param allowShuffle - if true, it will shuffle the values if elementsToPick is greater or equal to array length instead of returning the original array
|
|
10
10
|
*/
|
|
11
|
-
const samples = <T>(array: T[], elementsToPick: number, allowShuffle = false): T[] => { // eslint-disable-line max-statements
|
|
11
|
+
const samples = <T>(array: T[], elementsToPick: number, allowShuffle = false): T[] => { // eslint-disable-line max-statements
|
|
12
12
|
if (elementsToPick < 0) {
|
|
13
13
|
throw new Error("elementsToPick must be a positive number");
|
|
14
14
|
}
|
package/src/seq.spec.ts
CHANGED
|
@@ -119,17 +119,20 @@ describe("seq", () => {
|
|
|
119
119
|
const list = [
|
|
120
120
|
() => {
|
|
121
121
|
firstCalled = true;
|
|
122
|
-
|
|
122
|
+
|
|
123
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
|
123
124
|
return Promise.reject(1);
|
|
124
125
|
},
|
|
125
126
|
() => {
|
|
126
127
|
secondCalled = true;
|
|
127
|
-
|
|
128
|
+
|
|
129
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
|
128
130
|
return Promise.reject(2);
|
|
129
131
|
},
|
|
130
132
|
() => {
|
|
131
133
|
thirdCalled = true;
|
|
132
|
-
|
|
134
|
+
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
|
133
136
|
return Promise.reject(3);
|
|
134
137
|
},
|
|
135
138
|
];
|
package/src/seq.ts
CHANGED
|
@@ -38,7 +38,7 @@ const run = <T>(list: Fn<T>[], earlyBreaker?: EarlyBreaker): Promise<T> => {
|
|
|
38
38
|
const errors: Error[] = [];
|
|
39
39
|
|
|
40
40
|
const doTry = function(error?: Error) {
|
|
41
|
-
if (error !== undefined && earlyBreaker
|
|
41
|
+
if (error !== undefined && earlyBreaker?.(error)) {
|
|
42
42
|
reject(error);
|
|
43
43
|
return;
|
|
44
44
|
}
|
package/src/serialize.spec.ts
CHANGED
|
@@ -9,6 +9,7 @@ interface Test {
|
|
|
9
9
|
class Person {
|
|
10
10
|
public name: string;
|
|
11
11
|
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
12
13
|
public constructor(name: string) {
|
|
13
14
|
this.name = name;
|
|
14
15
|
}
|
|
@@ -80,4 +81,46 @@ describe("serialize", () => {
|
|
|
80
81
|
|
|
81
82
|
must(serialize(a)).equal(serialize(b));
|
|
82
83
|
});
|
|
84
|
+
|
|
85
|
+
it("allows serializing dates and other objects containing .toJSON", async () => {
|
|
86
|
+
const date = new Date(1714390008941);
|
|
87
|
+
must(serialize(date, {
|
|
88
|
+
D: (value) => {
|
|
89
|
+
if (value instanceof Date) {
|
|
90
|
+
return String(value.getTime());
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
},
|
|
94
|
+
})).equal(`"D:1714390008941"`);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should avoid excessive calls to custom serializers", async () => {
|
|
98
|
+
const customSerializers: CustomSerializers = {
|
|
99
|
+
p: (value) => {
|
|
100
|
+
// console.log("Called with", typeof value, value);
|
|
101
|
+
if (value instanceof Person) {
|
|
102
|
+
return value.name;
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const p1 = new Person("John");
|
|
109
|
+
const spy = jest.spyOn(customSerializers, "p");
|
|
110
|
+
|
|
111
|
+
serialize({
|
|
112
|
+
a: [p1],
|
|
113
|
+
b: 1,
|
|
114
|
+
c: {
|
|
115
|
+
d: true,
|
|
116
|
+
e: p1,
|
|
117
|
+
},
|
|
118
|
+
}, customSerializers);
|
|
119
|
+
expect(spy).toHaveBeenCalledTimes(4);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should not crash on unknown instances but serialize as plain object", async () => {
|
|
123
|
+
const p1 = new Person("John");
|
|
124
|
+
must(serialize(p1)).equal(`{"name":"s:John"}`);
|
|
125
|
+
});
|
|
83
126
|
});
|
package/src/serialize.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { sortProps } from "./sortProps.js";
|
|
2
|
+
import { replaceDeepByFn } from "./replaceDeepByFn.js";
|
|
3
|
+
import { isPlainObject } from "./isPlainObject.js";
|
|
4
|
+
import { DataWrapper } from "./utils/utils.js";
|
|
2
5
|
|
|
3
6
|
type CustomSerializers = {
|
|
4
7
|
[key: string]: (data: unknown) => (string | null);
|
|
@@ -32,7 +35,33 @@ type Options = {
|
|
|
32
35
|
* @param customSerializers - an object with custom serializers
|
|
33
36
|
* @param options - options
|
|
34
37
|
*/
|
|
35
|
-
const serialize = (data: unknown, customSerializers?: CustomSerializers, options?: Options) => { // eslint-disable-line max-lines-per-function
|
|
38
|
+
const serialize = (data: unknown, customSerializers?: CustomSerializers, options?: Options) => { // eslint-disable-line max-lines-per-function
|
|
39
|
+
const sourceData = Object.keys(customSerializers ?? {}).length
|
|
40
|
+
? replaceDeepByFn(
|
|
41
|
+
data,
|
|
42
|
+
value => {
|
|
43
|
+
if (["string", "number", "bigint", "undefined", "boolean"].includes(typeof value)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
if (value === null || Array.isArray(value)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (isPlainObject(value)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const serializerKeys = Object.keys(customSerializers ?? {});
|
|
54
|
+
for (const key of serializerKeys) {
|
|
55
|
+
const serialized = customSerializers![key]!(value);
|
|
56
|
+
if (typeof serialized === "string") {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
},
|
|
62
|
+
value => new DataWrapper(value),
|
|
63
|
+
)
|
|
64
|
+
: data;
|
|
36
65
|
const replacer = (_key: string, value: unknown) => { // eslint-disable-line max-statements
|
|
37
66
|
if (typeof value === "string") {
|
|
38
67
|
return `s:${value}`;
|
|
@@ -52,12 +81,22 @@ const serialize = (data: unknown, customSerializers?: CustomSerializers, options
|
|
|
52
81
|
if (value === null) {
|
|
53
82
|
return "l:";
|
|
54
83
|
}
|
|
84
|
+
if (Array.isArray(value)) {
|
|
85
|
+
return value as unknown[];
|
|
86
|
+
}
|
|
87
|
+
if (isPlainObject(value)) {
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
55
90
|
const serializerKeys = Object.keys(customSerializers ?? {});
|
|
56
91
|
for (const key of serializerKeys) {
|
|
57
|
-
const serialized = customSerializers![key]!(value);
|
|
92
|
+
const serialized = customSerializers![key]!(value instanceof DataWrapper ? value.data : value);
|
|
58
93
|
if (typeof serialized === "string") {
|
|
59
94
|
return `${key}:${serialized}`;
|
|
60
95
|
}
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
97
|
+
if (serialized !== null) {
|
|
98
|
+
throw new Error(`Custom serializer for key ${key} returned a non-string value: ${String(serialized)}`);
|
|
99
|
+
}
|
|
61
100
|
}
|
|
62
101
|
if (typeof value === "object") {
|
|
63
102
|
return value;
|
|
@@ -67,35 +106,43 @@ const serialize = (data: unknown, customSerializers?: CustomSerializers, options
|
|
|
67
106
|
};
|
|
68
107
|
|
|
69
108
|
if (
|
|
70
|
-
|
|
71
|
-
|| typeof
|
|
72
|
-
|| typeof
|
|
73
|
-
|| typeof
|
|
74
|
-
|| typeof
|
|
75
|
-
|| typeof
|
|
76
|
-
|| Array.isArray(
|
|
109
|
+
sourceData == null
|
|
110
|
+
|| typeof sourceData === "string"
|
|
111
|
+
|| typeof sourceData === "number"
|
|
112
|
+
|| typeof sourceData === "bigint"
|
|
113
|
+
|| typeof sourceData === "undefined"
|
|
114
|
+
|| typeof sourceData === "boolean"
|
|
115
|
+
|| Array.isArray(sourceData)
|
|
77
116
|
) {
|
|
78
|
-
return JSON.stringify(
|
|
117
|
+
return JSON.stringify(sourceData, replacer);
|
|
79
118
|
}
|
|
80
119
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
120
|
+
if (!isPlainObject(sourceData)) {
|
|
121
|
+
const serializerKeysGlobal = Object.keys(customSerializers ?? {});
|
|
122
|
+
for (const key of serializerKeysGlobal) {
|
|
123
|
+
const serialized = customSerializers![key]!(
|
|
124
|
+
sourceData instanceof DataWrapper ? sourceData.data : sourceData,
|
|
125
|
+
);
|
|
126
|
+
if (typeof serialized === "string") {
|
|
127
|
+
return `"${key}:${serialized}"`;
|
|
128
|
+
}
|
|
129
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
130
|
+
if (serialized !== null) {
|
|
131
|
+
throw new Error(`Custom serializer for key ${key} returned a non-string value: ${String(serialized)}`);
|
|
132
|
+
}
|
|
86
133
|
}
|
|
87
134
|
}
|
|
88
135
|
|
|
89
|
-
if (typeof
|
|
136
|
+
if (typeof sourceData === "object") {
|
|
90
137
|
return JSON.stringify(
|
|
91
138
|
options?.sortProps === false
|
|
92
|
-
?
|
|
93
|
-
: sortProps(
|
|
139
|
+
? sourceData
|
|
140
|
+
: sortProps(sourceData as Record<string, unknown>),
|
|
94
141
|
replacer,
|
|
95
142
|
);
|
|
96
143
|
}
|
|
97
144
|
|
|
98
|
-
throw new Error(`Unsupported data type: ${typeof
|
|
145
|
+
throw new Error(`Unsupported data type: ${typeof sourceData}`);
|
|
99
146
|
};
|
|
100
147
|
|
|
101
148
|
export type { CustomSerializers };
|
package/src/set.ts
CHANGED
|
@@ -30,7 +30,7 @@ const isObject = (value: unknown) => (typeof value === "object" || typeof value
|
|
|
30
30
|
* { "items": { "0": value }}
|
|
31
31
|
* @returns {Object} - given object or new object if source was primitive
|
|
32
32
|
*/
|
|
33
|
-
const set = (source: Source, path: string | string[], value: unknown): Source | unknown => { // eslint-disable-line @typescript-eslint/no-redundant-type-constituents
|
|
33
|
+
const set = (source: Source, path: string | string[], value: unknown): Source | unknown => { // eslint-disable-line @typescript-eslint/no-redundant-type-constituents
|
|
34
34
|
const pathParts = typeof path === "string" ? path.split(".") : path;
|
|
35
35
|
const len = pathParts.length;
|
|
36
36
|
|
package/src/setImmutable.ts
CHANGED
|
@@ -67,7 +67,7 @@ const getPathParts = (path: Path) => {
|
|
|
67
67
|
* { "items": { "0": value }}
|
|
68
68
|
* @returns {Object} - given object or new object if source was primitive
|
|
69
69
|
*/
|
|
70
|
-
const setImmutable = (source: Source, path: Path, value: unknown): Source | unknown => { // eslint-disable-line max-statements,
|
|
70
|
+
const setImmutable = (source: Source, path: Path, value: unknown): Source | unknown => { // eslint-disable-line max-statements, @typescript-eslint/no-redundant-type-constituents
|
|
71
71
|
const pathParts = getPathParts(path);
|
|
72
72
|
const isValidPath = hasOnlyValidPathParts(pathParts);
|
|
73
73
|
if (!isValidPath) {
|
package/src/sortBy.ts
CHANGED
|
@@ -10,7 +10,7 @@ const sortBy = <T>(propertyName: keyof T, asc = true, defaultValue: unknown = nu
|
|
|
10
10
|
return 0;
|
|
11
11
|
}
|
|
12
12
|
// @ts-expect-error We don't care about types here, it's for runtime pure JS too
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
if ((a[propertyName] ?? defaultValue) > (b[propertyName] ?? defaultValue)) {
|
|
15
15
|
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
|
16
16
|
return asc ? 1 : -1;
|
package/src/throttle.ts
CHANGED
|
@@ -46,7 +46,7 @@ type CanReturnUndefined<F extends (...args: any[]) => any> = (...args: Parameter
|
|
|
46
46
|
* @param {number | number[]} time - throttle time as number or array of numbers (min 1 element)
|
|
47
47
|
* @param {Opts} options
|
|
48
48
|
*/
|
|
49
|
-
const throttle = <RT, F extends (...args: any[]) => RT>( // eslint-disable-line max-lines-per-function, @typescript-eslint/no-explicit-any
|
|
49
|
+
const throttle = <RT, F extends (...args: any[]) => RT>( // eslint-disable-line max-lines-per-function, @typescript-eslint/no-explicit-any
|
|
50
50
|
fn: F, time: number | [number, ...number[]] = 0, options?: Opts,
|
|
51
51
|
): CanReturnUndefined<F> & Extras => {
|
|
52
52
|
const opts: Required<Opts> = {
|
package/src/trim.spec.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { trim } from "./trim";
|
|
2
|
+
|
|
3
|
+
describe("trim", () => {
|
|
4
|
+
it("should trim single character from both sides of the string", async () => {
|
|
5
|
+
must(trim("aaacataaa", "a")).equal("cat");
|
|
6
|
+
must(trim("abacteria", "a")).equal("bacteri");
|
|
7
|
+
must(trim("abc", "a")).equal("bc");
|
|
8
|
+
must(trim("abc", "c")).equal("ab");
|
|
9
|
+
must(trim("aajjja", "a")).equal("jjj");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should trim multiple characters as a whole", async () => {
|
|
13
|
+
must(trim("abopopab", "ab")).equal("opop");
|
|
14
|
+
must(trim("atitleb", "ab")).equal("atitleb");
|
|
15
|
+
must(trim("abtitleab", "ab")).equal("title");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("can trim into empty string", async () => {
|
|
19
|
+
must(trim("abc", "abc")).equal("");
|
|
20
|
+
must(trim("a", "a")).equal("");
|
|
21
|
+
});
|
|
22
|
+
});
|
package/src/trim.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { trimStart } from "./trimStart.js";
|
|
2
|
+
import { trimEnd } from "./trimEnd.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Removes given characters from both sides of the string.
|
|
6
|
+
* If you want to remove from one side of the string see {@link trimStart} and {@link trimEnd}.
|
|
7
|
+
*
|
|
8
|
+
* @param source - Source string.
|
|
9
|
+
* @param characters - Characters to remove, taken as a whole.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* trim("abcb", "ab"); // "cb"
|
|
13
|
+
* trim("!aaa!", "!"); // "aaa"
|
|
14
|
+
* trim("!aaa!!!", "!"); // "aaa"
|
|
15
|
+
* trim("!aaa!!!", "!!!"); // "!aaa"
|
|
16
|
+
*/
|
|
17
|
+
const trim = (source: string, characters: string) => {
|
|
18
|
+
return trimStart(trimEnd(source, characters), characters);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
trim,
|
|
23
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { trimEnd } from "./trimEnd";
|
|
2
|
+
|
|
3
|
+
describe("trimEnd", () => {
|
|
4
|
+
it("should trim single character from the end of the string", async () => {
|
|
5
|
+
must(trimEnd("abc?", "?")).equal("abc");
|
|
6
|
+
must(trimEnd("a? b?c???", "?")).equal("a? b?c");
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should trim multiple characters as a whole", async () => {
|
|
10
|
+
must(trimEnd("abc", "bc")).equal("a");
|
|
11
|
+
|
|
12
|
+
must(trimEnd("abcc", "bc")).equal("abcc");
|
|
13
|
+
must(trimEnd("abcb", "bc")).equal("abcb");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("can trim into empty string", async () => {
|
|
17
|
+
must(trimEnd("abc", "abc")).equal("");
|
|
18
|
+
must(trimEnd("a", "a")).equal("");
|
|
19
|
+
});
|
|
20
|
+
});
|
package/src/trimEnd.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes given characters from the end of the string.
|
|
3
|
+
* See also: {@link trim} and {@link trimStart}.
|
|
4
|
+
*
|
|
5
|
+
* @param source - Source string.
|
|
6
|
+
* @param characters - Characters to remove, taken as a whole.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* trimEnd("abcxzyz", "yz"); // "abcxz"
|
|
10
|
+
* trimEnd("!aaa!!", "!"); // "!aaa"
|
|
11
|
+
*/
|
|
12
|
+
const trimEnd = (source: string, characters: string) => {
|
|
13
|
+
let s = source;
|
|
14
|
+
while (s.endsWith(characters)) {
|
|
15
|
+
s = s.slice(0, -characters.length);
|
|
16
|
+
}
|
|
17
|
+
return s;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
trimEnd,
|
|
22
|
+
};
|