@jthong/util 0.1.0-alpha.0 → 0.1.0-alpha.1

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/README.md CHANGED
@@ -27,11 +27,14 @@ import { debounce } from "@jthong/util/fn";
27
27
  - `capitalize(str)` — 첫 글자 대문자
28
28
  - `camelToKebab(str)` / `kebabToCamel(str)` — 케이스 변환
29
29
  - `truncate(str, max, suffix?)` — 자르고 접미사 붙이기
30
+ - `formatNumber(n, locale?)` — 천 단위 콤마 (`1234567 → "1,234,567"`)
31
+ - `mask(str, { start?, end?, char? })` — 일부 마스킹 (`"01012345678" → "010****5678"`)
30
32
 
31
33
  ### `/array`
32
34
  - `chunk(arr, size)` — n개씩 분할
33
35
  - `unique(arr)` — 중복 제거
34
36
  - `groupBy(arr, keyFn)` — 키별 그룹화
37
+ - `sortBy(arr, keyFn, order?)` — 키 기반 정렬 (asc/desc, 입력 불변)
35
38
  - `range(start, end?, step?)` — 정수 범위
36
39
 
37
40
  ### `/object`
@@ -41,3 +44,7 @@ import { debounce } from "@jthong/util/fn";
41
44
  ### `/fn`
42
45
  - `debounce(fn, ms)` / `throttle(fn, ms)`
43
46
  - `sleep(ms)` — Promise 기반 대기
47
+ - `once(fn)` — 첫 호출 결과를 캐싱, 이후 동일 결과 반환
48
+ - `memoize(fn, keyFn?)` — 인자별 결과 캐싱
49
+ - `retry(fn, { retries?, delay?, backoff?, onError? })` — 지수 백오프 재시도
50
+ - `withTimeout(promise, ms, errorMessage?)` — Promise에 타임아웃 부여
@@ -18,6 +18,16 @@ var groupBy = (arr, keyFn) => {
18
18
  }
19
19
  return result;
20
20
  };
21
+ var sortBy = (arr, keyFn, order = "asc") => {
22
+ const sign = order === "asc" ? 1 : -1;
23
+ return [...arr].sort((a, b) => {
24
+ const ka = keyFn(a);
25
+ const kb = keyFn(b);
26
+ if (ka < kb) return -1 * sign;
27
+ if (ka > kb) return 1 * sign;
28
+ return 0;
29
+ });
30
+ };
21
31
  var range = (start, end, step = 1) => {
22
32
  const [from, to] = end === void 0 ? [0, start] : [start, end];
23
33
  const result = [];
@@ -30,6 +40,7 @@ var range = (start, end, step = 1) => {
30
40
  exports.chunk = chunk;
31
41
  exports.groupBy = groupBy;
32
42
  exports.range = range;
43
+ exports.sortBy = sortBy;
33
44
  exports.unique = unique;
34
45
  //# sourceMappingURL=index.cjs.map
35
46
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/array/index.ts"],"names":[],"mappings":";;;AAAO,IAAM,KAAA,GAAQ,CAAI,GAAA,EAAmB,IAAA,KAAwB;AAClE,EAAA,IAAI,IAAA,IAAQ,CAAA,EAAG,OAAO,EAAC;AACvB,EAAA,MAAM,SAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAA,EAAM;AACzC,IAAA,MAAA,CAAO,KAAK,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,IAAI,CAAC,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,MAAA;AACT;AAEO,IAAM,MAAA,GAAS,CAAI,GAAA,KAA2B,KAAA,CAAM,KAAK,IAAI,GAAA,CAAI,GAAG,CAAC;AAErE,IAAM,OAAA,GAAU,CACrB,GAAA,EACA,KAAA,KACmB;AACnB,EAAA,MAAM,SAAS,EAAC;AAChB,EAAA,KAAA,MAAW,QAAQ,GAAA,EAAK;AACtB,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AACtB,IAAA,CAAC,OAAO,GAAG,CAAA,KAAM,EAAC,EAAG,KAAK,IAAI,CAAA;AAAA,EAChC;AACA,EAAA,OAAO,MAAA;AACT;AAEO,IAAM,KAAA,GAAQ,CAAC,KAAA,EAAe,GAAA,EAAc,OAAO,CAAA,KAAgB;AACxE,EAAA,MAAM,CAAC,IAAA,EAAM,EAAE,CAAA,GAAI,GAAA,KAAQ,MAAA,GAAY,CAAC,CAAA,EAAG,KAAK,CAAA,GAAI,CAAC,KAAA,EAAO,GAAG,CAAA;AAC/D,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,IAAS,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA,GAAI,IAAI,EAAA,GAAK,CAAA,GAAI,EAAA,EAAI,CAAA,IAAK,IAAA,EAAM;AACxD,IAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,EACf;AACA,EAAA,OAAO,MAAA;AACT","file":"index.cjs","sourcesContent":["export const chunk = <T>(arr: readonly T[], size: number): T[][] => {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size));\n }\n return result;\n};\n\nexport const unique = <T>(arr: readonly T[]): T[] => Array.from(new Set(arr));\n\nexport const groupBy = <T, K extends PropertyKey>(\n arr: readonly T[],\n keyFn: (item: T) => K,\n): Record<K, T[]> => {\n const result = {} as Record<K, T[]>;\n for (const item of arr) {\n const key = keyFn(item);\n (result[key] ??= []).push(item);\n }\n return result;\n};\n\nexport const range = (start: number, end?: number, step = 1): number[] => {\n const [from, to] = end === undefined ? [0, start] : [start, end];\n const result: number[] = [];\n for (let i = from; step > 0 ? i < to : i > to; i += step) {\n result.push(i);\n }\n return result;\n};\n"]}
1
+ {"version":3,"sources":["../../src/array/index.ts"],"names":[],"mappings":";;;AAAO,IAAM,KAAA,GAAQ,CAAI,GAAA,EAAmB,IAAA,KAAwB;AAClE,EAAA,IAAI,IAAA,IAAQ,CAAA,EAAG,OAAO,EAAC;AACvB,EAAA,MAAM,SAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAA,EAAM;AACzC,IAAA,MAAA,CAAO,KAAK,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,IAAI,CAAC,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,MAAA;AACT;AAEO,IAAM,MAAA,GAAS,CAAI,GAAA,KAA2B,KAAA,CAAM,KAAK,IAAI,GAAA,CAAI,GAAG,CAAC;AAErE,IAAM,OAAA,GAAU,CACrB,GAAA,EACA,KAAA,KACmB;AACnB,EAAA,MAAM,SAAS,EAAC;AAChB,EAAA,KAAA,MAAW,QAAQ,GAAA,EAAK;AACtB,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AACtB,IAAA,CAAC,OAAO,GAAG,CAAA,KAAM,EAAC,EAAG,KAAK,IAAI,CAAA;AAAA,EAChC;AACA,EAAA,OAAO,MAAA;AACT;AAIO,IAAM,MAAA,GAAS,CACpB,GAAA,EACA,KAAA,EACA,QAAwB,KAAA,KAChB;AACR,EAAA,MAAM,IAAA,GAAO,KAAA,KAAU,KAAA,GAAQ,CAAA,GAAI,EAAA;AACnC,EAAA,OAAO,CAAC,GAAG,GAAG,EAAE,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AAC7B,IAAA,MAAM,EAAA,GAAK,MAAM,CAAC,CAAA;AAClB,IAAA,MAAM,EAAA,GAAK,MAAM,CAAC,CAAA;AAClB,IAAA,IAAI,EAAA,GAAK,EAAA,EAAI,OAAO,EAAA,GAAK,IAAA;AACzB,IAAA,IAAI,EAAA,GAAK,EAAA,EAAI,OAAO,CAAA,GAAI,IAAA;AACxB,IAAA,OAAO,CAAA;AAAA,EACT,CAAC,CAAA;AACH;AAEO,IAAM,KAAA,GAAQ,CAAC,KAAA,EAAe,GAAA,EAAc,OAAO,CAAA,KAAgB;AACxE,EAAA,MAAM,CAAC,IAAA,EAAM,EAAE,CAAA,GAAI,GAAA,KAAQ,MAAA,GAAY,CAAC,CAAA,EAAG,KAAK,CAAA,GAAI,CAAC,KAAA,EAAO,GAAG,CAAA;AAC/D,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,IAAS,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA,GAAI,IAAI,EAAA,GAAK,CAAA,GAAI,EAAA,EAAI,CAAA,IAAK,IAAA,EAAM;AACxD,IAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,EACf;AACA,EAAA,OAAO,MAAA;AACT","file":"index.cjs","sourcesContent":["export const chunk = <T>(arr: readonly T[], size: number): T[][] => {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size));\n }\n return result;\n};\n\nexport const unique = <T>(arr: readonly T[]): T[] => Array.from(new Set(arr));\n\nexport const groupBy = <T, K extends PropertyKey>(\n arr: readonly T[],\n keyFn: (item: T) => K,\n): Record<K, T[]> => {\n const result = {} as Record<K, T[]>;\n for (const item of arr) {\n const key = keyFn(item);\n (result[key] ??= []).push(item);\n }\n return result;\n};\n\ntype Comparable = string | number | bigint | boolean | Date;\n\nexport const sortBy = <T>(\n arr: readonly T[],\n keyFn: (item: T) => Comparable,\n order: \"asc\" | \"desc\" = \"asc\",\n): T[] => {\n const sign = order === \"asc\" ? 1 : -1;\n return [...arr].sort((a, b) => {\n const ka = keyFn(a);\n const kb = keyFn(b);\n if (ka < kb) return -1 * sign;\n if (ka > kb) return 1 * sign;\n return 0;\n });\n};\n\nexport const range = (start: number, end?: number, step = 1): number[] => {\n const [from, to] = end === undefined ? [0, start] : [start, end];\n const result: number[] = [];\n for (let i = from; step > 0 ? i < to : i > to; i += step) {\n result.push(i);\n }\n return result;\n};\n"]}
@@ -1,6 +1,8 @@
1
1
  declare const chunk: <T>(arr: readonly T[], size: number) => T[][];
2
2
  declare const unique: <T>(arr: readonly T[]) => T[];
3
3
  declare const groupBy: <T, K extends PropertyKey>(arr: readonly T[], keyFn: (item: T) => K) => Record<K, T[]>;
4
+ type Comparable = string | number | bigint | boolean | Date;
5
+ declare const sortBy: <T>(arr: readonly T[], keyFn: (item: T) => Comparable, order?: "asc" | "desc") => T[];
4
6
  declare const range: (start: number, end?: number, step?: number) => number[];
5
7
 
6
- export { chunk, groupBy, range, unique };
8
+ export { chunk, groupBy, range, sortBy, unique };
@@ -1,6 +1,8 @@
1
1
  declare const chunk: <T>(arr: readonly T[], size: number) => T[][];
2
2
  declare const unique: <T>(arr: readonly T[]) => T[];
3
3
  declare const groupBy: <T, K extends PropertyKey>(arr: readonly T[], keyFn: (item: T) => K) => Record<K, T[]>;
4
+ type Comparable = string | number | bigint | boolean | Date;
5
+ declare const sortBy: <T>(arr: readonly T[], keyFn: (item: T) => Comparable, order?: "asc" | "desc") => T[];
4
6
  declare const range: (start: number, end?: number, step?: number) => number[];
5
7
 
6
- export { chunk, groupBy, range, unique };
8
+ export { chunk, groupBy, range, sortBy, unique };
@@ -16,6 +16,16 @@ var groupBy = (arr, keyFn) => {
16
16
  }
17
17
  return result;
18
18
  };
19
+ var sortBy = (arr, keyFn, order = "asc") => {
20
+ const sign = order === "asc" ? 1 : -1;
21
+ return [...arr].sort((a, b) => {
22
+ const ka = keyFn(a);
23
+ const kb = keyFn(b);
24
+ if (ka < kb) return -1 * sign;
25
+ if (ka > kb) return 1 * sign;
26
+ return 0;
27
+ });
28
+ };
19
29
  var range = (start, end, step = 1) => {
20
30
  const [from, to] = end === void 0 ? [0, start] : [start, end];
21
31
  const result = [];
@@ -25,6 +35,6 @@ var range = (start, end, step = 1) => {
25
35
  return result;
26
36
  };
27
37
 
28
- export { chunk, groupBy, range, unique };
38
+ export { chunk, groupBy, range, sortBy, unique };
29
39
  //# sourceMappingURL=index.js.map
30
40
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/array/index.ts"],"names":[],"mappings":";AAAO,IAAM,KAAA,GAAQ,CAAI,GAAA,EAAmB,IAAA,KAAwB;AAClE,EAAA,IAAI,IAAA,IAAQ,CAAA,EAAG,OAAO,EAAC;AACvB,EAAA,MAAM,SAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAA,EAAM;AACzC,IAAA,MAAA,CAAO,KAAK,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,IAAI,CAAC,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,MAAA;AACT;AAEO,IAAM,MAAA,GAAS,CAAI,GAAA,KAA2B,KAAA,CAAM,KAAK,IAAI,GAAA,CAAI,GAAG,CAAC;AAErE,IAAM,OAAA,GAAU,CACrB,GAAA,EACA,KAAA,KACmB;AACnB,EAAA,MAAM,SAAS,EAAC;AAChB,EAAA,KAAA,MAAW,QAAQ,GAAA,EAAK;AACtB,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AACtB,IAAA,CAAC,OAAO,GAAG,CAAA,KAAM,EAAC,EAAG,KAAK,IAAI,CAAA;AAAA,EAChC;AACA,EAAA,OAAO,MAAA;AACT;AAEO,IAAM,KAAA,GAAQ,CAAC,KAAA,EAAe,GAAA,EAAc,OAAO,CAAA,KAAgB;AACxE,EAAA,MAAM,CAAC,IAAA,EAAM,EAAE,CAAA,GAAI,GAAA,KAAQ,MAAA,GAAY,CAAC,CAAA,EAAG,KAAK,CAAA,GAAI,CAAC,KAAA,EAAO,GAAG,CAAA;AAC/D,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,IAAS,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA,GAAI,IAAI,EAAA,GAAK,CAAA,GAAI,EAAA,EAAI,CAAA,IAAK,IAAA,EAAM;AACxD,IAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,EACf;AACA,EAAA,OAAO,MAAA;AACT","file":"index.js","sourcesContent":["export const chunk = <T>(arr: readonly T[], size: number): T[][] => {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size));\n }\n return result;\n};\n\nexport const unique = <T>(arr: readonly T[]): T[] => Array.from(new Set(arr));\n\nexport const groupBy = <T, K extends PropertyKey>(\n arr: readonly T[],\n keyFn: (item: T) => K,\n): Record<K, T[]> => {\n const result = {} as Record<K, T[]>;\n for (const item of arr) {\n const key = keyFn(item);\n (result[key] ??= []).push(item);\n }\n return result;\n};\n\nexport const range = (start: number, end?: number, step = 1): number[] => {\n const [from, to] = end === undefined ? [0, start] : [start, end];\n const result: number[] = [];\n for (let i = from; step > 0 ? i < to : i > to; i += step) {\n result.push(i);\n }\n return result;\n};\n"]}
1
+ {"version":3,"sources":["../../src/array/index.ts"],"names":[],"mappings":";AAAO,IAAM,KAAA,GAAQ,CAAI,GAAA,EAAmB,IAAA,KAAwB;AAClE,EAAA,IAAI,IAAA,IAAQ,CAAA,EAAG,OAAO,EAAC;AACvB,EAAA,MAAM,SAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAA,EAAM;AACzC,IAAA,MAAA,CAAO,KAAK,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,IAAI,CAAC,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,MAAA;AACT;AAEO,IAAM,MAAA,GAAS,CAAI,GAAA,KAA2B,KAAA,CAAM,KAAK,IAAI,GAAA,CAAI,GAAG,CAAC;AAErE,IAAM,OAAA,GAAU,CACrB,GAAA,EACA,KAAA,KACmB;AACnB,EAAA,MAAM,SAAS,EAAC;AAChB,EAAA,KAAA,MAAW,QAAQ,GAAA,EAAK;AACtB,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AACtB,IAAA,CAAC,OAAO,GAAG,CAAA,KAAM,EAAC,EAAG,KAAK,IAAI,CAAA;AAAA,EAChC;AACA,EAAA,OAAO,MAAA;AACT;AAIO,IAAM,MAAA,GAAS,CACpB,GAAA,EACA,KAAA,EACA,QAAwB,KAAA,KAChB;AACR,EAAA,MAAM,IAAA,GAAO,KAAA,KAAU,KAAA,GAAQ,CAAA,GAAI,EAAA;AACnC,EAAA,OAAO,CAAC,GAAG,GAAG,EAAE,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AAC7B,IAAA,MAAM,EAAA,GAAK,MAAM,CAAC,CAAA;AAClB,IAAA,MAAM,EAAA,GAAK,MAAM,CAAC,CAAA;AAClB,IAAA,IAAI,EAAA,GAAK,EAAA,EAAI,OAAO,EAAA,GAAK,IAAA;AACzB,IAAA,IAAI,EAAA,GAAK,EAAA,EAAI,OAAO,CAAA,GAAI,IAAA;AACxB,IAAA,OAAO,CAAA;AAAA,EACT,CAAC,CAAA;AACH;AAEO,IAAM,KAAA,GAAQ,CAAC,KAAA,EAAe,GAAA,EAAc,OAAO,CAAA,KAAgB;AACxE,EAAA,MAAM,CAAC,IAAA,EAAM,EAAE,CAAA,GAAI,GAAA,KAAQ,MAAA,GAAY,CAAC,CAAA,EAAG,KAAK,CAAA,GAAI,CAAC,KAAA,EAAO,GAAG,CAAA;AAC/D,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,IAAS,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA,GAAI,IAAI,EAAA,GAAK,CAAA,GAAI,EAAA,EAAI,CAAA,IAAK,IAAA,EAAM;AACxD,IAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,EACf;AACA,EAAA,OAAO,MAAA;AACT","file":"index.js","sourcesContent":["export const chunk = <T>(arr: readonly T[], size: number): T[][] => {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size));\n }\n return result;\n};\n\nexport const unique = <T>(arr: readonly T[]): T[] => Array.from(new Set(arr));\n\nexport const groupBy = <T, K extends PropertyKey>(\n arr: readonly T[],\n keyFn: (item: T) => K,\n): Record<K, T[]> => {\n const result = {} as Record<K, T[]>;\n for (const item of arr) {\n const key = keyFn(item);\n (result[key] ??= []).push(item);\n }\n return result;\n};\n\ntype Comparable = string | number | bigint | boolean | Date;\n\nexport const sortBy = <T>(\n arr: readonly T[],\n keyFn: (item: T) => Comparable,\n order: \"asc\" | \"desc\" = \"asc\",\n): T[] => {\n const sign = order === \"asc\" ? 1 : -1;\n return [...arr].sort((a, b) => {\n const ka = keyFn(a);\n const kb = keyFn(b);\n if (ka < kb) return -1 * sign;\n if (ka > kb) return 1 * sign;\n return 0;\n });\n};\n\nexport const range = (start: number, end?: number, step = 1): number[] => {\n const [from, to] = end === undefined ? [0, start] : [start, end];\n const result: number[] = [];\n for (let i = from; step > 0 ? i < to : i > to; i += step) {\n result.push(i);\n }\n return result;\n};\n"]}
package/dist/fn/index.cjs CHANGED
@@ -19,9 +19,63 @@ var throttle = (fn, ms) => {
19
19
  };
20
20
  };
21
21
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
22
+ var once = (fn) => {
23
+ let called = false;
24
+ let result;
25
+ return (...args) => {
26
+ if (!called) {
27
+ called = true;
28
+ result = fn(...args);
29
+ }
30
+ return result;
31
+ };
32
+ };
33
+ var memoize = (fn, keyFn = (...args) => JSON.stringify(args)) => {
34
+ const cache = /* @__PURE__ */ new Map();
35
+ return (...args) => {
36
+ const key = keyFn(...args);
37
+ const cached = cache.get(key);
38
+ if (cached !== void 0 || cache.has(key)) return cached;
39
+ const result = fn(...args);
40
+ cache.set(key, result);
41
+ return result;
42
+ };
43
+ };
44
+ var retry = async (fn, opts = {}) => {
45
+ const { retries = 3, delay = 100, backoff = 2, onError } = opts;
46
+ let lastError;
47
+ for (let attempt = 0; attempt <= retries; attempt++) {
48
+ try {
49
+ return await fn();
50
+ } catch (err) {
51
+ lastError = err;
52
+ onError?.(err, attempt);
53
+ if (attempt < retries) {
54
+ await sleep(delay * Math.pow(backoff, attempt));
55
+ }
56
+ }
57
+ }
58
+ throw lastError;
59
+ };
60
+ var withTimeout = (promise, ms, errorMessage = "Operation timed out") => {
61
+ let timeoutId;
62
+ const timeout = new Promise((_, reject) => {
63
+ timeoutId = setTimeout(() => reject(new Error(errorMessage)), ms);
64
+ });
65
+ return Promise.race([
66
+ promise.finally(() => {
67
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
68
+ }),
69
+ timeout
70
+ ]);
71
+ };
22
72
 
23
73
  exports.debounce = debounce;
74
+ exports.memoize = memoize;
75
+ exports.once = once;
76
+ exports.retry = retry;
24
77
  exports.sleep = sleep;
25
78
  exports.throttle = throttle;
79
+ exports.withTimeout = withTimeout;
26
80
  //# sourceMappingURL=index.cjs.map
27
81
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fn/index.ts"],"names":[],"mappings":";;;AAAO,IAAM,QAAA,GAAW,CACtB,EAAA,EACA,EAAA,KAC8B;AAC9B,EAAA,IAAI,KAAA;AACJ,EAAA,OAAO,IAAI,IAAA,KAAe;AACxB,IAAA,IAAI,KAAA,KAAU,MAAA,EAAW,YAAA,CAAa,KAAK,CAAA;AAC3C,IAAA,KAAA,GAAQ,WAAW,MAAM,EAAA,CAAG,GAAG,IAAI,GAAG,EAAE,CAAA;AAAA,EAC1C,CAAA;AACF;AAEO,IAAM,QAAA,GAAW,CACtB,EAAA,EACA,EAAA,KAC8B;AAC9B,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,OAAO,IAAI,IAAA,KAAe;AACxB,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,GAAA,GAAM,QAAQ,EAAA,EAAI;AACpB,MAAA,IAAA,GAAO,GAAA;AACP,MAAA,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,IACZ;AAAA,EACF,CAAA;AACF;AAEO,IAAM,KAAA,GAAQ,CAAC,EAAA,KACpB,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC","file":"index.cjs","sourcesContent":["export const debounce = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: Args) => {\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), ms);\n };\n};\n\nexport const throttle = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let last = 0;\n return (...args: Args) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n };\n};\n\nexport const sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n"]}
1
+ {"version":3,"sources":["../../src/fn/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export const debounce = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: Args) => {\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), ms);\n };\n};\n\nexport const throttle = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let last = 0;\n return (...args: Args) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n };\n};\n\nexport const sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport const once = <Args extends unknown[], R>(\n fn: (...args: Args) => R,\n): ((...args: Args) => R) => {\n let called = false;\n let result: R;\n return (...args: Args): R => {\n if (!called) {\n called = true;\n result = fn(...args);\n }\n return result;\n };\n};\n\nexport const memoize = <Args extends unknown[], R>(\n fn: (...args: Args) => R,\n keyFn: (...args: Args) => string = (...args) => JSON.stringify(args),\n): ((...args: Args) => R) => {\n const cache = new Map<string, R>();\n return (...args: Args): R => {\n const key = keyFn(...args);\n const cached = cache.get(key);\n if (cached !== undefined || cache.has(key)) return cached as R;\n const result = fn(...args);\n cache.set(key, result);\n return result;\n };\n};\n\nexport interface RetryOptions {\n retries?: number;\n delay?: number;\n backoff?: number;\n onError?: (error: unknown, attempt: number) => void;\n}\n\nexport const retry = async <T>(\n fn: () => Promise<T> | T,\n opts: RetryOptions = {},\n): Promise<T> => {\n const { retries = 3, delay = 100, backoff = 2, onError } = opts;\n let lastError: unknown;\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n onError?.(err, attempt);\n if (attempt < retries) {\n await sleep(delay * Math.pow(backoff, attempt));\n }\n }\n }\n throw lastError;\n};\n\nexport const withTimeout = <T>(\n promise: Promise<T>,\n ms: number,\n errorMessage = \"Operation timed out\",\n): Promise<T> => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(errorMessage)), ms);\n });\n return Promise.race([\n promise.finally(() => {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n }),\n timeout,\n ]);\n};\n"]}
@@ -1,5 +1,15 @@
1
1
  declare const debounce: <Args extends unknown[]>(fn: (...args: Args) => void, ms: number) => ((...args: Args) => void);
2
2
  declare const throttle: <Args extends unknown[]>(fn: (...args: Args) => void, ms: number) => ((...args: Args) => void);
3
3
  declare const sleep: (ms: number) => Promise<void>;
4
+ declare const once: <Args extends unknown[], R>(fn: (...args: Args) => R) => ((...args: Args) => R);
5
+ declare const memoize: <Args extends unknown[], R>(fn: (...args: Args) => R, keyFn?: (...args: Args) => string) => ((...args: Args) => R);
6
+ interface RetryOptions {
7
+ retries?: number;
8
+ delay?: number;
9
+ backoff?: number;
10
+ onError?: (error: unknown, attempt: number) => void;
11
+ }
12
+ declare const retry: <T>(fn: () => Promise<T> | T, opts?: RetryOptions) => Promise<T>;
13
+ declare const withTimeout: <T>(promise: Promise<T>, ms: number, errorMessage?: string) => Promise<T>;
4
14
 
5
- export { debounce, sleep, throttle };
15
+ export { type RetryOptions, debounce, memoize, once, retry, sleep, throttle, withTimeout };
@@ -1,5 +1,15 @@
1
1
  declare const debounce: <Args extends unknown[]>(fn: (...args: Args) => void, ms: number) => ((...args: Args) => void);
2
2
  declare const throttle: <Args extends unknown[]>(fn: (...args: Args) => void, ms: number) => ((...args: Args) => void);
3
3
  declare const sleep: (ms: number) => Promise<void>;
4
+ declare const once: <Args extends unknown[], R>(fn: (...args: Args) => R) => ((...args: Args) => R);
5
+ declare const memoize: <Args extends unknown[], R>(fn: (...args: Args) => R, keyFn?: (...args: Args) => string) => ((...args: Args) => R);
6
+ interface RetryOptions {
7
+ retries?: number;
8
+ delay?: number;
9
+ backoff?: number;
10
+ onError?: (error: unknown, attempt: number) => void;
11
+ }
12
+ declare const retry: <T>(fn: () => Promise<T> | T, opts?: RetryOptions) => Promise<T>;
13
+ declare const withTimeout: <T>(promise: Promise<T>, ms: number, errorMessage?: string) => Promise<T>;
4
14
 
5
- export { debounce, sleep, throttle };
15
+ export { type RetryOptions, debounce, memoize, once, retry, sleep, throttle, withTimeout };
package/dist/fn/index.js CHANGED
@@ -17,7 +17,57 @@ var throttle = (fn, ms) => {
17
17
  };
18
18
  };
19
19
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
20
+ var once = (fn) => {
21
+ let called = false;
22
+ let result;
23
+ return (...args) => {
24
+ if (!called) {
25
+ called = true;
26
+ result = fn(...args);
27
+ }
28
+ return result;
29
+ };
30
+ };
31
+ var memoize = (fn, keyFn = (...args) => JSON.stringify(args)) => {
32
+ const cache = /* @__PURE__ */ new Map();
33
+ return (...args) => {
34
+ const key = keyFn(...args);
35
+ const cached = cache.get(key);
36
+ if (cached !== void 0 || cache.has(key)) return cached;
37
+ const result = fn(...args);
38
+ cache.set(key, result);
39
+ return result;
40
+ };
41
+ };
42
+ var retry = async (fn, opts = {}) => {
43
+ const { retries = 3, delay = 100, backoff = 2, onError } = opts;
44
+ let lastError;
45
+ for (let attempt = 0; attempt <= retries; attempt++) {
46
+ try {
47
+ return await fn();
48
+ } catch (err) {
49
+ lastError = err;
50
+ onError?.(err, attempt);
51
+ if (attempt < retries) {
52
+ await sleep(delay * Math.pow(backoff, attempt));
53
+ }
54
+ }
55
+ }
56
+ throw lastError;
57
+ };
58
+ var withTimeout = (promise, ms, errorMessage = "Operation timed out") => {
59
+ let timeoutId;
60
+ const timeout = new Promise((_, reject) => {
61
+ timeoutId = setTimeout(() => reject(new Error(errorMessage)), ms);
62
+ });
63
+ return Promise.race([
64
+ promise.finally(() => {
65
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
66
+ }),
67
+ timeout
68
+ ]);
69
+ };
20
70
 
21
- export { debounce, sleep, throttle };
71
+ export { debounce, memoize, once, retry, sleep, throttle, withTimeout };
22
72
  //# sourceMappingURL=index.js.map
23
73
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fn/index.ts"],"names":[],"mappings":";AAAO,IAAM,QAAA,GAAW,CACtB,EAAA,EACA,EAAA,KAC8B;AAC9B,EAAA,IAAI,KAAA;AACJ,EAAA,OAAO,IAAI,IAAA,KAAe;AACxB,IAAA,IAAI,KAAA,KAAU,MAAA,EAAW,YAAA,CAAa,KAAK,CAAA;AAC3C,IAAA,KAAA,GAAQ,WAAW,MAAM,EAAA,CAAG,GAAG,IAAI,GAAG,EAAE,CAAA;AAAA,EAC1C,CAAA;AACF;AAEO,IAAM,QAAA,GAAW,CACtB,EAAA,EACA,EAAA,KAC8B;AAC9B,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,OAAO,IAAI,IAAA,KAAe;AACxB,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,GAAA,GAAM,QAAQ,EAAA,EAAI;AACpB,MAAA,IAAA,GAAO,GAAA;AACP,MAAA,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,IACZ;AAAA,EACF,CAAA;AACF;AAEO,IAAM,KAAA,GAAQ,CAAC,EAAA,KACpB,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC","file":"index.js","sourcesContent":["export const debounce = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: Args) => {\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), ms);\n };\n};\n\nexport const throttle = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let last = 0;\n return (...args: Args) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n };\n};\n\nexport const sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n"]}
1
+ {"version":3,"sources":["../../src/fn/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const debounce = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: Args) => {\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), ms);\n };\n};\n\nexport const throttle = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let last = 0;\n return (...args: Args) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n };\n};\n\nexport const sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport const once = <Args extends unknown[], R>(\n fn: (...args: Args) => R,\n): ((...args: Args) => R) => {\n let called = false;\n let result: R;\n return (...args: Args): R => {\n if (!called) {\n called = true;\n result = fn(...args);\n }\n return result;\n };\n};\n\nexport const memoize = <Args extends unknown[], R>(\n fn: (...args: Args) => R,\n keyFn: (...args: Args) => string = (...args) => JSON.stringify(args),\n): ((...args: Args) => R) => {\n const cache = new Map<string, R>();\n return (...args: Args): R => {\n const key = keyFn(...args);\n const cached = cache.get(key);\n if (cached !== undefined || cache.has(key)) return cached as R;\n const result = fn(...args);\n cache.set(key, result);\n return result;\n };\n};\n\nexport interface RetryOptions {\n retries?: number;\n delay?: number;\n backoff?: number;\n onError?: (error: unknown, attempt: number) => void;\n}\n\nexport const retry = async <T>(\n fn: () => Promise<T> | T,\n opts: RetryOptions = {},\n): Promise<T> => {\n const { retries = 3, delay = 100, backoff = 2, onError } = opts;\n let lastError: unknown;\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n onError?.(err, attempt);\n if (attempt < retries) {\n await sleep(delay * Math.pow(backoff, attempt));\n }\n }\n }\n throw lastError;\n};\n\nexport const withTimeout = <T>(\n promise: Promise<T>,\n ms: number,\n errorMessage = \"Operation timed out\",\n): Promise<T> => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(errorMessage)), ms);\n });\n return Promise.race([\n promise.finally(() => {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n }),\n timeout,\n ]);\n};\n"]}
package/dist/index.cjs CHANGED
@@ -5,6 +5,15 @@ var capitalize = (str) => str.length === 0 ? str : str[0].toUpperCase() + str.sl
5
5
  var camelToKebab = (str) => str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, "");
6
6
  var kebabToCamel = (str) => str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
7
7
  var truncate = (str, max, suffix = "...") => str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;
8
+ var formatNumber = (n, locale = "en-US") => new Intl.NumberFormat(locale).format(n);
9
+ var mask = (str, opts = {}) => {
10
+ const start = Math.max(0, opts.start ?? 1);
11
+ const end = Math.max(0, opts.end ?? 0);
12
+ const char = opts.char ?? "*";
13
+ if (str.length <= start + end) return str;
14
+ const masked = char.repeat(str.length - start - end);
15
+ return str.slice(0, start) + masked + str.slice(str.length - end);
16
+ };
8
17
 
9
18
  // src/array/index.ts
10
19
  var chunk = (arr, size) => {
@@ -24,6 +33,16 @@ var groupBy = (arr, keyFn) => {
24
33
  }
25
34
  return result;
26
35
  };
36
+ var sortBy = (arr, keyFn, order = "asc") => {
37
+ const sign = order === "asc" ? 1 : -1;
38
+ return [...arr].sort((a, b) => {
39
+ const ka = keyFn(a);
40
+ const kb = keyFn(b);
41
+ if (ka < kb) return -1 * sign;
42
+ if (ka > kb) return 1 * sign;
43
+ return 0;
44
+ });
45
+ };
27
46
  var range = (start, end, step = 1) => {
28
47
  const [from, to] = end === void 0 ? [0, start] : [start, end];
29
48
  const result = [];
@@ -73,20 +92,77 @@ var throttle = (fn, ms) => {
73
92
  };
74
93
  };
75
94
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
95
+ var once = (fn) => {
96
+ let called = false;
97
+ let result;
98
+ return (...args) => {
99
+ if (!called) {
100
+ called = true;
101
+ result = fn(...args);
102
+ }
103
+ return result;
104
+ };
105
+ };
106
+ var memoize = (fn, keyFn = (...args) => JSON.stringify(args)) => {
107
+ const cache = /* @__PURE__ */ new Map();
108
+ return (...args) => {
109
+ const key = keyFn(...args);
110
+ const cached = cache.get(key);
111
+ if (cached !== void 0 || cache.has(key)) return cached;
112
+ const result = fn(...args);
113
+ cache.set(key, result);
114
+ return result;
115
+ };
116
+ };
117
+ var retry = async (fn, opts = {}) => {
118
+ const { retries = 3, delay = 100, backoff = 2, onError } = opts;
119
+ let lastError;
120
+ for (let attempt = 0; attempt <= retries; attempt++) {
121
+ try {
122
+ return await fn();
123
+ } catch (err) {
124
+ lastError = err;
125
+ onError?.(err, attempt);
126
+ if (attempt < retries) {
127
+ await sleep(delay * Math.pow(backoff, attempt));
128
+ }
129
+ }
130
+ }
131
+ throw lastError;
132
+ };
133
+ var withTimeout = (promise, ms, errorMessage = "Operation timed out") => {
134
+ let timeoutId;
135
+ const timeout = new Promise((_, reject) => {
136
+ timeoutId = setTimeout(() => reject(new Error(errorMessage)), ms);
137
+ });
138
+ return Promise.race([
139
+ promise.finally(() => {
140
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
141
+ }),
142
+ timeout
143
+ ]);
144
+ };
76
145
 
77
146
  exports.camelToKebab = camelToKebab;
78
147
  exports.capitalize = capitalize;
79
148
  exports.chunk = chunk;
80
149
  exports.debounce = debounce;
150
+ exports.formatNumber = formatNumber;
81
151
  exports.groupBy = groupBy;
82
152
  exports.isPlainObject = isPlainObject;
83
153
  exports.kebabToCamel = kebabToCamel;
154
+ exports.mask = mask;
155
+ exports.memoize = memoize;
84
156
  exports.omit = omit;
157
+ exports.once = once;
85
158
  exports.pick = pick;
86
159
  exports.range = range;
160
+ exports.retry = retry;
87
161
  exports.sleep = sleep;
162
+ exports.sortBy = sortBy;
88
163
  exports.throttle = throttle;
89
164
  exports.truncate = truncate;
90
165
  exports.unique = unique;
166
+ exports.withTimeout = withTimeout;
91
167
  //# sourceMappingURL=index.cjs.map
92
168
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/string/index.ts","../src/array/index.ts","../src/object/index.ts","../src/fn/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export const capitalize = (str: string): string =>\n str.length === 0 ? str : str[0]!.toUpperCase() + str.slice(1);\n\nexport const camelToKebab = (str: string): string =>\n str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, \"\");\n\nexport const kebabToCamel = (str: string): string =>\n str.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n\nexport const truncate = (str: string, max: number, suffix = \"...\"): string =>\n str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;\n","export const chunk = <T>(arr: readonly T[], size: number): T[][] => {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size));\n }\n return result;\n};\n\nexport const unique = <T>(arr: readonly T[]): T[] => Array.from(new Set(arr));\n\nexport const groupBy = <T, K extends PropertyKey>(\n arr: readonly T[],\n keyFn: (item: T) => K,\n): Record<K, T[]> => {\n const result = {} as Record<K, T[]>;\n for (const item of arr) {\n const key = keyFn(item);\n (result[key] ??= []).push(item);\n }\n return result;\n};\n\nexport const range = (start: number, end?: number, step = 1): number[] => {\n const [from, to] = end === undefined ? [0, start] : [start, end];\n const result: number[] = [];\n for (let i = from; step > 0 ? i < to : i > to; i += step) {\n result.push(i);\n }\n return result;\n};\n","export const pick = <T extends object, K extends keyof T>(\n obj: T,\n keys: readonly K[],\n): Pick<T, K> => {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n if (key in obj) result[key] = obj[key];\n }\n return result;\n};\n\nexport const omit = <T extends object, K extends keyof T>(\n obj: T,\n keys: readonly K[],\n): Omit<T, K> => {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result;\n};\n\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n};\n","export const debounce = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: Args) => {\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), ms);\n };\n};\n\nexport const throttle = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let last = 0;\n return (...args: Args) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n };\n};\n\nexport const sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n"]}
1
+ {"version":3,"sources":["../src/string/index.ts","../src/array/index.ts","../src/object/index.ts","../src/fn/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export const capitalize = (str: string): string =>\n str.length === 0 ? str : str[0]!.toUpperCase() + str.slice(1);\n\nexport const camelToKebab = (str: string): string =>\n str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, \"\");\n\nexport const kebabToCamel = (str: string): string =>\n str.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n\nexport const truncate = (str: string, max: number, suffix = \"...\"): string =>\n str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;\n\nexport const formatNumber = (n: number, locale = \"en-US\"): string =>\n new Intl.NumberFormat(locale).format(n);\n\nexport interface MaskOptions {\n start?: number;\n end?: number;\n char?: string;\n}\n\nexport const mask = (str: string, opts: MaskOptions = {}): string => {\n const start = Math.max(0, opts.start ?? 1);\n const end = Math.max(0, opts.end ?? 0);\n const char = opts.char ?? \"*\";\n if (str.length <= start + end) return str;\n const masked = char.repeat(str.length - start - end);\n return str.slice(0, start) + masked + str.slice(str.length - end);\n};\n","export const chunk = <T>(arr: readonly T[], size: number): T[][] => {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size));\n }\n return result;\n};\n\nexport const unique = <T>(arr: readonly T[]): T[] => Array.from(new Set(arr));\n\nexport const groupBy = <T, K extends PropertyKey>(\n arr: readonly T[],\n keyFn: (item: T) => K,\n): Record<K, T[]> => {\n const result = {} as Record<K, T[]>;\n for (const item of arr) {\n const key = keyFn(item);\n (result[key] ??= []).push(item);\n }\n return result;\n};\n\ntype Comparable = string | number | bigint | boolean | Date;\n\nexport const sortBy = <T>(\n arr: readonly T[],\n keyFn: (item: T) => Comparable,\n order: \"asc\" | \"desc\" = \"asc\",\n): T[] => {\n const sign = order === \"asc\" ? 1 : -1;\n return [...arr].sort((a, b) => {\n const ka = keyFn(a);\n const kb = keyFn(b);\n if (ka < kb) return -1 * sign;\n if (ka > kb) return 1 * sign;\n return 0;\n });\n};\n\nexport const range = (start: number, end?: number, step = 1): number[] => {\n const [from, to] = end === undefined ? [0, start] : [start, end];\n const result: number[] = [];\n for (let i = from; step > 0 ? i < to : i > to; i += step) {\n result.push(i);\n }\n return result;\n};\n","export const pick = <T extends object, K extends keyof T>(\n obj: T,\n keys: readonly K[],\n): Pick<T, K> => {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n if (key in obj) result[key] = obj[key];\n }\n return result;\n};\n\nexport const omit = <T extends object, K extends keyof T>(\n obj: T,\n keys: readonly K[],\n): Omit<T, K> => {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result;\n};\n\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n};\n","export const debounce = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: Args) => {\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), ms);\n };\n};\n\nexport const throttle = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let last = 0;\n return (...args: Args) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n };\n};\n\nexport const sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport const once = <Args extends unknown[], R>(\n fn: (...args: Args) => R,\n): ((...args: Args) => R) => {\n let called = false;\n let result: R;\n return (...args: Args): R => {\n if (!called) {\n called = true;\n result = fn(...args);\n }\n return result;\n };\n};\n\nexport const memoize = <Args extends unknown[], R>(\n fn: (...args: Args) => R,\n keyFn: (...args: Args) => string = (...args) => JSON.stringify(args),\n): ((...args: Args) => R) => {\n const cache = new Map<string, R>();\n return (...args: Args): R => {\n const key = keyFn(...args);\n const cached = cache.get(key);\n if (cached !== undefined || cache.has(key)) return cached as R;\n const result = fn(...args);\n cache.set(key, result);\n return result;\n };\n};\n\nexport interface RetryOptions {\n retries?: number;\n delay?: number;\n backoff?: number;\n onError?: (error: unknown, attempt: number) => void;\n}\n\nexport const retry = async <T>(\n fn: () => Promise<T> | T,\n opts: RetryOptions = {},\n): Promise<T> => {\n const { retries = 3, delay = 100, backoff = 2, onError } = opts;\n let lastError: unknown;\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n onError?.(err, attempt);\n if (attempt < retries) {\n await sleep(delay * Math.pow(backoff, attempt));\n }\n }\n }\n throw lastError;\n};\n\nexport const withTimeout = <T>(\n promise: Promise<T>,\n ms: number,\n errorMessage = \"Operation timed out\",\n): Promise<T> => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(errorMessage)), ms);\n });\n return Promise.race([\n promise.finally(() => {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n }),\n timeout,\n ]);\n};\n"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { camelToKebab, capitalize, kebabToCamel, truncate } from './string/index.cjs';
2
- export { chunk, groupBy, range, unique } from './array/index.cjs';
1
+ export { MaskOptions, camelToKebab, capitalize, formatNumber, kebabToCamel, mask, truncate } from './string/index.cjs';
2
+ export { chunk, groupBy, range, sortBy, unique } from './array/index.cjs';
3
3
  export { isPlainObject, omit, pick } from './object/index.cjs';
4
- export { debounce, sleep, throttle } from './fn/index.cjs';
4
+ export { RetryOptions, debounce, memoize, once, retry, sleep, throttle, withTimeout } from './fn/index.cjs';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { camelToKebab, capitalize, kebabToCamel, truncate } from './string/index.js';
2
- export { chunk, groupBy, range, unique } from './array/index.js';
1
+ export { MaskOptions, camelToKebab, capitalize, formatNumber, kebabToCamel, mask, truncate } from './string/index.js';
2
+ export { chunk, groupBy, range, sortBy, unique } from './array/index.js';
3
3
  export { isPlainObject, omit, pick } from './object/index.js';
4
- export { debounce, sleep, throttle } from './fn/index.js';
4
+ export { RetryOptions, debounce, memoize, once, retry, sleep, throttle, withTimeout } from './fn/index.js';
package/dist/index.js CHANGED
@@ -3,6 +3,15 @@ var capitalize = (str) => str.length === 0 ? str : str[0].toUpperCase() + str.sl
3
3
  var camelToKebab = (str) => str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, "");
4
4
  var kebabToCamel = (str) => str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
5
5
  var truncate = (str, max, suffix = "...") => str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;
6
+ var formatNumber = (n, locale = "en-US") => new Intl.NumberFormat(locale).format(n);
7
+ var mask = (str, opts = {}) => {
8
+ const start = Math.max(0, opts.start ?? 1);
9
+ const end = Math.max(0, opts.end ?? 0);
10
+ const char = opts.char ?? "*";
11
+ if (str.length <= start + end) return str;
12
+ const masked = char.repeat(str.length - start - end);
13
+ return str.slice(0, start) + masked + str.slice(str.length - end);
14
+ };
6
15
 
7
16
  // src/array/index.ts
8
17
  var chunk = (arr, size) => {
@@ -22,6 +31,16 @@ var groupBy = (arr, keyFn) => {
22
31
  }
23
32
  return result;
24
33
  };
34
+ var sortBy = (arr, keyFn, order = "asc") => {
35
+ const sign = order === "asc" ? 1 : -1;
36
+ return [...arr].sort((a, b) => {
37
+ const ka = keyFn(a);
38
+ const kb = keyFn(b);
39
+ if (ka < kb) return -1 * sign;
40
+ if (ka > kb) return 1 * sign;
41
+ return 0;
42
+ });
43
+ };
25
44
  var range = (start, end, step = 1) => {
26
45
  const [from, to] = end === void 0 ? [0, start] : [start, end];
27
46
  const result = [];
@@ -71,7 +90,57 @@ var throttle = (fn, ms) => {
71
90
  };
72
91
  };
73
92
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
93
+ var once = (fn) => {
94
+ let called = false;
95
+ let result;
96
+ return (...args) => {
97
+ if (!called) {
98
+ called = true;
99
+ result = fn(...args);
100
+ }
101
+ return result;
102
+ };
103
+ };
104
+ var memoize = (fn, keyFn = (...args) => JSON.stringify(args)) => {
105
+ const cache = /* @__PURE__ */ new Map();
106
+ return (...args) => {
107
+ const key = keyFn(...args);
108
+ const cached = cache.get(key);
109
+ if (cached !== void 0 || cache.has(key)) return cached;
110
+ const result = fn(...args);
111
+ cache.set(key, result);
112
+ return result;
113
+ };
114
+ };
115
+ var retry = async (fn, opts = {}) => {
116
+ const { retries = 3, delay = 100, backoff = 2, onError } = opts;
117
+ let lastError;
118
+ for (let attempt = 0; attempt <= retries; attempt++) {
119
+ try {
120
+ return await fn();
121
+ } catch (err) {
122
+ lastError = err;
123
+ onError?.(err, attempt);
124
+ if (attempt < retries) {
125
+ await sleep(delay * Math.pow(backoff, attempt));
126
+ }
127
+ }
128
+ }
129
+ throw lastError;
130
+ };
131
+ var withTimeout = (promise, ms, errorMessage = "Operation timed out") => {
132
+ let timeoutId;
133
+ const timeout = new Promise((_, reject) => {
134
+ timeoutId = setTimeout(() => reject(new Error(errorMessage)), ms);
135
+ });
136
+ return Promise.race([
137
+ promise.finally(() => {
138
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
139
+ }),
140
+ timeout
141
+ ]);
142
+ };
74
143
 
75
- export { camelToKebab, capitalize, chunk, debounce, groupBy, isPlainObject, kebabToCamel, omit, pick, range, sleep, throttle, truncate, unique };
144
+ export { camelToKebab, capitalize, chunk, debounce, formatNumber, groupBy, isPlainObject, kebabToCamel, mask, memoize, omit, once, pick, range, retry, sleep, sortBy, throttle, truncate, unique, withTimeout };
76
145
  //# sourceMappingURL=index.js.map
77
146
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/string/index.ts","../src/array/index.ts","../src/object/index.ts","../src/fn/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const capitalize = (str: string): string =>\n str.length === 0 ? str : str[0]!.toUpperCase() + str.slice(1);\n\nexport const camelToKebab = (str: string): string =>\n str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, \"\");\n\nexport const kebabToCamel = (str: string): string =>\n str.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n\nexport const truncate = (str: string, max: number, suffix = \"...\"): string =>\n str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;\n","export const chunk = <T>(arr: readonly T[], size: number): T[][] => {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size));\n }\n return result;\n};\n\nexport const unique = <T>(arr: readonly T[]): T[] => Array.from(new Set(arr));\n\nexport const groupBy = <T, K extends PropertyKey>(\n arr: readonly T[],\n keyFn: (item: T) => K,\n): Record<K, T[]> => {\n const result = {} as Record<K, T[]>;\n for (const item of arr) {\n const key = keyFn(item);\n (result[key] ??= []).push(item);\n }\n return result;\n};\n\nexport const range = (start: number, end?: number, step = 1): number[] => {\n const [from, to] = end === undefined ? [0, start] : [start, end];\n const result: number[] = [];\n for (let i = from; step > 0 ? i < to : i > to; i += step) {\n result.push(i);\n }\n return result;\n};\n","export const pick = <T extends object, K extends keyof T>(\n obj: T,\n keys: readonly K[],\n): Pick<T, K> => {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n if (key in obj) result[key] = obj[key];\n }\n return result;\n};\n\nexport const omit = <T extends object, K extends keyof T>(\n obj: T,\n keys: readonly K[],\n): Omit<T, K> => {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result;\n};\n\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n};\n","export const debounce = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: Args) => {\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), ms);\n };\n};\n\nexport const throttle = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let last = 0;\n return (...args: Args) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n };\n};\n\nexport const sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n"]}
1
+ {"version":3,"sources":["../src/string/index.ts","../src/array/index.ts","../src/object/index.ts","../src/fn/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const capitalize = (str: string): string =>\n str.length === 0 ? str : str[0]!.toUpperCase() + str.slice(1);\n\nexport const camelToKebab = (str: string): string =>\n str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, \"\");\n\nexport const kebabToCamel = (str: string): string =>\n str.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n\nexport const truncate = (str: string, max: number, suffix = \"...\"): string =>\n str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;\n\nexport const formatNumber = (n: number, locale = \"en-US\"): string =>\n new Intl.NumberFormat(locale).format(n);\n\nexport interface MaskOptions {\n start?: number;\n end?: number;\n char?: string;\n}\n\nexport const mask = (str: string, opts: MaskOptions = {}): string => {\n const start = Math.max(0, opts.start ?? 1);\n const end = Math.max(0, opts.end ?? 0);\n const char = opts.char ?? \"*\";\n if (str.length <= start + end) return str;\n const masked = char.repeat(str.length - start - end);\n return str.slice(0, start) + masked + str.slice(str.length - end);\n};\n","export const chunk = <T>(arr: readonly T[], size: number): T[][] => {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size));\n }\n return result;\n};\n\nexport const unique = <T>(arr: readonly T[]): T[] => Array.from(new Set(arr));\n\nexport const groupBy = <T, K extends PropertyKey>(\n arr: readonly T[],\n keyFn: (item: T) => K,\n): Record<K, T[]> => {\n const result = {} as Record<K, T[]>;\n for (const item of arr) {\n const key = keyFn(item);\n (result[key] ??= []).push(item);\n }\n return result;\n};\n\ntype Comparable = string | number | bigint | boolean | Date;\n\nexport const sortBy = <T>(\n arr: readonly T[],\n keyFn: (item: T) => Comparable,\n order: \"asc\" | \"desc\" = \"asc\",\n): T[] => {\n const sign = order === \"asc\" ? 1 : -1;\n return [...arr].sort((a, b) => {\n const ka = keyFn(a);\n const kb = keyFn(b);\n if (ka < kb) return -1 * sign;\n if (ka > kb) return 1 * sign;\n return 0;\n });\n};\n\nexport const range = (start: number, end?: number, step = 1): number[] => {\n const [from, to] = end === undefined ? [0, start] : [start, end];\n const result: number[] = [];\n for (let i = from; step > 0 ? i < to : i > to; i += step) {\n result.push(i);\n }\n return result;\n};\n","export const pick = <T extends object, K extends keyof T>(\n obj: T,\n keys: readonly K[],\n): Pick<T, K> => {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n if (key in obj) result[key] = obj[key];\n }\n return result;\n};\n\nexport const omit = <T extends object, K extends keyof T>(\n obj: T,\n keys: readonly K[],\n): Omit<T, K> => {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result;\n};\n\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n};\n","export const debounce = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: Args) => {\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), ms);\n };\n};\n\nexport const throttle = <Args extends unknown[]>(\n fn: (...args: Args) => void,\n ms: number,\n): ((...args: Args) => void) => {\n let last = 0;\n return (...args: Args) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n };\n};\n\nexport const sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport const once = <Args extends unknown[], R>(\n fn: (...args: Args) => R,\n): ((...args: Args) => R) => {\n let called = false;\n let result: R;\n return (...args: Args): R => {\n if (!called) {\n called = true;\n result = fn(...args);\n }\n return result;\n };\n};\n\nexport const memoize = <Args extends unknown[], R>(\n fn: (...args: Args) => R,\n keyFn: (...args: Args) => string = (...args) => JSON.stringify(args),\n): ((...args: Args) => R) => {\n const cache = new Map<string, R>();\n return (...args: Args): R => {\n const key = keyFn(...args);\n const cached = cache.get(key);\n if (cached !== undefined || cache.has(key)) return cached as R;\n const result = fn(...args);\n cache.set(key, result);\n return result;\n };\n};\n\nexport interface RetryOptions {\n retries?: number;\n delay?: number;\n backoff?: number;\n onError?: (error: unknown, attempt: number) => void;\n}\n\nexport const retry = async <T>(\n fn: () => Promise<T> | T,\n opts: RetryOptions = {},\n): Promise<T> => {\n const { retries = 3, delay = 100, backoff = 2, onError } = opts;\n let lastError: unknown;\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n onError?.(err, attempt);\n if (attempt < retries) {\n await sleep(delay * Math.pow(backoff, attempt));\n }\n }\n }\n throw lastError;\n};\n\nexport const withTimeout = <T>(\n promise: Promise<T>,\n ms: number,\n errorMessage = \"Operation timed out\",\n): Promise<T> => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(errorMessage)), ms);\n });\n return Promise.race([\n promise.finally(() => {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n }),\n timeout,\n ]);\n};\n"]}
@@ -5,10 +5,21 @@ var capitalize = (str) => str.length === 0 ? str : str[0].toUpperCase() + str.sl
5
5
  var camelToKebab = (str) => str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, "");
6
6
  var kebabToCamel = (str) => str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
7
7
  var truncate = (str, max, suffix = "...") => str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;
8
+ var formatNumber = (n, locale = "en-US") => new Intl.NumberFormat(locale).format(n);
9
+ var mask = (str, opts = {}) => {
10
+ const start = Math.max(0, opts.start ?? 1);
11
+ const end = Math.max(0, opts.end ?? 0);
12
+ const char = opts.char ?? "*";
13
+ if (str.length <= start + end) return str;
14
+ const masked = char.repeat(str.length - start - end);
15
+ return str.slice(0, start) + masked + str.slice(str.length - end);
16
+ };
8
17
 
9
18
  exports.camelToKebab = camelToKebab;
10
19
  exports.capitalize = capitalize;
20
+ exports.formatNumber = formatNumber;
11
21
  exports.kebabToCamel = kebabToCamel;
22
+ exports.mask = mask;
12
23
  exports.truncate = truncate;
13
24
  //# sourceMappingURL=index.cjs.map
14
25
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/string/index.ts"],"names":[],"mappings":";;;AAAO,IAAM,UAAA,GAAa,CAAC,GAAA,KACzB,GAAA,CAAI,WAAW,CAAA,GAAI,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAG,WAAA,EAAY,GAAI,GAAA,CAAI,MAAM,CAAC;AAEvD,IAAM,eAAe,CAAC,GAAA,KAC3B,GAAA,CAAI,OAAA,CAAQ,UAAU,CAAC,CAAA,KAAM,CAAA,CAAA,EAAI,CAAA,CAAE,aAAa,CAAA,CAAE,CAAA,CAAE,OAAA,CAAQ,MAAM,EAAE;AAE/D,IAAM,YAAA,GAAe,CAAC,GAAA,KAC3B,GAAA,CAAI,OAAA,CAAQ,WAAA,EAAa,CAAC,CAAA,EAAG,CAAA,KAAc,CAAA,CAAE,WAAA,EAAa;AAErD,IAAM,QAAA,GAAW,CAAC,GAAA,EAAa,GAAA,EAAa,SAAS,KAAA,KAC1D,GAAA,CAAI,UAAU,GAAA,GAAM,GAAA,GAAM,IAAI,KAAA,CAAM,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,MAAM,MAAA,CAAO,MAAM,CAAC,CAAA,GAAI","file":"index.cjs","sourcesContent":["export const capitalize = (str: string): string =>\n str.length === 0 ? str : str[0]!.toUpperCase() + str.slice(1);\n\nexport const camelToKebab = (str: string): string =>\n str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, \"\");\n\nexport const kebabToCamel = (str: string): string =>\n str.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n\nexport const truncate = (str: string, max: number, suffix = \"...\"): string =>\n str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;\n"]}
1
+ {"version":3,"sources":["../../src/string/index.ts"],"names":[],"mappings":";;;AAAO,IAAM,UAAA,GAAa,CAAC,GAAA,KACzB,GAAA,CAAI,WAAW,CAAA,GAAI,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAG,WAAA,EAAY,GAAI,GAAA,CAAI,MAAM,CAAC;AAEvD,IAAM,eAAe,CAAC,GAAA,KAC3B,GAAA,CAAI,OAAA,CAAQ,UAAU,CAAC,CAAA,KAAM,CAAA,CAAA,EAAI,CAAA,CAAE,aAAa,CAAA,CAAE,CAAA,CAAE,OAAA,CAAQ,MAAM,EAAE;AAE/D,IAAM,YAAA,GAAe,CAAC,GAAA,KAC3B,GAAA,CAAI,OAAA,CAAQ,WAAA,EAAa,CAAC,CAAA,EAAG,CAAA,KAAc,CAAA,CAAE,WAAA,EAAa;AAErD,IAAM,QAAA,GAAW,CAAC,GAAA,EAAa,GAAA,EAAa,SAAS,KAAA,KAC1D,GAAA,CAAI,UAAU,GAAA,GAAM,GAAA,GAAM,IAAI,KAAA,CAAM,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,MAAM,MAAA,CAAO,MAAM,CAAC,CAAA,GAAI;AAEtE,IAAM,YAAA,GAAe,CAAC,CAAA,EAAW,MAAA,GAAS,OAAA,KAC/C,IAAI,IAAA,CAAK,YAAA,CAAa,MAAM,CAAA,CAAE,MAAA,CAAO,CAAC;AAQjC,IAAM,IAAA,GAAO,CAAC,GAAA,EAAa,IAAA,GAAoB,EAAC,KAAc;AACnE,EAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,SAAS,CAAC,CAAA;AACzC,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,OAAO,CAAC,CAAA;AACrC,EAAA,MAAM,IAAA,GAAO,KAAK,IAAA,IAAQ,GAAA;AAC1B,EAAA,IAAI,GAAA,CAAI,MAAA,IAAU,KAAA,GAAQ,GAAA,EAAK,OAAO,GAAA;AACtC,EAAA,MAAM,SAAS,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,MAAA,GAAS,QAAQ,GAAG,CAAA;AACnD,EAAA,OAAO,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,GAAI,SAAS,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,MAAA,GAAS,GAAG,CAAA;AAClE","file":"index.cjs","sourcesContent":["export const capitalize = (str: string): string =>\n str.length === 0 ? str : str[0]!.toUpperCase() + str.slice(1);\n\nexport const camelToKebab = (str: string): string =>\n str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, \"\");\n\nexport const kebabToCamel = (str: string): string =>\n str.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n\nexport const truncate = (str: string, max: number, suffix = \"...\"): string =>\n str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;\n\nexport const formatNumber = (n: number, locale = \"en-US\"): string =>\n new Intl.NumberFormat(locale).format(n);\n\nexport interface MaskOptions {\n start?: number;\n end?: number;\n char?: string;\n}\n\nexport const mask = (str: string, opts: MaskOptions = {}): string => {\n const start = Math.max(0, opts.start ?? 1);\n const end = Math.max(0, opts.end ?? 0);\n const char = opts.char ?? \"*\";\n if (str.length <= start + end) return str;\n const masked = char.repeat(str.length - start - end);\n return str.slice(0, start) + masked + str.slice(str.length - end);\n};\n"]}
@@ -2,5 +2,12 @@ declare const capitalize: (str: string) => string;
2
2
  declare const camelToKebab: (str: string) => string;
3
3
  declare const kebabToCamel: (str: string) => string;
4
4
  declare const truncate: (str: string, max: number, suffix?: string) => string;
5
+ declare const formatNumber: (n: number, locale?: string) => string;
6
+ interface MaskOptions {
7
+ start?: number;
8
+ end?: number;
9
+ char?: string;
10
+ }
11
+ declare const mask: (str: string, opts?: MaskOptions) => string;
5
12
 
6
- export { camelToKebab, capitalize, kebabToCamel, truncate };
13
+ export { type MaskOptions, camelToKebab, capitalize, formatNumber, kebabToCamel, mask, truncate };
@@ -2,5 +2,12 @@ declare const capitalize: (str: string) => string;
2
2
  declare const camelToKebab: (str: string) => string;
3
3
  declare const kebabToCamel: (str: string) => string;
4
4
  declare const truncate: (str: string, max: number, suffix?: string) => string;
5
+ declare const formatNumber: (n: number, locale?: string) => string;
6
+ interface MaskOptions {
7
+ start?: number;
8
+ end?: number;
9
+ char?: string;
10
+ }
11
+ declare const mask: (str: string, opts?: MaskOptions) => string;
5
12
 
6
- export { camelToKebab, capitalize, kebabToCamel, truncate };
13
+ export { type MaskOptions, camelToKebab, capitalize, formatNumber, kebabToCamel, mask, truncate };
@@ -3,7 +3,16 @@ var capitalize = (str) => str.length === 0 ? str : str[0].toUpperCase() + str.sl
3
3
  var camelToKebab = (str) => str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, "");
4
4
  var kebabToCamel = (str) => str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
5
5
  var truncate = (str, max, suffix = "...") => str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;
6
+ var formatNumber = (n, locale = "en-US") => new Intl.NumberFormat(locale).format(n);
7
+ var mask = (str, opts = {}) => {
8
+ const start = Math.max(0, opts.start ?? 1);
9
+ const end = Math.max(0, opts.end ?? 0);
10
+ const char = opts.char ?? "*";
11
+ if (str.length <= start + end) return str;
12
+ const masked = char.repeat(str.length - start - end);
13
+ return str.slice(0, start) + masked + str.slice(str.length - end);
14
+ };
6
15
 
7
- export { camelToKebab, capitalize, kebabToCamel, truncate };
16
+ export { camelToKebab, capitalize, formatNumber, kebabToCamel, mask, truncate };
8
17
  //# sourceMappingURL=index.js.map
9
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/string/index.ts"],"names":[],"mappings":";AAAO,IAAM,UAAA,GAAa,CAAC,GAAA,KACzB,GAAA,CAAI,WAAW,CAAA,GAAI,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAG,WAAA,EAAY,GAAI,GAAA,CAAI,MAAM,CAAC;AAEvD,IAAM,eAAe,CAAC,GAAA,KAC3B,GAAA,CAAI,OAAA,CAAQ,UAAU,CAAC,CAAA,KAAM,CAAA,CAAA,EAAI,CAAA,CAAE,aAAa,CAAA,CAAE,CAAA,CAAE,OAAA,CAAQ,MAAM,EAAE;AAE/D,IAAM,YAAA,GAAe,CAAC,GAAA,KAC3B,GAAA,CAAI,OAAA,CAAQ,WAAA,EAAa,CAAC,CAAA,EAAG,CAAA,KAAc,CAAA,CAAE,WAAA,EAAa;AAErD,IAAM,QAAA,GAAW,CAAC,GAAA,EAAa,GAAA,EAAa,SAAS,KAAA,KAC1D,GAAA,CAAI,UAAU,GAAA,GAAM,GAAA,GAAM,IAAI,KAAA,CAAM,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,MAAM,MAAA,CAAO,MAAM,CAAC,CAAA,GAAI","file":"index.js","sourcesContent":["export const capitalize = (str: string): string =>\n str.length === 0 ? str : str[0]!.toUpperCase() + str.slice(1);\n\nexport const camelToKebab = (str: string): string =>\n str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, \"\");\n\nexport const kebabToCamel = (str: string): string =>\n str.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n\nexport const truncate = (str: string, max: number, suffix = \"...\"): string =>\n str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;\n"]}
1
+ {"version":3,"sources":["../../src/string/index.ts"],"names":[],"mappings":";AAAO,IAAM,UAAA,GAAa,CAAC,GAAA,KACzB,GAAA,CAAI,WAAW,CAAA,GAAI,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAG,WAAA,EAAY,GAAI,GAAA,CAAI,MAAM,CAAC;AAEvD,IAAM,eAAe,CAAC,GAAA,KAC3B,GAAA,CAAI,OAAA,CAAQ,UAAU,CAAC,CAAA,KAAM,CAAA,CAAA,EAAI,CAAA,CAAE,aAAa,CAAA,CAAE,CAAA,CAAE,OAAA,CAAQ,MAAM,EAAE;AAE/D,IAAM,YAAA,GAAe,CAAC,GAAA,KAC3B,GAAA,CAAI,OAAA,CAAQ,WAAA,EAAa,CAAC,CAAA,EAAG,CAAA,KAAc,CAAA,CAAE,WAAA,EAAa;AAErD,IAAM,QAAA,GAAW,CAAC,GAAA,EAAa,GAAA,EAAa,SAAS,KAAA,KAC1D,GAAA,CAAI,UAAU,GAAA,GAAM,GAAA,GAAM,IAAI,KAAA,CAAM,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,MAAM,MAAA,CAAO,MAAM,CAAC,CAAA,GAAI;AAEtE,IAAM,YAAA,GAAe,CAAC,CAAA,EAAW,MAAA,GAAS,OAAA,KAC/C,IAAI,IAAA,CAAK,YAAA,CAAa,MAAM,CAAA,CAAE,MAAA,CAAO,CAAC;AAQjC,IAAM,IAAA,GAAO,CAAC,GAAA,EAAa,IAAA,GAAoB,EAAC,KAAc;AACnE,EAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,SAAS,CAAC,CAAA;AACzC,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,OAAO,CAAC,CAAA;AACrC,EAAA,MAAM,IAAA,GAAO,KAAK,IAAA,IAAQ,GAAA;AAC1B,EAAA,IAAI,GAAA,CAAI,MAAA,IAAU,KAAA,GAAQ,GAAA,EAAK,OAAO,GAAA;AACtC,EAAA,MAAM,SAAS,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,MAAA,GAAS,QAAQ,GAAG,CAAA;AACnD,EAAA,OAAO,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,GAAI,SAAS,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,MAAA,GAAS,GAAG,CAAA;AAClE","file":"index.js","sourcesContent":["export const capitalize = (str: string): string =>\n str.length === 0 ? str : str[0]!.toUpperCase() + str.slice(1);\n\nexport const camelToKebab = (str: string): string =>\n str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^-/, \"\");\n\nexport const kebabToCamel = (str: string): string =>\n str.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n\nexport const truncate = (str: string, max: number, suffix = \"...\"): string =>\n str.length <= max ? str : str.slice(0, Math.max(0, max - suffix.length)) + suffix;\n\nexport const formatNumber = (n: number, locale = \"en-US\"): string =>\n new Intl.NumberFormat(locale).format(n);\n\nexport interface MaskOptions {\n start?: number;\n end?: number;\n char?: string;\n}\n\nexport const mask = (str: string, opts: MaskOptions = {}): string => {\n const start = Math.max(0, opts.start ?? 1);\n const end = Math.max(0, opts.end ?? 0);\n const char = opts.char ?? \"*\";\n if (str.length <= start + end) return str;\n const masked = char.repeat(str.length - start - end);\n return str.slice(0, start) + masked + str.slice(str.length - end);\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jthong/util",
3
- "version": "0.1.0-alpha.0",
3
+ "version": "0.1.0-alpha.1",
4
4
  "description": "Framework-agnostic TypeScript utility functions",
5
5
  "license": "MIT",
6
6
  "type": "module",