@pogodisco/ts-kit 0.0.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.
Files changed (91) hide show
  1. package/dist/accessors/get-at-path.d.ts +1 -0
  2. package/dist/accessors/get-at-path.js +13 -0
  3. package/dist/accessors/index.d.ts +6 -0
  4. package/dist/accessors/index.js +6 -0
  5. package/dist/accessors/push-to-nested-array.d.ts +1 -0
  6. package/dist/accessors/push-to-nested-array.js +16 -0
  7. package/dist/accessors/push-unique-to-array.d.ts +1 -0
  8. package/dist/accessors/push-unique-to-array.js +5 -0
  9. package/dist/accessors/select-map.d.ts +1 -0
  10. package/dist/accessors/select-map.js +5 -0
  11. package/dist/accessors/set-at-path.d.ts +1 -0
  12. package/dist/accessors/set-at-path.js +30 -0
  13. package/dist/accessors/set-deep-object-value.d.ts +1 -0
  14. package/dist/accessors/set-deep-object-value.js +12 -0
  15. package/dist/array/index.d.ts +2 -0
  16. package/dist/array/index.js +2 -0
  17. package/dist/array/random-from-array.d.ts +1 -0
  18. package/dist/array/random-from-array.js +6 -0
  19. package/dist/array/random-subset-from-array.d.ts +1 -0
  20. package/dist/array/random-subset-from-array.js +12 -0
  21. package/dist/data/file-content-types.d.ts +8 -0
  22. package/dist/data/file-content-types.js +61 -0
  23. package/dist/data/index.d.ts +1 -0
  24. package/dist/data/index.js +1 -0
  25. package/dist/date/format-smart-date.d.ts +8 -0
  26. package/dist/date/format-smart-date.js +32 -0
  27. package/dist/date/index.d.ts +1 -0
  28. package/dist/date/index.js +1 -0
  29. package/dist/finance/index.d.ts +17 -0
  30. package/dist/finance/index.js +52 -0
  31. package/dist/format/create-id-from-date.d.ts +1 -0
  32. package/dist/format/create-id-from-date.js +4 -0
  33. package/dist/format/format-capitalize-string.d.ts +1 -0
  34. package/dist/format/format-capitalize-string.js +3 -0
  35. package/dist/format/format-size.d.ts +1 -0
  36. package/dist/format/format-size.js +11 -0
  37. package/dist/format/format-unit-suffix.d.ts +1 -0
  38. package/dist/format/format-unit-suffix.js +6 -0
  39. package/dist/format/format-url.d.ts +1 -0
  40. package/dist/format/format-url.js +8 -0
  41. package/dist/format/index.d.ts +12 -0
  42. package/dist/format/index.js +12 -0
  43. package/dist/format/replace-last-sement.d.ts +1 -0
  44. package/dist/format/replace-last-sement.js +13 -0
  45. package/dist/format/sanitize.d.ts +11 -0
  46. package/dist/format/sanitize.js +53 -0
  47. package/dist/format/strip-slashes.d.ts +1 -0
  48. package/dist/format/strip-slashes.js +1 -0
  49. package/dist/format/strip-trailing-slashes.d.ts +1 -0
  50. package/dist/format/strip-trailing-slashes.js +1 -0
  51. package/dist/format/to-kebab-case.d.ts +1 -0
  52. package/dist/format/to-kebab-case.js +7 -0
  53. package/dist/format/trim-whitespace.d.ts +1 -0
  54. package/dist/format/trim-whitespace.js +1 -0
  55. package/dist/format/truncate-text.d.ts +1 -0
  56. package/dist/format/truncate-text.js +5 -0
  57. package/dist/index.d.ts +8 -0
  58. package/dist/index.js +8 -0
  59. package/dist/parsers/clone-object.d.ts +1 -0
  60. package/dist/parsers/clone-object.js +3 -0
  61. package/dist/parsers/coerce-numeric-strings.d.ts +1 -0
  62. package/dist/parsers/coerce-numeric-strings.js +16 -0
  63. package/dist/parsers/escape-html.d.ts +1 -0
  64. package/dist/parsers/escape-html.js +8 -0
  65. package/dist/parsers/flatten-deep.d.ts +1 -0
  66. package/dist/parsers/flatten-deep.js +3 -0
  67. package/dist/parsers/flatten-object-keys.d.ts +8 -0
  68. package/dist/parsers/flatten-object-keys.js +17 -0
  69. package/dist/parsers/fn-parser.d.ts +17 -0
  70. package/dist/parsers/fn-parser.js +80 -0
  71. package/dist/parsers/index.d.ts +10 -0
  72. package/dist/parsers/index.js +10 -0
  73. package/dist/parsers/is-colon-separated.d.ts +1 -0
  74. package/dist/parsers/is-colon-separated.js +3 -0
  75. package/dist/parsers/map-filter.d.ts +1 -0
  76. package/dist/parsers/map-filter.js +10 -0
  77. package/dist/parsers/omit-keys-deep.d.ts +9 -0
  78. package/dist/parsers/omit-keys-deep.js +43 -0
  79. package/dist/parsers/parse-string-to-object.d.ts +1 -0
  80. package/dist/parsers/parse-string-to-object.js +8 -0
  81. package/dist/parsers/style/index.d.ts +1 -0
  82. package/dist/parsers/style/index.js +1 -0
  83. package/dist/parsers/style/parse-border-string.d.ts +5 -0
  84. package/dist/parsers/style/parse-border-string.js +8 -0
  85. package/dist/processors/deep-merge.d.ts +1 -0
  86. package/dist/processors/deep-merge.js +18 -0
  87. package/dist/processors/index.d.ts +2 -0
  88. package/dist/processors/index.js +2 -0
  89. package/dist/processors/process-data-in-chunks.d.ts +5 -0
  90. package/dist/processors/process-data-in-chunks.js +21 -0
  91. package/package.json +39 -0
@@ -0,0 +1 @@
1
+ export declare function getAtPath(obj: any, path: string): any;
@@ -0,0 +1,13 @@
1
+ export function getAtPath(obj, path) {
2
+ const keys = path.split(".");
3
+ return keys.reduce((acc, key) => {
4
+ if (!acc)
5
+ return undefined;
6
+ const match = key.match(/^(\w+)\[(\d+)\]$/);
7
+ if (match) {
8
+ const [, arrKey, index] = match;
9
+ return acc[arrKey]?.[Number(index)];
10
+ }
11
+ return acc[key];
12
+ }, obj);
13
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./push-to-nested-array.js";
2
+ export * from "./set-deep-object-value.js";
3
+ export * from "./push-unique-to-array.js";
4
+ export * from "./get-at-path.js";
5
+ export * from "./set-at-path.js";
6
+ export * from "./select-map.js";
@@ -0,0 +1,6 @@
1
+ export * from "./push-to-nested-array.js";
2
+ export * from "./set-deep-object-value.js";
3
+ export * from "./push-unique-to-array.js";
4
+ export * from "./get-at-path.js";
5
+ export * from "./set-at-path.js";
6
+ export * from "./select-map.js";
@@ -0,0 +1 @@
1
+ export declare function pushToNestedArray(obj: Record<string, any>, path: string, value: any): void;
@@ -0,0 +1,16 @@
1
+ export function pushToNestedArray(obj, path, value) {
2
+ const keys = path.split(".");
3
+ let current = obj;
4
+ for (let i = 0; i < keys.length - 1; i++) {
5
+ const key = keys[i];
6
+ if (!(key in current) || typeof current[key] !== "object") {
7
+ current[key] = {};
8
+ }
9
+ current = current[key];
10
+ }
11
+ const finalKey = keys[keys.length - 1];
12
+ if (!Array.isArray(current[finalKey])) {
13
+ current[finalKey] = [];
14
+ }
15
+ current[finalKey].push(value);
16
+ }
@@ -0,0 +1 @@
1
+ export declare const pushUniqueToArray: (target: any[], value: any) => void;
@@ -0,0 +1,5 @@
1
+ export const pushUniqueToArray = (target, value) => {
2
+ if (!target.includes(value)) {
3
+ target.push(value);
4
+ }
5
+ };
@@ -0,0 +1 @@
1
+ export declare function selectMap(map: Record<string, string>): (key: string) => string | undefined;
@@ -0,0 +1,5 @@
1
+ export function selectMap(map) {
2
+ return (key) => {
3
+ return map[key];
4
+ };
5
+ }
@@ -0,0 +1 @@
1
+ export declare function setAtPath(obj: any, path: string, value: any): void;
@@ -0,0 +1,30 @@
1
+ export function setAtPath(obj, path, value) {
2
+ const keys = path.split(".");
3
+ const lastKey = keys.pop();
4
+ const target = keys.reduce((acc, key) => {
5
+ const match = key.match(/^(\w+)\[(\d+)\]$/);
6
+ if (match) {
7
+ const [, arrKey, index] = match;
8
+ if (!acc[arrKey])
9
+ acc[arrKey] = [];
10
+ if (!acc[arrKey][Number(index)])
11
+ acc[arrKey][Number(index)] = {};
12
+ return acc[arrKey][Number(index)];
13
+ }
14
+ if (!acc[key])
15
+ acc[key] = {};
16
+ return acc[key];
17
+ }, obj);
18
+ if (!lastKey)
19
+ return;
20
+ const match = lastKey.match(/^(\w+)\[(\d+)\]$/);
21
+ if (match) {
22
+ const [, arrKey, index] = match;
23
+ if (!target[arrKey])
24
+ target[arrKey] = [];
25
+ target[arrKey][Number(index)] = value;
26
+ }
27
+ else {
28
+ target[lastKey] = value;
29
+ }
30
+ }
@@ -0,0 +1 @@
1
+ export declare function setObjectValue(obj: Record<string, any>, path: string, value: any): void;
@@ -0,0 +1,12 @@
1
+ export function setObjectValue(obj, path, value) {
2
+ const keys = path.split(".");
3
+ let current = obj;
4
+ for (let i = 0; i < keys.length - 1; i++) {
5
+ const key = keys[i];
6
+ if (!(key in current) || typeof current[key] !== "object") {
7
+ current[key] = {};
8
+ }
9
+ current = current[key];
10
+ }
11
+ current[keys[keys.length - 1]] = value;
12
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./random-from-array.js";
2
+ export * from "./random-subset-from-array.js";
@@ -0,0 +1,2 @@
1
+ export * from "./random-from-array.js";
2
+ export * from "./random-subset-from-array.js";
@@ -0,0 +1 @@
1
+ export declare function randomFromArray<T>(arr: T[]): T | undefined;
@@ -0,0 +1,6 @@
1
+ export function randomFromArray(arr) {
2
+ if (!arr.length)
3
+ return undefined;
4
+ const index = Math.floor(Math.random() * arr.length);
5
+ return arr[index];
6
+ }
@@ -0,0 +1 @@
1
+ export declare function randomSubsetFromArray<T>(arr: T[], min: number, max: number): T[];
@@ -0,0 +1,12 @@
1
+ export function randomSubsetFromArray(arr, min, max) {
2
+ if (!arr.length || min > arr.length)
3
+ return [];
4
+ const size = Math.floor(Math.random() * (max - min + 1)) + min;
5
+ // shuffle a copy of the array (Fisher-Yates)
6
+ const copy = [...arr];
7
+ for (let i = copy.length - 1; i > 0; i--) {
8
+ const j = Math.floor(Math.random() * (i + 1));
9
+ [copy[i], copy[j]] = [copy[j], copy[i]];
10
+ }
11
+ return copy.slice(0, Math.min(size, copy.length));
12
+ }
@@ -0,0 +1,8 @@
1
+ export declare const imageTypes: string[];
2
+ export declare const videoTypes: string[];
3
+ export declare const audioTypes: string[];
4
+ export declare const documentTypes: string[];
5
+ export declare const compressedTypes: string[];
6
+ export declare const dataTypes: string[];
7
+ export declare const apiAndWebTypes: string[];
8
+ export declare const contentTypes: string[];
@@ -0,0 +1,61 @@
1
+ export const imageTypes = [
2
+ "image/jpeg",
3
+ "image/png",
4
+ "image/gif",
5
+ "image/svg+xml",
6
+ "image/webp",
7
+ "image/avif",
8
+ "image/bmp",
9
+ "image/tiff",
10
+ ];
11
+ export const videoTypes = [
12
+ "video/mp4",
13
+ "video/webm",
14
+ "video/ogg",
15
+ "video/x-msvideo",
16
+ "video/quicktime",
17
+ ];
18
+ export const audioTypes = ["audio/mpeg", "audio/wav", "audi/ogg", "audio/flac"];
19
+ export const documentTypes = [
20
+ "application/pdf",
21
+ "application/msword",
22
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
23
+ "application/vnd.ms-excel",
24
+ "application/vnd.ms-powerpoint",
25
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
26
+ "text/plain",
27
+ "application/rtf",
28
+ ];
29
+ export const compressedTypes = [
30
+ "application/zip",
31
+ "application/x-tar",
32
+ "application/x-rar-compressed",
33
+ "application/gzip",
34
+ "application/x-7z-compressed",
35
+ ];
36
+ export const dataTypes = [
37
+ "application/json",
38
+ "application/xml",
39
+ "text/html",
40
+ "text/css",
41
+ "text/javascript",
42
+ "application/sql",
43
+ "application/x-sh",
44
+ "application/java-archive",
45
+ "application/octet-stream",
46
+ ];
47
+ export const apiAndWebTypes = [
48
+ "application/x-www-form-urlencoded",
49
+ "multipart/form-data",
50
+ "application/x-ndjson",
51
+ "application/vnd.api+json",
52
+ ];
53
+ export const contentTypes = [
54
+ ...imageTypes,
55
+ ...videoTypes,
56
+ ...audioTypes,
57
+ ...documentTypes,
58
+ ...compressedTypes,
59
+ ...dataTypes,
60
+ ...apiAndWebTypes,
61
+ ];
@@ -0,0 +1 @@
1
+ export * from "./file-content-types.js";
@@ -0,0 +1 @@
1
+ export * from "./file-content-types.js";
@@ -0,0 +1,8 @@
1
+ import { Locale } from "date-fns";
2
+ type SmartDateOpts = {
3
+ withTime?: boolean;
4
+ locale?: Locale;
5
+ referenceDate?: Date;
6
+ };
7
+ export declare function formatSmartDate(dateInput: string | Date, options?: SmartDateOpts): string;
8
+ export {};
@@ -0,0 +1,32 @@
1
+ import { format, isToday, isYesterday, isThisWeek, isThisYear, differenceInDays, parseISO, } from "date-fns";
2
+ import { enUS } from "date-fns/locale";
3
+ export function formatSmartDate(dateInput, options = {}) {
4
+ const { withTime = true, locale = enUS, referenceDate = new Date(), } = options;
5
+ if (!dateInput)
6
+ return "";
7
+ const date = typeof dateInput === "string" ? parseISO(dateInput) : new Date(dateInput);
8
+ const daysDiff = differenceInDays(referenceDate, date);
9
+ const timePart = withTime ? `, ${format(date, "HH:mm", { locale })}` : "";
10
+ // ✅ Today
11
+ if (isToday(date)) {
12
+ return format(date, withTime ? "HH:mm" : "d MMM", { locale });
13
+ }
14
+ // ✅ Yesterday
15
+ if (isYesterday(date)) {
16
+ return `Yesterday${timePart}`;
17
+ }
18
+ // ✅ This week
19
+ if (isThisWeek(date, { weekStartsOn: 1 })) {
20
+ return `${format(date, "EEE", { locale })}${timePart}`;
21
+ }
22
+ // ✅ Within last month
23
+ if (daysDiff <= 30) {
24
+ return `${format(date, "d MMM", { locale })}${timePart}`;
25
+ }
26
+ // ✅ Same year
27
+ if (isThisYear(date)) {
28
+ return `${format(date, "d MMM", { locale })}${timePart}`;
29
+ }
30
+ // ✅ Older
31
+ return `${format(date, "dd.MM.yyyy", { locale })}${timePart}`;
32
+ }
@@ -0,0 +1 @@
1
+ export * from "./format-smart-date.js";
@@ -0,0 +1 @@
1
+ export * from "./format-smart-date.js";
@@ -0,0 +1,17 @@
1
+ export type Calculable = {
2
+ base: number;
3
+ overhead: number;
4
+ };
5
+ export type CurrencyCode = "usd" | "gbp" | "eur" | "pln" | "jpy";
6
+ export declare function withOverhead(input: Calculable, precision?: number): number;
7
+ export declare function getOverheadAmount(input: Calculable, precision?: number): number;
8
+ export declare function subtotal(input: Calculable, qty: number, precision?: number): {
9
+ netSubtotal: number;
10
+ overheadAmount: number;
11
+ grossSubtotal: number;
12
+ };
13
+ export declare function chainOverheads(base: number, ...overheads: number[]): number;
14
+ export declare function roundDecimals(value: number, decimals?: number): number;
15
+ export declare function toMinorUnits(amount: number, currency: string): number;
16
+ export declare function fromMinorUnits(amount: number, currency: string): number;
17
+ export declare const addCurrencySymbol: (value: number | string, currencyCode: CurrencyCode) => string;
@@ -0,0 +1,52 @@
1
+ function normalizeFactor(factor) {
2
+ // integers >= 1 are percentages; 0 < factor <= 1 are fractions
3
+ return factor >= 1 ? factor / 100 : factor;
4
+ }
5
+ export function withOverhead(input, precision = 2) {
6
+ const factor = normalizeFactor(input.overhead);
7
+ return +(input.base * (1 + factor)).toFixed(precision);
8
+ }
9
+ export function getOverheadAmount(input, precision = 2) {
10
+ const factor = normalizeFactor(input.overhead);
11
+ return +(input.base * factor).toFixed(precision);
12
+ }
13
+ export function subtotal(input, qty, precision = 2) {
14
+ const factor = normalizeFactor(input.overhead);
15
+ const baseWithOverhead = +(input.base * (1 + factor)).toFixed(precision);
16
+ const netSubtotal = +(input.base * qty).toFixed(precision);
17
+ const grossSubtotal = +(baseWithOverhead * qty).toFixed(precision);
18
+ const overheadAmount = +(grossSubtotal - netSubtotal).toFixed(precision);
19
+ return {
20
+ netSubtotal,
21
+ overheadAmount,
22
+ grossSubtotal,
23
+ };
24
+ }
25
+ export function chainOverheads(base, ...overheads) {
26
+ return overheads.reduce((acc, overhead) => withOverhead({ base: acc, overhead }), base);
27
+ }
28
+ export function roundDecimals(value, decimals = 2) {
29
+ return parseFloat(value.toFixed(decimals));
30
+ }
31
+ export function toMinorUnits(amount, currency) {
32
+ const decimals = ["jpy"].includes(currency.toLowerCase()) ? 0 : 2;
33
+ return Math.round(amount * 10 ** decimals);
34
+ }
35
+ export function fromMinorUnits(amount, currency) {
36
+ const decimals = ["jpy"].includes(currency.toLowerCase()) ? 0 : 2;
37
+ return amount / 10 ** decimals;
38
+ }
39
+ export const addCurrencySymbol = (value, currencyCode) => {
40
+ switch (currencyCode.toLowerCase()) {
41
+ case "pln":
42
+ return `${value} zł`;
43
+ case "usd":
44
+ return `${value} $`;
45
+ case "gbp":
46
+ return `£${value}`;
47
+ case "eur":
48
+ return `€${value}`;
49
+ default:
50
+ return `${value} ${currencyCode}`;
51
+ }
52
+ };
@@ -0,0 +1 @@
1
+ export declare const createIdFromDate: () => string;
@@ -0,0 +1,4 @@
1
+ import { sanitizeForUrl } from "./format-url.js";
2
+ export const createIdFromDate = () => {
3
+ return sanitizeForUrl(new Date().toISOString());
4
+ };
@@ -0,0 +1 @@
1
+ export declare function capitalize(str: string): string;
@@ -0,0 +1,3 @@
1
+ export function capitalize(str) {
2
+ return str.charAt(0).toUpperCase() + str.slice(1);
3
+ }
@@ -0,0 +1 @@
1
+ export declare function formatSize(bytes: number): string;
@@ -0,0 +1,11 @@
1
+ export function formatSize(bytes) {
2
+ if (bytes < 1024)
3
+ return `${bytes} B`;
4
+ const units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB'];
5
+ let i = -1;
6
+ do {
7
+ bytes /= 1024;
8
+ i++;
9
+ } while (bytes >= 1024 && i < units.length - 1);
10
+ return `${bytes.toFixed(2)} ${units[i]}`;
11
+ }
@@ -0,0 +1 @@
1
+ export declare function formatUnitSuffix(input: string | number, suffix: string): string;
@@ -0,0 +1,6 @@
1
+ export function formatUnitSuffix(input, suffix) {
2
+ const str = String(input).trim();
3
+ const match = str.match(/^(-?\d*\.?\d+)/);
4
+ const num = match ? match[1] : "0";
5
+ return `${num}${suffix}`;
6
+ }
@@ -0,0 +1 @@
1
+ export declare function sanitizeForUrl(input: string, separator?: '-' | '_'): string;
@@ -0,0 +1,8 @@
1
+ export function sanitizeForUrl(input, separator = '-') {
2
+ return input
3
+ .toLowerCase()
4
+ .normalize('NFD')
5
+ .replace(/[\u0300-\u036f]/g, '')
6
+ .replace(/[^\w\s-]/g, '')
7
+ .replace(/\s+/g, separator);
8
+ }
@@ -0,0 +1,12 @@
1
+ export * from "./replace-last-sement.js";
2
+ export * from "./strip-slashes.js";
3
+ export * from "./strip-trailing-slashes.js";
4
+ export * from "./trim-whitespace.js";
5
+ export * from "./format-url.js";
6
+ export * from "./create-id-from-date.js";
7
+ export * from "./format-capitalize-string.js";
8
+ export * from "./format-size.js";
9
+ export * from "./format-unit-suffix.js";
10
+ export * from "./sanitize.js";
11
+ export * from "./truncate-text.js";
12
+ export * from "./to-kebab-case.js";
@@ -0,0 +1,12 @@
1
+ export * from "./replace-last-sement.js";
2
+ export * from "./strip-slashes.js";
3
+ export * from "./strip-trailing-slashes.js";
4
+ export * from "./trim-whitespace.js";
5
+ export * from "./format-url.js";
6
+ export * from "./create-id-from-date.js";
7
+ export * from "./format-capitalize-string.js";
8
+ export * from "./format-size.js";
9
+ export * from "./format-unit-suffix.js";
10
+ export * from "./sanitize.js";
11
+ export * from "./truncate-text.js";
12
+ export * from "./to-kebab-case.js";
@@ -0,0 +1 @@
1
+ export declare function replaceLastSegment(path: string, replacement: string): string;
@@ -0,0 +1,13 @@
1
+ export function replaceLastSegment(path, replacement) {
2
+ const hasTrailingSlash = path.endsWith("/");
3
+ const segments = path
4
+ .split("/")
5
+ .filter((seg, i, arr) => i < arr.length - 1 || seg);
6
+ if (segments.length > 0) {
7
+ segments[segments.length - 1] = replacement;
8
+ }
9
+ else {
10
+ segments.push(replacement);
11
+ }
12
+ return segments.join("/") + (hasTrailingSlash ? "/" : "");
13
+ }
@@ -0,0 +1,11 @@
1
+ type Sanitizer = (val: any) => any;
2
+ export type SanitizerContext = {
3
+ value: any;
4
+ document: any;
5
+ parent?: any;
6
+ index?: number;
7
+ path: string;
8
+ };
9
+ export type SanitizerEntry = [string, Sanitizer];
10
+ export declare function applySanitizers(obj: any, sanitizers: SanitizerEntry[]): any;
11
+ export {};
@@ -0,0 +1,53 @@
1
+ import { getAtPath, setAtPath } from "../accessors/index.js";
2
+ export function applySanitizers(obj, sanitizers) {
3
+ const cloned = JSON.parse(JSON.stringify(obj));
4
+ for (const [path, fn] of sanitizers) {
5
+ const isWildcard = path.includes("[]");
6
+ const pathsToSanitize = isWildcard ? expandPaths(cloned, path) : [path];
7
+ for (const resolvedPath of pathsToSanitize) {
8
+ const value = getAtPath(cloned, resolvedPath);
9
+ if (value === undefined)
10
+ continue;
11
+ const context = {
12
+ value,
13
+ document: cloned,
14
+ path: resolvedPath,
15
+ };
16
+ if (isWildcard) {
17
+ const indexMatch = resolvedPath.match(/\[(\d+)\]/);
18
+ const index = indexMatch ? Number(indexMatch[1]) : undefined;
19
+ context.index = index;
20
+ const parentPath = resolvedPath.replace(/\.\w+$/, ""); // up one level
21
+ context.parent = getAtPath(cloned, parentPath);
22
+ }
23
+ setAtPath(cloned, resolvedPath, fn(context));
24
+ }
25
+ }
26
+ return cloned;
27
+ }
28
+ function expandPaths(obj, wildcardPath) {
29
+ const segments = wildcardPath.split(".");
30
+ const result = [];
31
+ function recurse(current, pathParts, currentPath) {
32
+ if (!pathParts.length) {
33
+ result.push(currentPath.join("."));
34
+ return;
35
+ }
36
+ const part = pathParts[0];
37
+ const match = part.match(/^(\w+)\[\]$/);
38
+ if (match) {
39
+ const key = match[1];
40
+ const array = current?.[key];
41
+ if (!Array.isArray(array))
42
+ return;
43
+ for (let i = 0; i < array.length; i++) {
44
+ recurse(array[i], pathParts.slice(1), [...currentPath, `${key}[${i}]`]);
45
+ }
46
+ }
47
+ else {
48
+ recurse(current?.[part], pathParts.slice(1), [...currentPath, part]);
49
+ }
50
+ }
51
+ recurse(obj, segments, []);
52
+ return result;
53
+ }
@@ -0,0 +1 @@
1
+ export declare const stripSlashes: (str: string) => string;
@@ -0,0 +1 @@
1
+ export const stripSlashes = (str) => str.replace(/\//g, '');
@@ -0,0 +1 @@
1
+ export declare const stripTrailingSlashes: (str: string) => string;
@@ -0,0 +1 @@
1
+ export const stripTrailingSlashes = (str) => str.replace(/\s+/g, '');
@@ -0,0 +1 @@
1
+ export declare function toKebabCase(str: string): string;
@@ -0,0 +1,7 @@
1
+ export function toKebabCase(str) {
2
+ return str
3
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
4
+ .replace(/([A-Z])([A-Z][a-z])/g, "$1-$2")
5
+ .replace(/^([A-Z])/, "-$1")
6
+ .toLowerCase();
7
+ }
@@ -0,0 +1 @@
1
+ export declare const trimWhitespace: (str: string) => string;
@@ -0,0 +1 @@
1
+ export const trimWhitespace = (str) => str.replace(/\/+$/g, '');
@@ -0,0 +1 @@
1
+ export declare function truncateText(text: string, limit: number): string;
@@ -0,0 +1,5 @@
1
+ export function truncateText(text, limit) {
2
+ if (text.length <= limit)
3
+ return text;
4
+ return text.slice(0, limit).trimEnd() + "…";
5
+ }
@@ -0,0 +1,8 @@
1
+ export * from "./accessors/index.js";
2
+ export * from "./parsers/index.js";
3
+ export * from "./data/index.js";
4
+ export * from "./format/index.js";
5
+ export * from "./processors/index.js";
6
+ export * from "./array/index.js";
7
+ export * from "./date/index.js";
8
+ export * from "./finance/index.js";
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export * from "./accessors/index.js";
2
+ export * from "./parsers/index.js";
3
+ export * from "./data/index.js";
4
+ export * from "./format/index.js";
5
+ export * from "./processors/index.js";
6
+ export * from "./array/index.js";
7
+ export * from "./date/index.js";
8
+ export * from "./finance/index.js";
@@ -0,0 +1 @@
1
+ export declare function cloneObject(obj: Record<string, any> | Record<string, any>[]): any;
@@ -0,0 +1,3 @@
1
+ export function cloneObject(obj) {
2
+ return JSON.parse(JSON.stringify(obj));
3
+ }
@@ -0,0 +1 @@
1
+ export declare function coerceNumericStrings(obj: Record<string, any> | Record<string, any>[]): any;
@@ -0,0 +1,16 @@
1
+ export function coerceNumericStrings(obj) {
2
+ if (Array.isArray(obj)) {
3
+ return obj.map(coerceNumericStrings);
4
+ }
5
+ if (obj && typeof obj === "object") {
6
+ const result = {};
7
+ for (const [key, value] of Object.entries(obj)) {
8
+ result[key] = coerceNumericStrings(value);
9
+ }
10
+ return result;
11
+ }
12
+ if (typeof obj === "string" && /^-?\d+(\.\d+)?$/.test(obj)) {
13
+ return parseFloat(obj);
14
+ }
15
+ return obj;
16
+ }
@@ -0,0 +1 @@
1
+ export declare function escapeHTML(str: string): string;
@@ -0,0 +1,8 @@
1
+ export function escapeHTML(str) {
2
+ return str
3
+ .replace(/&/g, "&amp;")
4
+ .replace(/"/g, "&quot;")
5
+ .replace(/'/g, "&#39;")
6
+ .replace(/</g, "&lt;")
7
+ .replace(/>/g, "&gt;");
8
+ }
@@ -0,0 +1 @@
1
+ export declare function flattenDeep(obj: any): any[];
@@ -0,0 +1,3 @@
1
+ export function flattenDeep(obj) {
2
+ return Object.values(obj).flatMap((v) => typeof v === "object" && !Array.isArray(v) ? flattenDeep(v) : v);
3
+ }
@@ -0,0 +1,8 @@
1
+ type FlattenOptions = {
2
+ input: Record<string, any>;
3
+ prefix?: string;
4
+ result?: Record<string, any>;
5
+ ignore?: (value: any, key: string, path: string) => boolean;
6
+ };
7
+ export declare function flattenObjectKeys({ input, prefix, result, ignore, }: FlattenOptions): Record<string, any>;
8
+ export {};
@@ -0,0 +1,17 @@
1
+ export function flattenObjectKeys({ input, prefix = "", result = {}, ignore, }) {
2
+ for (const [key, value] of Object.entries(input)) {
3
+ const path = prefix ? `${prefix}.${key}` : key;
4
+ const isObject = value &&
5
+ typeof value === "object" &&
6
+ !Array.isArray(value) &&
7
+ !(value instanceof Date);
8
+ const stop = ignore?.(value, key, path) ?? false;
9
+ if (isObject && !stop) {
10
+ flattenObjectKeys({ input: value, prefix: path, result, ignore });
11
+ }
12
+ else {
13
+ result[path] = value;
14
+ }
15
+ }
16
+ return result;
17
+ }
@@ -0,0 +1,17 @@
1
+ export declare function getFunctionParamNames(fn: Function): string[];
2
+ export declare function parseMethodsObject(ob: any): string[];
3
+ export declare function getMethodFromString(initializer: any, path: string): any;
4
+ export declare function callMethodFromString(initializer: any, path: string, ...args: any[]): any;
5
+ export declare function inspectMethod(initializer: any, path: string): {
6
+ isFunction: boolean;
7
+ argCount: any;
8
+ paramNames: string[];
9
+ signature: any;
10
+ message?: undefined;
11
+ } | {
12
+ isFunction: boolean;
13
+ message: string;
14
+ argCount?: undefined;
15
+ paramNames?: undefined;
16
+ signature?: undefined;
17
+ };
@@ -0,0 +1,80 @@
1
+ export function getFunctionParamNames(fn) {
2
+ const fnStr = fn.toString();
3
+ // Match function signature: handles regular functions, arrow functions, etc.
4
+ const match = fnStr.match(/^[\w\s]*?\(?([^\)]*)\)?\s*=>|function[^\(]*\(([^\)]*)\)/);
5
+ const args = match ? match[1] || match[2] : '';
6
+ // Split by comma and trim
7
+ return args
8
+ .split(',')
9
+ .map((arg) => arg.trim())
10
+ .filter((arg) => arg.length > 0);
11
+ }
12
+ export function parseMethodsObject(ob) {
13
+ const result = [];
14
+ const visited = new WeakSet();
15
+ const walk = (obj, path = []) => {
16
+ if (typeof obj !== 'object' || obj === null || visited.has(obj))
17
+ return;
18
+ visited.add(obj);
19
+ for (const key of Object.keys(obj)) {
20
+ const value = obj[key];
21
+ const currentPath = [...path, key];
22
+ if (typeof value === 'function') {
23
+ result.push(currentPath.join('.'));
24
+ }
25
+ else if (typeof value === 'object') {
26
+ walk(value, currentPath);
27
+ }
28
+ }
29
+ };
30
+ walk(ob);
31
+ return result;
32
+ }
33
+ export function getMethodFromString(initializer, path) {
34
+ const parts = path.split('.');
35
+ let current = initializer;
36
+ for (const part of parts) {
37
+ if (current && part in current) {
38
+ current = current[part];
39
+ }
40
+ else {
41
+ throw new Error(`Invalid path: ${path}`);
42
+ }
43
+ }
44
+ return current;
45
+ }
46
+ export function callMethodFromString(initializer, path, ...args) {
47
+ const fn = getMethodFromString(initializer, path);
48
+ if (typeof fn === 'function') {
49
+ return fn(...args);
50
+ }
51
+ else {
52
+ throw new Error(`Path does not point to a function: ${path}`);
53
+ }
54
+ }
55
+ export function inspectMethod(initializer, path) {
56
+ const parts = path.split('.');
57
+ let current = initializer;
58
+ for (const part of parts) {
59
+ if (current && part in current) {
60
+ current = current[part];
61
+ }
62
+ else {
63
+ throw new Error(`Invalid faker path: ${path}`);
64
+ }
65
+ }
66
+ if (typeof current === 'function') {
67
+ return {
68
+ isFunction: true,
69
+ argCount: current.length,
70
+ paramNames: getFunctionParamNames(current),
71
+ signature: current.toString().split('\n')[0] // First line of function
72
+ };
73
+ }
74
+ else {
75
+ return {
76
+ isFunction: false,
77
+ message: 'Not a function'
78
+ };
79
+ }
80
+ }
@@ -0,0 +1,10 @@
1
+ export * from "./clone-object.js";
2
+ export * from "./coerce-numeric-strings.js";
3
+ export * from "./is-colon-separated.js";
4
+ export * from "./parse-string-to-object.js";
5
+ export * from "./escape-html.js";
6
+ export * from "./flatten-deep.js";
7
+ export * from "./flatten-object-keys.js";
8
+ export * from "./map-filter.js";
9
+ export * from "./omit-keys-deep.js";
10
+ export * from "./style/index.js";
@@ -0,0 +1,10 @@
1
+ export * from "./clone-object.js";
2
+ export * from "./coerce-numeric-strings.js";
3
+ export * from "./is-colon-separated.js";
4
+ export * from "./parse-string-to-object.js";
5
+ export * from "./escape-html.js";
6
+ export * from "./flatten-deep.js";
7
+ export * from "./flatten-object-keys.js";
8
+ export * from "./map-filter.js";
9
+ export * from "./omit-keys-deep.js";
10
+ export * from "./style/index.js";
@@ -0,0 +1 @@
1
+ export declare function isColonSeparated(str: string): boolean;
@@ -0,0 +1,3 @@
1
+ export function isColonSeparated(str) {
2
+ return (str.match(/:/g) || []).length === 1;
3
+ }
@@ -0,0 +1 @@
1
+ export declare function mapFilter<T, U>(array: T[], mapper: (item: T, index: number) => U | undefined | null): U[];
@@ -0,0 +1,10 @@
1
+ export function mapFilter(array, mapper) {
2
+ const result = [];
3
+ for (let i = 0; i < array.length; i++) {
4
+ const mapped = mapper(array[i], i);
5
+ if (mapped !== undefined && mapped !== null) {
6
+ result.push(mapped);
7
+ }
8
+ }
9
+ return result;
10
+ }
@@ -0,0 +1,9 @@
1
+ export interface TrimOptions {
2
+ omitKeys?: string[];
3
+ stripNull?: boolean;
4
+ stripUndefined?: boolean;
5
+ stripEmptyStrings?: boolean;
6
+ stripEmptyArrays?: boolean;
7
+ stripEmptyObjects?: boolean;
8
+ }
9
+ export declare function omitKeysDeep(obj: Record<string, any>, options?: TrimOptions): Record<string, any>;
@@ -0,0 +1,43 @@
1
+ export function omitKeysDeep(obj, options = {}) {
2
+ const { omitKeys = [], stripNull = true, stripUndefined = true, stripEmptyStrings = false, stripEmptyArrays = false, stripEmptyObjects = false, } = options;
3
+ const omitPaths = new Set(omitKeys);
4
+ // const clone = JSON.parse(JSON.stringify(obj));
5
+ function recurse(o, path = []) {
6
+ if (Array.isArray(o)) {
7
+ const cleanedArray = o
8
+ .map((item, i) => recurse(item, path.concat(String(i))))
9
+ .filter((v) => {
10
+ return !shouldStrip(v);
11
+ });
12
+ return cleanedArray;
13
+ }
14
+ if (typeof o === "object" && o !== null) {
15
+ const result = {};
16
+ for (const [k, v] of Object.entries(o)) {
17
+ const fullPath = path.concat(k).join(".");
18
+ if (omitPaths.has(fullPath))
19
+ continue;
20
+ const value = recurse(v, path.concat(k));
21
+ if (!shouldStrip(value)) {
22
+ result[k] = value;
23
+ }
24
+ }
25
+ return result;
26
+ }
27
+ return o;
28
+ }
29
+ function shouldStrip(value) {
30
+ return ((stripUndefined && value === undefined) ||
31
+ (stripNull && value === null) ||
32
+ (stripEmptyStrings && value === "") ||
33
+ (stripEmptyArrays && Array.isArray(value) && value.length === 0) ||
34
+ (stripEmptyObjects && isEmptyObject(value)));
35
+ }
36
+ return recurse(obj);
37
+ }
38
+ function isEmptyObject(value) {
39
+ return (typeof value === "object" &&
40
+ value !== null &&
41
+ !Array.isArray(value) &&
42
+ Object.keys(value).length === 0);
43
+ }
@@ -0,0 +1 @@
1
+ export declare function parseStringToObject(input: string): Record<string, string>;
@@ -0,0 +1,8 @@
1
+ export function parseStringToObject(input) {
2
+ return input.split(',').reduce((acc, pair) => {
3
+ const [key, value] = pair.split(':').map((s) => s.trim());
4
+ if (key)
5
+ acc[key] = value;
6
+ return acc;
7
+ }, {});
8
+ }
@@ -0,0 +1 @@
1
+ export * from "./parse-border-string.js";
@@ -0,0 +1 @@
1
+ export * from "./parse-border-string.js";
@@ -0,0 +1,5 @@
1
+ export declare function parseBorderString(border: string): {
2
+ width: string;
3
+ style: string;
4
+ color: string;
5
+ };
@@ -0,0 +1,8 @@
1
+ export function parseBorderString(border) {
2
+ const regex = /^([\d.]+[a-z%]+)\s+(\w+)\s+(.+)$/;
3
+ const match = border.match(regex);
4
+ if (!match)
5
+ return { width: "", style: "", color: "" };
6
+ const [, width, style, color] = match;
7
+ return { width, style, color };
8
+ }
@@ -0,0 +1 @@
1
+ export declare function deepMerge<T extends object, U extends object>(target: T, source: U): T & U;
@@ -0,0 +1,18 @@
1
+ export function deepMerge(target, source) {
2
+ const result = { ...target };
3
+ for (const key in source) {
4
+ const sourceValue = source[key];
5
+ const targetValue = target[key];
6
+ if (sourceValue &&
7
+ targetValue &&
8
+ typeof sourceValue === "object" &&
9
+ typeof targetValue === "object" &&
10
+ !Array.isArray(sourceValue)) {
11
+ result[key] = deepMerge(targetValue, sourceValue);
12
+ }
13
+ else {
14
+ result[key] = sourceValue;
15
+ }
16
+ }
17
+ return result;
18
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./process-data-in-chunks.js";
2
+ export * from "./deep-merge.js";
@@ -0,0 +1,2 @@
1
+ export * from "./process-data-in-chunks.js";
2
+ export * from "./deep-merge.js";
@@ -0,0 +1,5 @@
1
+ export declare function processInChunks<T>(data: T[], chunkSize: number, processChunk: (chunk: T[]) => Promise<{
2
+ ok: boolean;
3
+ error?: string;
4
+ }>, logger?: (level: "info" | "error", message: string, meta?: any) => void): Promise<any>;
5
+ export declare function arrayChunk<T>(arr: T[], size: number, logger?: (level: "info" | "error", message: string, meta?: any) => void): T[][];
@@ -0,0 +1,21 @@
1
+ export async function processInChunks(data, chunkSize, processChunk, logger = () => { }) {
2
+ for (let i = 0; i < data.length; i += chunkSize) {
3
+ const chunk = data.slice(i, i + chunkSize);
4
+ logger("info", `Processing chunk ${i}-${i + chunkSize}...`);
5
+ const res = await processChunk(chunk);
6
+ if (!res.ok) {
7
+ logger("error", `Chunk ${i}-${i + chunkSize} failed:`, res.error);
8
+ return res;
9
+ }
10
+ logger("info", `Successfully processed batch ${i}-${i + chunkSize}`);
11
+ }
12
+ return { ok: true, message: "All chunks processed successfully." };
13
+ }
14
+ export function arrayChunk(arr, size, logger = () => { }) {
15
+ const chunks = [];
16
+ for (let i = 0; i < arr.length; i += size) {
17
+ chunks.push(arr.slice(i, i + size));
18
+ }
19
+ logger("info", `Split array into ${chunks.length} chunks of size ${size}`);
20
+ return chunks;
21
+ }
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@pogodisco/ts-kit",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "license": "MIT",
9
+ "author": "Jakub Bystroński",
10
+ "description": "typescript utility kit",
11
+ "keywords": [
12
+ "tools",
13
+ "utilities",
14
+ "typescript"
15
+ ],
16
+ "license": "MIT",
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "import": "./dist/index.js",
22
+ "types": "./dist/index.d.ts"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "scripts": {
29
+ "prepublishOnly": "npm run build",
30
+ "build": "tsc",
31
+ "clean": "rm -rf dist"
32
+ },
33
+ "dependencies": {
34
+ "date-fns": "^4.1.0"
35
+ },
36
+ "devDependencies": {
37
+ "typescript": "^5.9.3"
38
+ }
39
+ }