@revolugo/common 6.10.7-beta.7 → 6.10.7-beta.9

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.
Files changed (38) hide show
  1. package/package.json +1 -2
  2. package/src/cancellation-policies.ts +1 -1
  3. package/src/currencies/index.ts +1 -1
  4. package/src/utils/{math.ts → amount-from-percentage.ts} +0 -10
  5. package/src/utils/case-transformers.ts +0 -1
  6. package/src/utils/chunk.ts +7 -0
  7. package/src/utils/colors.ts +1 -1
  8. package/src/utils/compact-object.ts +7 -0
  9. package/src/utils/compact.ts +28 -0
  10. package/src/utils/compute-margin-rate.ts +13 -0
  11. package/src/utils/compute-selling-price.ts +12 -0
  12. package/src/utils/defaults-deep.ts +85 -0
  13. package/src/utils/delay.ts +5 -0
  14. package/src/utils/generate-numbers-from-str.ts +15 -0
  15. package/src/utils/generate-pseudo-random-string.ts +3 -0
  16. package/src/utils/get-guest-count.ts +1 -2
  17. package/src/utils/get-random-element-from-array.ts +10 -0
  18. package/src/utils/get-random-hex-color.ts +5 -0
  19. package/src/utils/{random.ts → get-random-int.ts} +0 -6
  20. package/src/utils/index.ts +30 -12
  21. package/src/utils/key-by.ts +25 -0
  22. package/src/utils/omit-by.ts +37 -0
  23. package/src/utils/omit.ts +39 -0
  24. package/src/utils/pick.ts +12 -0
  25. package/src/utils/poller.ts +0 -1
  26. package/src/utils/{strings.ts → prepare-ts-query.ts} +0 -6
  27. package/src/utils/{promise-tools.ts → promise-timeout.ts} +0 -6
  28. package/src/utils/random-int.ts +3 -0
  29. package/src/utils/shuffle-array.ts +13 -0
  30. package/src/utils/{array-tools.ts → sort-by.ts} +0 -103
  31. package/src/utils/sum-by.ts +23 -0
  32. package/src/utils/uniq-with.ts +16 -0
  33. package/src/utils/validators.ts +0 -1
  34. package/src/utils/weighted-mean.ts +9 -0
  35. package/src/utils/numbers.ts +0 -46
  36. package/src/utils/object-tools.ts +0 -210
  37. /package/src/utils/{value-tools.ts → is-nil.ts} +0 -0
  38. /package/src/utils/{children-tools.ts → parse-children.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revolugo/common",
3
- "version": "6.10.7-beta.7",
3
+ "version": "6.10.7-beta.9",
4
4
  "private": false,
5
5
  "description": "Revolugo common",
6
6
  "author": "Revolugo",
@@ -26,7 +26,6 @@
26
26
  "change-case": "5.4.4",
27
27
  "dayjs": "1.11.18",
28
28
  "ky": "1.11.0",
29
- "lodash-es": "4.17.21",
30
29
  "slugify": "1.6.6",
31
30
  "uuid": "13.0.0"
32
31
  },
@@ -1,4 +1,4 @@
1
- import { compact } from './utils/array-tools.ts'
1
+ import { compact } from './utils/compact.ts'
2
2
  import { type Dayjs, dayjs } from './utils/dayjs.ts'
3
3
  import { isEmpty } from './utils/is-empty.ts'
4
4
 
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable max-lines */
2
2
  import { Currency } from '../constants/currencies.ts'
3
- import { pick } from '../utils/object-tools.ts'
3
+ import { pick } from '../utils/pick.ts'
4
4
 
5
5
  import type { ICurrency } from '../types/currency.ts'
6
6
 
@@ -1,13 +1,3 @@
1
- export function weightedMean(values: number[], weights: number[]): number {
2
- const sum = values.reduce(
3
- (acc: number, val: number, i: number) => acc + val * (weights[i] ?? 0),
4
- 0,
5
- )
6
- const sumWeights = weights.reduce((acc: number, val: number) => acc + val, 0)
7
-
8
- return sum / sumWeights
9
- }
10
-
11
1
  export function amountFromPercentage(
12
2
  percentage: number,
13
3
  amount: number,
@@ -23,7 +23,6 @@ export enum CaseTransformer {
23
23
  Snake = 'snakeCase',
24
24
  }
25
25
 
26
- /* @__PURE__ */
27
26
  const CASE_TRANSORMERS_MAPPING = {
28
27
  [CaseTransformer.Camel]: camelCase,
29
28
  [CaseTransformer.Capital]: capitalCase,
@@ -0,0 +1,7 @@
1
+ export function chunk<T>(array: T[], size: number): T[][] {
2
+ const chunks: T[][] = []
3
+ for (let i = 0; i < array.length; i += size) {
4
+ chunks.push(array.slice(i, i + size))
5
+ }
6
+ return chunks
7
+ }
@@ -1,4 +1,4 @@
1
- import { generateNumbersFromStr } from './numbers.ts'
1
+ import { generateNumbersFromStr } from './generate-numbers-from-str.ts'
2
2
 
3
3
  export function generateRandomColorFromString(
4
4
  str: string,
@@ -0,0 +1,7 @@
1
+ import { isNil } from './is-nil.ts'
2
+
3
+ export function compactObject<T extends object>(obj: T): Partial<T> {
4
+ return Object.fromEntries(
5
+ Object.entries(obj).filter(([, value]) => !isNil(value)),
6
+ ) as Partial<T>
7
+ }
@@ -0,0 +1,28 @@
1
+ export function compact<T>(
2
+ array: (T | null | undefined)[] | null | undefined,
3
+ ): Exclude<T, null | undefined>[] {
4
+ const length = array === null || array === undefined ? 0 : array.length
5
+ let index = -1
6
+ let resIndex = 0
7
+ const result: Exclude<T, null | undefined>[] = []
8
+
9
+ while (index < length) {
10
+ index += 1
11
+ if (array !== null && array !== undefined) {
12
+ const value = array[index]
13
+
14
+ if (
15
+ value !== null &&
16
+ value !== undefined &&
17
+ value !== false &&
18
+ value !== 0 &&
19
+ value !== ''
20
+ ) {
21
+ result[resIndex] = value as Exclude<T, null | undefined>
22
+ resIndex += 1
23
+ }
24
+ }
25
+ }
26
+
27
+ return result
28
+ }
@@ -0,0 +1,13 @@
1
+ export function computeMarginRate(
2
+ buyingPrice: number | string,
3
+ sellingPrice: number | string,
4
+ ): number {
5
+ const buyingPriceNum = Number(buyingPrice)
6
+ const sellingPriceNum = Number(sellingPrice)
7
+
8
+ if (Number.isNaN(sellingPriceNum) || Number.isNaN(buyingPriceNum)) {
9
+ throw new TypeError('sellingPrice or buyingPrice is NaN')
10
+ }
11
+
12
+ return Number((1 - buyingPriceNum / sellingPriceNum).toPrecision(10))
13
+ }
@@ -0,0 +1,12 @@
1
+ export function computeSellingPrice(
2
+ buyingPrice: number | string | null = 0,
3
+ rate: number | string | null = 0,
4
+ ): number {
5
+ if (Number.isNaN(Number(buyingPrice)) || Number.isNaN(Number(rate))) {
6
+ throw new TypeError('price or rate is NaN')
7
+ }
8
+
9
+ const sellingPrice = Number(buyingPrice) / (1 - Number(rate))
10
+
11
+ return Math.ceil(Math.floor(sellingPrice * 100) / 100)
12
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Drop-in native TypeScript replacement for `lodash-es` `defaultsDeep`.
3
+ *
4
+ * Behaviour matched (carefully):
5
+ * - Mutates and returns the first argument (target).
6
+ * - Assigns own and *inherited* enumerable **string-keyed** properties from sources
7
+ * to the target only when the target's property is `undefined`.
8
+ * - Recursively assigns (deep) when both target and source values are objects/arrays.
9
+ * - Does not copy symbol-keyed properties (matches the "string keyed" behaviour).
10
+ * - Preserves `null` (i.e. `null` is NOT considered `undefined` so it won't be overwritten).
11
+ * - Avoids infinite recursion for circular source structures.
12
+ */
13
+
14
+ /* eslint-disable @typescript-eslint/no-explicit-any */
15
+ type AnyObject = Record<string, any>
16
+
17
+ function isObject(value: any): value is AnyObject {
18
+ return value !== null && typeof value === 'object'
19
+ }
20
+
21
+ export function defaultsDeep<T>(
22
+ object: T,
23
+ ...sources: any[]
24
+ ): T extends AnyObject ? T : any {
25
+ // Ensure we always return an object reference we can mutate (lodash creates/uses {} when target is falsy)
26
+ const target: AnyObject = (
27
+ object === null || object === undefined ? {} : object
28
+ ) as AnyObject
29
+
30
+ // WeakMap to track already-cloned source objects so circular refs won't blow the stack
31
+ const seen = new WeakMap<object, object>()
32
+
33
+ function applyDefaults(dst: AnyObject, src: any) {
34
+ // Only iterate string-keyed enumerable properties (own + inherited) => for...in
35
+ for (const key in src) {
36
+ if (Object.hasOwn(src, key)) {
37
+ const srcVal = src[key]
38
+ const dstVal = dst[key]
39
+
40
+ // only apply when destination is strictly `undefined` (lodash semantics)
41
+ if (dstVal === undefined) {
42
+ // eslint-disable-next-line max-depth
43
+ if (isObject(srcVal)) {
44
+ // If we've already cloned this source object (circular), reuse it
45
+ // eslint-disable-next-line max-depth
46
+ if (seen.has(srcVal)) {
47
+ dst[key] = seen.get(srcVal)
48
+ } else {
49
+ // Prepare new container (array vs object)
50
+ const created = Array.isArray(srcVal)
51
+ ? ([] as unknown[])
52
+ : ({} as AnyObject)
53
+ // remember mapping to handle circular refs
54
+ seen.set(srcVal, created)
55
+
56
+ // Recursively fill created from srcVal
57
+ applyDefaults(created, srcVal)
58
+
59
+ // assign the created clone as the default
60
+ dst[key] = created
61
+ }
62
+ } else {
63
+ // Primitive or function: assign directly
64
+ dst[key] = srcVal
65
+ }
66
+ } else if (isObject(dstVal) && isObject(srcVal)) {
67
+ // destination already has a value (not undefined) and both are objects => recurse
68
+ // (do not overwrite existing non-undefined values)
69
+ // Note: do not treat arrays specially here; Array.isArray check only used when creating new value
70
+ applyDefaults(dstVal, srcVal)
71
+ }
72
+ // else: destination has a non-undefined primitive or non-object - skip (do not overwrite)
73
+ }
74
+ }
75
+ }
76
+
77
+ for (const src of sources) {
78
+ if (src !== null && src !== undefined) {
79
+ // If source itself has been seen (unlikely across top-level sources), we still traverse it
80
+ applyDefaults(target, src)
81
+ }
82
+ }
83
+
84
+ return target as any
85
+ }
@@ -0,0 +1,5 @@
1
+ export function delay(duration: number): Promise<void> {
2
+ return new Promise(resolve => {
3
+ setTimeout(resolve, duration)
4
+ })
5
+ }
@@ -0,0 +1,15 @@
1
+ export function generateNumbersFromStr(str: string): [number, number] {
2
+ let hash = 5381
3
+ for (let i = 0; i < str.length; i++) {
4
+ // eslint-disable-next-line no-bitwise
5
+ hash = (hash << 5) + hash + str.charCodeAt(i)
6
+ }
7
+
8
+ // Generate two numbers using the hash
9
+ // eslint-disable-next-line no-bitwise
10
+ const num1 = (hash & 0xff_ff) / 0xff_ff
11
+ // eslint-disable-next-line no-bitwise
12
+ const num2 = ((hash >> 16) & 0xff_ff) / 0xff_ff
13
+
14
+ return [num1, num2]
15
+ }
@@ -0,0 +1,3 @@
1
+ export function generatePseudoRandomString(length: number): string {
2
+ return Array.from({ length }, () => Math.random().toString(36)[2]).join('')
3
+ }
@@ -1,6 +1,5 @@
1
- import { parseChildren } from './children-tools.ts'
1
+ import { parseChildren } from './parse-children.ts'
2
2
 
3
- /* @__PURE__ */
4
3
  export const CHILDREN_FREE_BREAKFAST_AGE_LIMIT = 4
5
4
 
6
5
  export function getGuestCount(
@@ -0,0 +1,10 @@
1
+ export function getRandomElementFromArray<T>(array: readonly T[]): T {
2
+ if (array.length === 0) {
3
+ throw new Error('Cannot get random element from empty array')
4
+ }
5
+ const element = array[Math.floor(Math.random() * array.length)]
6
+ if (element === undefined) {
7
+ throw new Error('Array element is undefined')
8
+ }
9
+ return element
10
+ }
@@ -0,0 +1,5 @@
1
+ export function getRandomHexColor(): string {
2
+ const hex = Math.floor(Math.random() * 0xffffff).toString(16)
3
+
4
+ return hex.padStart(6, '0').toUpperCase()
5
+ }
@@ -4,9 +4,3 @@ export function getRandomInt(min: number, max: number): number {
4
4
 
5
5
  return Math.floor(Math.random() * (roundedMax - roundedMin + 1)) + roundedMin
6
6
  }
7
-
8
- export function getRandomHexColor(): string {
9
- const hex = Math.floor(Math.random() * 0xffffff).toString(16)
10
-
11
- return hex.padStart(6, '0').toUpperCase()
12
- }
@@ -1,32 +1,50 @@
1
1
  export * from './add-classes.ts'
2
- export * from './array-tools.ts'
2
+ export * from './amount-from-percentage.ts'
3
3
  export * from './case-transformers.ts'
4
+ export * from './chunk.ts'
4
5
  export * from './colors.ts'
6
+ export * from './compact-object.ts'
7
+ export * from './compact.ts'
8
+ export * from './compute-margin-rate.ts'
9
+ export * from './compute-selling-price.ts'
10
+ export * from './create-composite-key.ts'
5
11
  export * from './currency.ts'
6
12
  export * from './dates.ts'
7
13
  export * from './dayjs.ts'
8
14
  export * from './debounce.ts'
15
+ export * from './defaults-deep.ts'
16
+ export * from './delay.ts'
9
17
  export * from './find-unique-keys.ts'
18
+ export * from './generate-numbers-from-str.ts'
19
+ export * from './generate-pseudo-random-string.ts'
10
20
  export * from './get-guest-count.ts'
21
+ export * from './get-random-element-from-array.ts'
22
+ export * from './get-random-hex-color.ts'
23
+ export * from './get-random-int.ts'
11
24
  export * from './group-by.ts'
25
+ export * from './images.ts'
12
26
  export * from './is-empty.ts'
13
27
  export * from './is-equal.ts'
28
+ export * from './is-nil.ts'
29
+ export * from './key-by.ts'
14
30
  export * from './lang-default-fallbacks.ts'
15
- export * from './math.ts'
16
31
  export * from './merge.ts'
17
- export * from './numbers.ts'
18
- export * from './object-tools.ts'
32
+ export * from './omit-by.ts'
33
+ export * from './omit.ts'
34
+ export * from './parse-children.ts'
35
+ export * from './pick.ts'
19
36
  export * from './poller.ts'
20
- export * from './promise-tools.ts'
21
- export * from './random.ts'
37
+ export * from './prepare-ts-query.ts'
38
+ export * from './promise-timeout.ts'
39
+ export * from './random-int.ts'
22
40
  export * from './range.ts'
23
- export * from './strings.ts'
41
+ export * from './shake.ts'
42
+ export * from './shuffle-array.ts'
43
+ export * from './sort-by.ts'
44
+ export * from './sum-by.ts'
24
45
  export * from './sum.ts'
25
46
  export * from './to-boolean.ts'
26
47
  export * from './uniq-by.ts'
48
+ export * from './uniq-with.ts'
27
49
  export * from './validators.ts'
28
- export * from './value-tools.ts'
29
- export * from './create-composite-key.ts'
30
- export * from './children-tools.ts'
31
- export * from './shake.ts'
32
- export * from './images.ts'
50
+ export * from './weighted-mean.ts'
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Creates an object composed of keys generated from the results of running each element of collection through iteratee.
3
+ * The corresponding value of each key is the last element responsible for generating the key.
4
+ *
5
+ * @param collection - The collection to iterate over
6
+ * @param iteratee - The iteratee to transform keys. Can be a function or a property name
7
+ * @returns Returns the composed aggregate object
8
+ */
9
+ export function keyBy<T>(
10
+ collection: T[] | null | undefined,
11
+ iteratee: ((value: T) => string | number) | keyof T,
12
+ ): Record<string, T> {
13
+ return (
14
+ collection?.reduce<Record<string, T>>((acc, item) => {
15
+ if (item === undefined || item === null) {
16
+ return acc
17
+ }
18
+
19
+ const key =
20
+ typeof iteratee === 'function' ? iteratee(item) : String(item[iteratee])
21
+ acc[key] = item
22
+ return acc
23
+ }, {}) || {}
24
+ )
25
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Creates an object composed of the own enumerable properties of object that predicate doesn't return truthy for.
3
+ * The predicate is invoked with two arguments: (value, key).
4
+ * If predicate is a string, it omits the property with that key name.
5
+ *
6
+ * @param object - The source object
7
+ * @param predicate - The function invoked per property or a string key to omit
8
+ * @returns Returns the new object
9
+ */
10
+ export function omitBy<T extends object>(
11
+ object: T,
12
+ predicate: ((value: T[keyof T], key: keyof T) => boolean) | string,
13
+ ): Partial<T> {
14
+ const result = {} as Partial<T>
15
+
16
+ for (const key in object) {
17
+ if (Object.hasOwn(object, key)) {
18
+ const value = object[key]
19
+
20
+ // If predicate is a string, check if key matches
21
+ if (typeof predicate === 'string') {
22
+ // eslint-disable-next-line max-depth
23
+ if (key !== predicate) {
24
+ result[key] = value
25
+ }
26
+ } else if (typeof predicate === 'function') {
27
+ // If predicate is a function, use it
28
+ // eslint-disable-next-line max-depth
29
+ if (!predicate(value, key)) {
30
+ result[key] = value
31
+ }
32
+ }
33
+ }
34
+ }
35
+
36
+ return result
37
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Creates a shallow clone of `object` excluding the given own enumerable keys.
3
+ * Accepts a single key or an array of keys. Symbol keys are supported.
4
+ * If `object` is nullish, returns an empty object.
5
+ */
6
+ export function omit<T extends object, K extends keyof T>(
7
+ object: T | null | undefined,
8
+ keys: readonly K[] | K,
9
+ ): Omit<T, K> {
10
+ if (object === null || object === undefined) {
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ return {} as any
13
+ }
14
+
15
+ const keysArray = (
16
+ Array.isArray(keys) ? keys : [keys]
17
+ ) as readonly (keyof T)[]
18
+ const keysSet = new Set<keyof T>(keysArray as (keyof T)[])
19
+
20
+ const result: Partial<T> = {}
21
+
22
+ // Copy string/number keys
23
+ for (const key in object) {
24
+ if (Object.hasOwn(object, key) && !keysSet.has(key as keyof T)) {
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ ;(result as any)[key] = object[key as keyof T]
27
+ }
28
+ }
29
+
30
+ // Copy symbol keys
31
+ for (const sym of Object.getOwnPropertySymbols(object)) {
32
+ if (!keysSet.has(sym as keyof T)) {
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ ;(result as any)[sym as unknown as keyof T] = (object as any)[sym]
35
+ }
36
+ }
37
+
38
+ return result as Omit<T, K>
39
+ }
@@ -0,0 +1,12 @@
1
+ export function pick<T extends object, K extends keyof T>(
2
+ obj: T,
3
+ keys: readonly K[],
4
+ ): Pick<T, K> {
5
+ const result = {} as Pick<T, K>
6
+ for (const key of keys) {
7
+ if (Object.hasOwn(obj, key)) {
8
+ result[key] = obj[key]
9
+ }
10
+ }
11
+ return result
12
+ }
@@ -21,7 +21,6 @@ export type TPollerEvents<V extends IPollerResponse = IPollerResponse> = {
21
21
  [k in TPollerEventName]: TPollerEventCallback<V>
22
22
  }
23
23
 
24
- /* @__PURE__ */
25
24
  const INTERVAL = 1500
26
25
 
27
26
  export interface IPollerOptions<U> {
@@ -1,8 +1,3 @@
1
- export function generatePseudoRandomString(length: number): string {
2
- return Array.from({ length }, () => Math.random().toString(36)[2]).join('')
3
- }
4
-
5
- /* @__PURE__ */
6
1
  const TS_QUERY_SPECIAL_CHARS = new Set([
7
2
  '&',
8
3
  '|',
@@ -15,7 +10,6 @@ const TS_QUERY_SPECIAL_CHARS = new Set([
15
10
  '@',
16
11
  ])
17
12
 
18
- /* @__PURE__ */
19
13
  const REGEX_SPECIAL_CHARS = new Set(['|', '(', ')'])
20
14
 
21
15
  export function prepareTsQuery(query: string): string | null {
@@ -1,9 +1,3 @@
1
- export function delay(duration: number): Promise<void> {
2
- return new Promise(resolve => {
3
- setTimeout(resolve, duration)
4
- })
5
- }
6
-
7
1
  export function promiseTimeout<T>(
8
2
  delayAmount: number,
9
3
  valueToReturn: T,
@@ -0,0 +1,3 @@
1
+ export function randomInt(min: number, max: number): number {
2
+ return Math.floor(Math.random() * (max - min + 1) + min)
3
+ }
@@ -0,0 +1,13 @@
1
+ export function shuffleArray<T>(array: T[]): T[] {
2
+ const shuffled = [...array]
3
+ for (let i = shuffled.length - 1; i > 0; i--) {
4
+ const j = Math.floor(Math.random() * (i + 1))
5
+ const temp = shuffled[i]
6
+ const swap = shuffled[j]
7
+ if (temp !== undefined && swap !== undefined) {
8
+ shuffled[i] = swap
9
+ shuffled[j] = temp
10
+ }
11
+ }
12
+ return shuffled
13
+ }
@@ -1,106 +1,3 @@
1
- export function chunk<T>(array: T[], size: number): T[][] {
2
- const chunks: T[][] = []
3
- for (let i = 0; i < array.length; i += size) {
4
- chunks.push(array.slice(i, i + size))
5
- }
6
- return chunks
7
- }
8
-
9
- export function getRandomElementFromArray<T>(array: readonly T[]): T {
10
- if (array.length === 0) {
11
- throw new Error('Cannot get random element from empty array')
12
- }
13
- const element = array[Math.floor(Math.random() * array.length)]
14
- if (element === undefined) {
15
- throw new Error('Array element is undefined')
16
- }
17
- return element
18
- }
19
-
20
- export function shuffleArray<T>(array: T[]): T[] {
21
- const shuffled = [...array]
22
- for (let i = shuffled.length - 1; i > 0; i--) {
23
- const j = Math.floor(Math.random() * (i + 1))
24
- const temp = shuffled[i]
25
- const swap = shuffled[j]
26
- if (temp !== undefined && swap !== undefined) {
27
- shuffled[i] = swap
28
- shuffled[j] = temp
29
- }
30
- }
31
- return shuffled
32
- }
33
-
34
- type Comparator<T> = (a: T, b: T) => boolean
35
-
36
- export function uniqWith<T>(array: T[], comparator: Comparator<T>): T[] {
37
- if (!Array.isArray(array) || typeof comparator !== 'function') {
38
- throw new TypeError(
39
- 'First argument must be an array and second argument must be a function',
40
- )
41
- }
42
-
43
- return array.reduce((unique: T[], current: T) => {
44
- // Check if current item matches any existing item in unique array based on comparator
45
- const hasDuplicate = unique.some(item => comparator(item, current))
46
- // If no duplicate found, add current item to unique array
47
- return hasDuplicate ? unique : [...unique, current]
48
- }, [])
49
- }
50
-
51
- export function compact<T>(
52
- array: (T | null | undefined)[] | null | undefined,
53
- ): Exclude<T, null | undefined>[] {
54
- const length = array === null || array === undefined ? 0 : array.length
55
- let index = -1
56
- let resIndex = 0
57
- const result: Exclude<T, null | undefined>[] = []
58
-
59
- while (index < length) {
60
- index += 1
61
- if (array !== null && array !== undefined) {
62
- const value = array[index]
63
-
64
- if (
65
- value !== null &&
66
- value !== undefined &&
67
- value !== false &&
68
- value !== 0 &&
69
- value !== ''
70
- ) {
71
- result[resIndex] = value as Exclude<T, null | undefined>
72
- resIndex += 1
73
- }
74
- }
75
- }
76
-
77
- return result
78
- }
79
-
80
- export function sumBy<T>(
81
- array: T[] | null | undefined,
82
- iteratee: ((value: T) => number) | keyof T,
83
- ): number {
84
- if (!array || !array.length) {
85
- return 0
86
- }
87
-
88
- const getValue =
89
- typeof iteratee === 'function'
90
- ? iteratee
91
- : (item: T) => item[iteratee] as unknown as number
92
-
93
- let result: number | undefined = undefined
94
- for (const item of array) {
95
- const current = getValue(item)
96
- if (current !== undefined) {
97
- result = result === undefined ? current : result + current
98
- }
99
- }
100
-
101
- return result ?? 0
102
- }
103
-
104
1
  type Iteratee<T> = ((item: T) => unknown) | keyof T
105
2
  type SortOrder = 'asc' | 'desc'
106
3
 
@@ -0,0 +1,23 @@
1
+ export function sumBy<T>(
2
+ array: T[] | null | undefined,
3
+ iteratee: ((value: T) => number) | keyof T,
4
+ ): number {
5
+ if (!array || !array.length) {
6
+ return 0
7
+ }
8
+
9
+ const getValue =
10
+ typeof iteratee === 'function'
11
+ ? iteratee
12
+ : (item: T) => item[iteratee] as unknown as number
13
+
14
+ let result: number | undefined = undefined
15
+ for (const item of array) {
16
+ const current = getValue(item)
17
+ if (current !== undefined) {
18
+ result = result === undefined ? current : result + current
19
+ }
20
+ }
21
+
22
+ return result ?? 0
23
+ }
@@ -0,0 +1,16 @@
1
+ type Comparator<T> = (a: T, b: T) => boolean
2
+
3
+ export function uniqWith<T>(array: T[], comparator: Comparator<T>): T[] {
4
+ if (!Array.isArray(array) || typeof comparator !== 'function') {
5
+ throw new TypeError(
6
+ 'First argument must be an array and second argument must be a function',
7
+ )
8
+ }
9
+
10
+ return array.reduce((unique: T[], current: T) => {
11
+ // Check if current item matches any existing item in unique array based on comparator
12
+ const hasDuplicate = unique.some(item => comparator(item, current))
13
+ // If no duplicate found, add current item to unique array
14
+ return hasDuplicate ? unique : [...unique, current]
15
+ }, [])
16
+ }
@@ -1,4 +1,3 @@
1
- /* @__PURE__ */
2
1
  export const validators = {
3
2
  alpha: (value: string): boolean => /[a-zA-Z]/u.test(value),
4
3
  email: (value: string): boolean => /.+@.+\..+/u.test(value),
@@ -0,0 +1,9 @@
1
+ export function weightedMean(values: number[], weights: number[]): number {
2
+ const sum = values.reduce(
3
+ (acc: number, val: number, i: number) => acc + val * (weights[i] ?? 0),
4
+ 0,
5
+ )
6
+ const sumWeights = weights.reduce((acc: number, val: number) => acc + val, 0)
7
+
8
+ return sum / sumWeights
9
+ }
@@ -1,46 +0,0 @@
1
- export function generateNumbersFromStr(str: string): [number, number] {
2
- let hash = 5381
3
- for (let i = 0; i < str.length; i++) {
4
- // eslint-disable-next-line no-bitwise
5
- hash = (hash << 5) + hash + str.charCodeAt(i)
6
- }
7
-
8
- // Generate two numbers using the hash
9
- // eslint-disable-next-line no-bitwise
10
- const num1 = (hash & 0xff_ff) / 0xff_ff
11
- // eslint-disable-next-line no-bitwise
12
- const num2 = ((hash >> 16) & 0xff_ff) / 0xff_ff
13
-
14
- return [num1, num2]
15
- }
16
-
17
- export function randomInt(min: number, max: number): number {
18
- return Math.floor(Math.random() * (max - min + 1) + min)
19
- }
20
-
21
- export function computeSellingPrice(
22
- buyingPrice: number | string | null = 0,
23
- rate: number | string | null = 0,
24
- ): number {
25
- if (Number.isNaN(Number(buyingPrice)) || Number.isNaN(Number(rate))) {
26
- throw new TypeError('price or rate is NaN')
27
- }
28
-
29
- const sellingPrice = Number(buyingPrice) / (1 - Number(rate))
30
-
31
- return Math.ceil(Math.floor(sellingPrice * 100) / 100)
32
- }
33
-
34
- export function computeMarginRate(
35
- buyingPrice: number | string,
36
- sellingPrice: number | string,
37
- ): number {
38
- const buyingPriceNum = Number(buyingPrice)
39
- const sellingPriceNum = Number(sellingPrice)
40
-
41
- if (Number.isNaN(sellingPriceNum) || Number.isNaN(buyingPriceNum)) {
42
- throw new TypeError('sellingPrice or buyingPrice is NaN')
43
- }
44
-
45
- return Number((1 - buyingPriceNum / sellingPriceNum).toPrecision(10))
46
- }
@@ -1,210 +0,0 @@
1
- import { isNil } from './value-tools.ts'
2
-
3
- export function pick<T extends object, K extends keyof T>(
4
- obj: T,
5
- keys: readonly K[],
6
- ): Pick<T, K> {
7
- const result = {} as Pick<T, K>
8
- for (const key of keys) {
9
- if (Object.hasOwn(obj, key)) {
10
- result[key] = obj[key]
11
- }
12
- }
13
- return result
14
- }
15
-
16
- export function compactObject<T extends object>(obj: T): Partial<T> {
17
- return Object.fromEntries(
18
- Object.entries(obj).filter(([, value]) => !isNil(value)),
19
- ) as Partial<T>
20
- }
21
-
22
- /**
23
- * Creates an object composed of keys generated from the results of running each element of collection through iteratee.
24
- * The corresponding value of each key is the last element responsible for generating the key.
25
- *
26
- * @param collection - The collection to iterate over
27
- * @param iteratee - The iteratee to transform keys. Can be a function or a property name
28
- * @returns Returns the composed aggregate object
29
- */
30
- export function keyBy<T>(
31
- collection: T[] | null | undefined,
32
- iteratee: ((value: T) => string | number) | keyof T,
33
- ): Record<string, T> {
34
- return (
35
- collection?.reduce<Record<string, T>>((acc, item) => {
36
- if (item === undefined || item === null) {
37
- return acc
38
- }
39
-
40
- const key =
41
- typeof iteratee === 'function' ? iteratee(item) : String(item[iteratee])
42
- acc[key] = item
43
- return acc
44
- }, {}) || {}
45
- )
46
- }
47
-
48
- /**
49
- * Creates an object composed of the own enumerable properties of object that predicate doesn't return truthy for.
50
- * The predicate is invoked with two arguments: (value, key).
51
- * If predicate is a string, it omits the property with that key name.
52
- *
53
- * @param object - The source object
54
- * @param predicate - The function invoked per property or a string key to omit
55
- * @returns Returns the new object
56
- */
57
- export function omitBy<T extends object>(
58
- object: T,
59
- predicate: ((value: T[keyof T], key: keyof T) => boolean) | string,
60
- ): Partial<T> {
61
- const result = {} as Partial<T>
62
-
63
- for (const key in object) {
64
- if (Object.hasOwn(object, key)) {
65
- const value = object[key]
66
-
67
- // If predicate is a string, check if key matches
68
- if (typeof predicate === 'string') {
69
- // eslint-disable-next-line max-depth
70
- if (key !== predicate) {
71
- result[key] = value
72
- }
73
- } else if (typeof predicate === 'function') {
74
- // If predicate is a function, use it
75
- // eslint-disable-next-line max-depth
76
- if (!predicate(value, key)) {
77
- result[key] = value
78
- }
79
- }
80
- }
81
- }
82
-
83
- return result
84
- }
85
-
86
- /**
87
- * Creates a shallow clone of `object` excluding the given own enumerable keys.
88
- * Accepts a single key or an array of keys. Symbol keys are supported.
89
- * If `object` is nullish, returns an empty object.
90
- */
91
- export function omit<T extends object, K extends keyof T>(
92
- object: T | null | undefined,
93
- keys: readonly K[] | K,
94
- ): Omit<T, K> {
95
- if (object === null || object === undefined) {
96
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
97
- return {} as any
98
- }
99
-
100
- const keysArray = (
101
- Array.isArray(keys) ? keys : [keys]
102
- ) as readonly (keyof T)[]
103
- const keysSet = new Set<keyof T>(keysArray as (keyof T)[])
104
-
105
- const result: Partial<T> = {}
106
-
107
- // Copy string/number keys
108
- for (const key in object) {
109
- if (Object.hasOwn(object, key) && !keysSet.has(key as keyof T)) {
110
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
111
- ;(result as any)[key] = object[key as keyof T]
112
- }
113
- }
114
-
115
- // Copy symbol keys
116
- for (const sym of Object.getOwnPropertySymbols(object)) {
117
- if (!keysSet.has(sym as keyof T)) {
118
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
- ;(result as any)[sym as unknown as keyof T] = (object as any)[sym]
120
- }
121
- }
122
-
123
- return result as Omit<T, K>
124
- }
125
-
126
- /**
127
- * Drop-in native TypeScript replacement for `lodash-es` `defaultsDeep`.
128
- *
129
- * Behaviour matched (carefully):
130
- * - Mutates and returns the first argument (target).
131
- * - Assigns own and *inherited* enumerable **string-keyed** properties from sources
132
- * to the target only when the target's property is `undefined`.
133
- * - Recursively assigns (deep) when both target and source values are objects/arrays.
134
- * - Does not copy symbol-keyed properties (matches the "string keyed" behaviour).
135
- * - Preserves `null` (i.e. `null` is NOT considered `undefined` so it won't be overwritten).
136
- * - Avoids infinite recursion for circular source structures.
137
- */
138
-
139
- /* eslint-disable @typescript-eslint/no-explicit-any */
140
- type AnyObject = Record<string, any>
141
-
142
- function isObject(value: any): value is AnyObject {
143
- return value !== null && typeof value === 'object'
144
- }
145
-
146
- export function defaultsDeep<T>(
147
- object: T,
148
- ...sources: any[]
149
- ): T extends AnyObject ? T : any {
150
- // Ensure we always return an object reference we can mutate (lodash creates/uses {} when target is falsy)
151
- const target: AnyObject = (
152
- object === null || object === undefined ? {} : object
153
- ) as AnyObject
154
-
155
- // WeakMap to track already-cloned source objects so circular refs won't blow the stack
156
- const seen = new WeakMap<object, object>()
157
-
158
- function applyDefaults(dst: AnyObject, src: any) {
159
- // Only iterate string-keyed enumerable properties (own + inherited) => for...in
160
- for (const key in src) {
161
- if (Object.hasOwn(src, key)) {
162
- const srcVal = src[key]
163
- const dstVal = dst[key]
164
-
165
- // only apply when destination is strictly `undefined` (lodash semantics)
166
- if (dstVal === undefined) {
167
- // eslint-disable-next-line max-depth
168
- if (isObject(srcVal)) {
169
- // If we've already cloned this source object (circular), reuse it
170
- // eslint-disable-next-line max-depth
171
- if (seen.has(srcVal)) {
172
- dst[key] = seen.get(srcVal)
173
- } else {
174
- // Prepare new container (array vs object)
175
- const created = Array.isArray(srcVal)
176
- ? ([] as unknown[])
177
- : ({} as AnyObject)
178
- // remember mapping to handle circular refs
179
- seen.set(srcVal, created)
180
-
181
- // Recursively fill created from srcVal
182
- applyDefaults(created, srcVal)
183
-
184
- // assign the created clone as the default
185
- dst[key] = created
186
- }
187
- } else {
188
- // Primitive or function: assign directly
189
- dst[key] = srcVal
190
- }
191
- } else if (isObject(dstVal) && isObject(srcVal)) {
192
- // destination already has a value (not undefined) and both are objects => recurse
193
- // (do not overwrite existing non-undefined values)
194
- // Note: do not treat arrays specially here; Array.isArray check only used when creating new value
195
- applyDefaults(dstVal, srcVal)
196
- }
197
- // else: destination has a non-undefined primitive or non-object - skip (do not overwrite)
198
- }
199
- }
200
- }
201
-
202
- for (const src of sources) {
203
- if (src !== null && src !== undefined) {
204
- // If source itself has been seen (unlikely across top-level sources), we still traverse it
205
- applyDefaults(target, src)
206
- }
207
- }
208
-
209
- return target as any
210
- }
File without changes