@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.
- package/dist/accessors/get-at-path.d.ts +1 -0
- package/dist/accessors/get-at-path.js +13 -0
- package/dist/accessors/index.d.ts +6 -0
- package/dist/accessors/index.js +6 -0
- package/dist/accessors/push-to-nested-array.d.ts +1 -0
- package/dist/accessors/push-to-nested-array.js +16 -0
- package/dist/accessors/push-unique-to-array.d.ts +1 -0
- package/dist/accessors/push-unique-to-array.js +5 -0
- package/dist/accessors/select-map.d.ts +1 -0
- package/dist/accessors/select-map.js +5 -0
- package/dist/accessors/set-at-path.d.ts +1 -0
- package/dist/accessors/set-at-path.js +30 -0
- package/dist/accessors/set-deep-object-value.d.ts +1 -0
- package/dist/accessors/set-deep-object-value.js +12 -0
- package/dist/array/index.d.ts +2 -0
- package/dist/array/index.js +2 -0
- package/dist/array/random-from-array.d.ts +1 -0
- package/dist/array/random-from-array.js +6 -0
- package/dist/array/random-subset-from-array.d.ts +1 -0
- package/dist/array/random-subset-from-array.js +12 -0
- package/dist/data/file-content-types.d.ts +8 -0
- package/dist/data/file-content-types.js +61 -0
- package/dist/data/index.d.ts +1 -0
- package/dist/data/index.js +1 -0
- package/dist/date/format-smart-date.d.ts +8 -0
- package/dist/date/format-smart-date.js +32 -0
- package/dist/date/index.d.ts +1 -0
- package/dist/date/index.js +1 -0
- package/dist/finance/index.d.ts +17 -0
- package/dist/finance/index.js +52 -0
- package/dist/format/create-id-from-date.d.ts +1 -0
- package/dist/format/create-id-from-date.js +4 -0
- package/dist/format/format-capitalize-string.d.ts +1 -0
- package/dist/format/format-capitalize-string.js +3 -0
- package/dist/format/format-size.d.ts +1 -0
- package/dist/format/format-size.js +11 -0
- package/dist/format/format-unit-suffix.d.ts +1 -0
- package/dist/format/format-unit-suffix.js +6 -0
- package/dist/format/format-url.d.ts +1 -0
- package/dist/format/format-url.js +8 -0
- package/dist/format/index.d.ts +12 -0
- package/dist/format/index.js +12 -0
- package/dist/format/replace-last-sement.d.ts +1 -0
- package/dist/format/replace-last-sement.js +13 -0
- package/dist/format/sanitize.d.ts +11 -0
- package/dist/format/sanitize.js +53 -0
- package/dist/format/strip-slashes.d.ts +1 -0
- package/dist/format/strip-slashes.js +1 -0
- package/dist/format/strip-trailing-slashes.d.ts +1 -0
- package/dist/format/strip-trailing-slashes.js +1 -0
- package/dist/format/to-kebab-case.d.ts +1 -0
- package/dist/format/to-kebab-case.js +7 -0
- package/dist/format/trim-whitespace.d.ts +1 -0
- package/dist/format/trim-whitespace.js +1 -0
- package/dist/format/truncate-text.d.ts +1 -0
- package/dist/format/truncate-text.js +5 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/parsers/clone-object.d.ts +1 -0
- package/dist/parsers/clone-object.js +3 -0
- package/dist/parsers/coerce-numeric-strings.d.ts +1 -0
- package/dist/parsers/coerce-numeric-strings.js +16 -0
- package/dist/parsers/escape-html.d.ts +1 -0
- package/dist/parsers/escape-html.js +8 -0
- package/dist/parsers/flatten-deep.d.ts +1 -0
- package/dist/parsers/flatten-deep.js +3 -0
- package/dist/parsers/flatten-object-keys.d.ts +8 -0
- package/dist/parsers/flatten-object-keys.js +17 -0
- package/dist/parsers/fn-parser.d.ts +17 -0
- package/dist/parsers/fn-parser.js +80 -0
- package/dist/parsers/index.d.ts +10 -0
- package/dist/parsers/index.js +10 -0
- package/dist/parsers/is-colon-separated.d.ts +1 -0
- package/dist/parsers/is-colon-separated.js +3 -0
- package/dist/parsers/map-filter.d.ts +1 -0
- package/dist/parsers/map-filter.js +10 -0
- package/dist/parsers/omit-keys-deep.d.ts +9 -0
- package/dist/parsers/omit-keys-deep.js +43 -0
- package/dist/parsers/parse-string-to-object.d.ts +1 -0
- package/dist/parsers/parse-string-to-object.js +8 -0
- package/dist/parsers/style/index.d.ts +1 -0
- package/dist/parsers/style/index.js +1 -0
- package/dist/parsers/style/parse-border-string.d.ts +5 -0
- package/dist/parsers/style/parse-border-string.js +8 -0
- package/dist/processors/deep-merge.d.ts +1 -0
- package/dist/processors/deep-merge.js +18 -0
- package/dist/processors/index.d.ts +2 -0
- package/dist/processors/index.js +2 -0
- package/dist/processors/process-data-in-chunks.d.ts +5 -0
- package/dist/processors/process-data-in-chunks.js +21 -0
- 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 @@
|
|
|
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 @@
|
|
|
1
|
+
export declare function selectMap(map: Record<string, string>): (key: string) => string | undefined;
|
|
@@ -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 @@
|
|
|
1
|
+
export declare function randomFromArray<T>(arr: T[]): T | undefined;
|
|
@@ -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,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 @@
|
|
|
1
|
+
export declare function capitalize(str: string): string;
|
|
@@ -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 @@
|
|
|
1
|
+
export declare function sanitizeForUrl(input: string, separator?: '-' | '_'): string;
|
|
@@ -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 @@
|
|
|
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;
|
package/dist/index.d.ts
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";
|
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 @@
|
|
|
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 @@
|
|
|
1
|
+
export declare function flattenDeep(obj: any): any[];
|
|
@@ -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 @@
|
|
|
1
|
+
export declare function mapFilter<T, U>(array: T[], mapper: (item: T, index: number) => U | undefined | null): U[];
|
|
@@ -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 @@
|
|
|
1
|
+
export * from "./parse-border-string.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./parse-border-string.js";
|
|
@@ -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,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
|
+
}
|