ayiin 2.0.49 → 2.0.50
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/methods/async.d.ts +16 -0
- package/dist/methods/async.js +31 -0
- package/dist/methods/currency.d.ts +12 -0
- package/dist/methods/currency.js +20 -0
- package/dist/methods/dates.d.ts +42 -0
- package/dist/methods/dates.js +78 -0
- package/dist/methods/files.d.ts +15 -0
- package/dist/methods/files.js +26 -0
- package/dist/methods/index.d.ts +10 -3
- package/dist/methods/index.js +18 -4
- package/dist/methods/limiter.d.ts +3 -2
- package/dist/methods/limiter.js +3 -4
- package/dist/methods/objects.d.ts +15 -0
- package/dist/methods/objects.js +21 -0
- package/dist/methods/random.d.ts +22 -0
- package/dist/methods/random.js +39 -0
- package/dist/methods/strings.d.ts +27 -0
- package/dist/methods/strings.js +56 -0
- package/dist/methods/validation.d.ts +16 -0
- package/dist/methods/validation.js +28 -0
- package/package.json +1 -1
- package/dist/methods/tools.d.ts +0 -87
- package/dist/methods/tools.js +0 -192
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare class Async {
|
|
2
|
+
/**
|
|
3
|
+
* Sleep for a given number of milliseconds
|
|
4
|
+
* @param {number} ms - milliseconds to sleep
|
|
5
|
+
* @returns {Promise<void>}
|
|
6
|
+
*/
|
|
7
|
+
sleep: (ms: number) => Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Retry a function with a given number of retries
|
|
10
|
+
* @param {function} fn - function to retry
|
|
11
|
+
* @param {number} retries - number of retries
|
|
12
|
+
* @returns {Promise<T>}
|
|
13
|
+
*/
|
|
14
|
+
retry: <T>(fn: () => Promise<T>, retries?: number) => Promise<T>;
|
|
15
|
+
}
|
|
16
|
+
export default Async;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class Async {
|
|
4
|
+
/**
|
|
5
|
+
* Sleep for a given number of milliseconds
|
|
6
|
+
* @param {number} ms - milliseconds to sleep
|
|
7
|
+
* @returns {Promise<void>}
|
|
8
|
+
*/
|
|
9
|
+
sleep = (ms) => {
|
|
10
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Retry a function with a given number of retries
|
|
14
|
+
* @param {function} fn - function to retry
|
|
15
|
+
* @param {number} retries - number of retries
|
|
16
|
+
* @returns {Promise<T>}
|
|
17
|
+
*/
|
|
18
|
+
retry = async (fn, retries = 3) => {
|
|
19
|
+
let error;
|
|
20
|
+
for (let i = 0; i < retries; i++) {
|
|
21
|
+
try {
|
|
22
|
+
return await fn();
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
error = err;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
throw error;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
exports.default = Async;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare class Currency {
|
|
2
|
+
/**
|
|
3
|
+
* Format money ke string sesuai locale
|
|
4
|
+
* @memberof Random
|
|
5
|
+
* @param {number | string} amount - jumlah uang
|
|
6
|
+
* @param {Intl.LocalesArgument} locales - default "id-ID"
|
|
7
|
+
* @param {Intl.NumberFormatOptions} options - default currency IDR
|
|
8
|
+
* @returns {string} string
|
|
9
|
+
*/
|
|
10
|
+
formatMoney: (amount: number | string, locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions) => string;
|
|
11
|
+
}
|
|
12
|
+
export default Currency;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class Currency {
|
|
4
|
+
/**
|
|
5
|
+
* Format money ke string sesuai locale
|
|
6
|
+
* @memberof Random
|
|
7
|
+
* @param {number | string} amount - jumlah uang
|
|
8
|
+
* @param {Intl.LocalesArgument} locales - default "id-ID"
|
|
9
|
+
* @param {Intl.NumberFormatOptions} options - default currency IDR
|
|
10
|
+
* @returns {string} string
|
|
11
|
+
*/
|
|
12
|
+
formatMoney = (amount, locales = "id-ID", options = {
|
|
13
|
+
style: "currency",
|
|
14
|
+
currency: "IDR",
|
|
15
|
+
minimumFractionDigits: 0,
|
|
16
|
+
}) => {
|
|
17
|
+
return new Intl.NumberFormat(locales, options).format(Number(amount));
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
exports.default = Currency;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { DurationInput } from "../types";
|
|
2
|
+
declare class Dates {
|
|
3
|
+
/**
|
|
4
|
+
* Format tanggal ke string sesuai locale
|
|
5
|
+
* @param {Date} date
|
|
6
|
+
* @param {Intl.LocalesArgument} locales - default "id-ID"
|
|
7
|
+
* @returns {string} string
|
|
8
|
+
*/
|
|
9
|
+
formatDate: (date: Date, locales?: Intl.LocalesArgument) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Hitung waktu relatif (misalnya "5 menit lalu")
|
|
12
|
+
* @param {Date} date
|
|
13
|
+
* @returns {string} string
|
|
14
|
+
*/
|
|
15
|
+
timeAgo: (date: Date) => string;
|
|
16
|
+
/**
|
|
17
|
+
* Tambahkan menit ke tanggal
|
|
18
|
+
* @param {Date} date
|
|
19
|
+
* @param {number} minutes - menit untuk ditambahkan
|
|
20
|
+
* @returns {Date} tanggal baru
|
|
21
|
+
*/
|
|
22
|
+
addMinutes: (date: Date, minutes: number) => Date;
|
|
23
|
+
/**
|
|
24
|
+
* Cek apakah tanggal telah berakhir
|
|
25
|
+
* @param {Date} date
|
|
26
|
+
* @returns {boolean} true jika tanggal telah berakhir, false jika belum
|
|
27
|
+
*/
|
|
28
|
+
isExpired: (date: Date) => boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Konversi waktu ke milidetik
|
|
31
|
+
* @param {DurationInput} duration
|
|
32
|
+
* @returns {number} milidetik
|
|
33
|
+
*/
|
|
34
|
+
toMilliseconds: ({ hours, minutes, seconds, }: DurationInput) => number;
|
|
35
|
+
/**
|
|
36
|
+
* Format waktu sisa ke string
|
|
37
|
+
* @param {number} ms - milisekund
|
|
38
|
+
* @returns {string} string
|
|
39
|
+
*/
|
|
40
|
+
formatRemainingTime: (ms: number) => string;
|
|
41
|
+
}
|
|
42
|
+
export default Dates;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class Dates {
|
|
4
|
+
/**
|
|
5
|
+
* Format tanggal ke string sesuai locale
|
|
6
|
+
* @param {Date} date
|
|
7
|
+
* @param {Intl.LocalesArgument} locales - default "id-ID"
|
|
8
|
+
* @returns {string} string
|
|
9
|
+
*/
|
|
10
|
+
formatDate = (date, locales = "id-ID") => new Intl.DateTimeFormat(locales, {
|
|
11
|
+
year: "numeric",
|
|
12
|
+
month: "long",
|
|
13
|
+
day: "numeric",
|
|
14
|
+
hour: "2-digit",
|
|
15
|
+
minute: "2-digit",
|
|
16
|
+
}).format(date);
|
|
17
|
+
/**
|
|
18
|
+
* Hitung waktu relatif (misalnya "5 menit lalu")
|
|
19
|
+
* @param {Date} date
|
|
20
|
+
* @returns {string} string
|
|
21
|
+
*/
|
|
22
|
+
timeAgo = (date) => {
|
|
23
|
+
const diff = Date.now() - date.getTime();
|
|
24
|
+
const seconds = Math.floor(diff / 1000);
|
|
25
|
+
if (seconds < 60)
|
|
26
|
+
return `${seconds} detik lalu`;
|
|
27
|
+
const minutes = Math.floor(seconds / 60);
|
|
28
|
+
if (minutes < 60)
|
|
29
|
+
return `${minutes} menit lalu`;
|
|
30
|
+
const hours = Math.floor(minutes / 60);
|
|
31
|
+
if (hours < 24)
|
|
32
|
+
return `${hours} jam lalu`;
|
|
33
|
+
const days = Math.floor(hours / 24);
|
|
34
|
+
return `${days} hari lalu`;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Tambahkan menit ke tanggal
|
|
38
|
+
* @param {Date} date
|
|
39
|
+
* @param {number} minutes - menit untuk ditambahkan
|
|
40
|
+
* @returns {Date} tanggal baru
|
|
41
|
+
*/
|
|
42
|
+
addMinutes = (date, minutes) => {
|
|
43
|
+
return new Date(date.getTime() + minutes * 60_000);
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Cek apakah tanggal telah berakhir
|
|
47
|
+
* @param {Date} date
|
|
48
|
+
* @returns {boolean} true jika tanggal telah berakhir, false jika belum
|
|
49
|
+
*/
|
|
50
|
+
isExpired = (date) => {
|
|
51
|
+
return date.getTime() < Date.now();
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Konversi waktu ke milidetik
|
|
55
|
+
* @param {DurationInput} duration
|
|
56
|
+
* @returns {number} milidetik
|
|
57
|
+
*/
|
|
58
|
+
toMilliseconds = ({ hours = 0, minutes = 0, seconds = 0, }) => {
|
|
59
|
+
return (hours * 3600 + minutes * 60 + seconds) * 1000;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Format waktu sisa ke string
|
|
63
|
+
* @param {number} ms - milisekund
|
|
64
|
+
* @returns {string} string
|
|
65
|
+
*/
|
|
66
|
+
formatRemainingTime = (ms) => {
|
|
67
|
+
if (ms <= 0)
|
|
68
|
+
return "0 detik";
|
|
69
|
+
const totalSeconds = Math.floor(ms / 1000);
|
|
70
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
71
|
+
const seconds = totalSeconds % 60;
|
|
72
|
+
if (minutes > 0) {
|
|
73
|
+
return `${minutes} menit ${seconds} detik lagi`;
|
|
74
|
+
}
|
|
75
|
+
return `${seconds} detik lagi`;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
exports.default = Dates;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare class Files {
|
|
2
|
+
/**
|
|
3
|
+
* Pastikan direktori ada
|
|
4
|
+
* @param {string} path - path direktori
|
|
5
|
+
* @returns {Promise<void>}
|
|
6
|
+
*/
|
|
7
|
+
ensureDir: (path: string) => Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Baca file JSON
|
|
10
|
+
* @param {string} path - path file
|
|
11
|
+
* @returns {Promise<T>} data JSON
|
|
12
|
+
*/
|
|
13
|
+
readJSON: <T>(path: string) => Promise<T>;
|
|
14
|
+
}
|
|
15
|
+
export default Files;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
7
|
+
class Files {
|
|
8
|
+
/**
|
|
9
|
+
* Pastikan direktori ada
|
|
10
|
+
* @param {string} path - path direktori
|
|
11
|
+
* @returns {Promise<void>}
|
|
12
|
+
*/
|
|
13
|
+
ensureDir = async (path) => {
|
|
14
|
+
await promises_1.default.mkdir(path, { recursive: true });
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Baca file JSON
|
|
18
|
+
* @param {string} path - path file
|
|
19
|
+
* @returns {Promise<T>} data JSON
|
|
20
|
+
*/
|
|
21
|
+
readJSON = async (path) => {
|
|
22
|
+
const data = await promises_1.default.readFile(path, "utf-8");
|
|
23
|
+
return JSON.parse(data);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
exports.default = Files;
|
package/dist/methods/index.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import Async from "./async";
|
|
1
2
|
import Crypt from "./crypt";
|
|
2
|
-
import
|
|
3
|
+
import Currency from "./currency";
|
|
4
|
+
import Dates from "./dates";
|
|
5
|
+
import Files from "./files";
|
|
6
|
+
import Limiter from "./limiter";
|
|
7
|
+
import Objects from "./objects";
|
|
8
|
+
import Random from "./random";
|
|
3
9
|
import ResponseApi from "./response";
|
|
4
|
-
import
|
|
10
|
+
import Strings from "./strings";
|
|
11
|
+
import Validation from "./validation";
|
|
5
12
|
declare class Methods {
|
|
6
13
|
}
|
|
7
|
-
interface Methods extends Crypt,
|
|
14
|
+
interface Methods extends Async, Crypt, Currency, Dates, Files, Limiter, Objects, Random, ResponseApi, Strings, Validation {
|
|
8
15
|
}
|
|
9
16
|
export default Methods;
|
package/dist/methods/index.js
CHANGED
|
@@ -3,15 +3,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const async_1 = __importDefault(require("./async"));
|
|
6
7
|
const crypt_1 = __importDefault(require("./crypt"));
|
|
7
|
-
const
|
|
8
|
+
const currency_1 = __importDefault(require("./currency"));
|
|
9
|
+
const dates_1 = __importDefault(require("./dates"));
|
|
10
|
+
const files_1 = __importDefault(require("./files"));
|
|
11
|
+
const limiter_1 = __importDefault(require("./limiter"));
|
|
12
|
+
const objects_1 = __importDefault(require("./objects"));
|
|
13
|
+
const random_1 = __importDefault(require("./random"));
|
|
8
14
|
const response_1 = __importDefault(require("./response"));
|
|
9
|
-
const
|
|
15
|
+
const strings_1 = __importDefault(require("./strings"));
|
|
16
|
+
const validation_1 = __importDefault(require("./validation"));
|
|
10
17
|
class Methods {
|
|
11
18
|
}
|
|
12
19
|
// copy instance properties
|
|
13
|
-
Object.assign(Methods.prototype, new
|
|
20
|
+
Object.assign(Methods.prototype, new async_1.default());
|
|
14
21
|
Object.assign(Methods.prototype, new crypt_1.default());
|
|
22
|
+
Object.assign(Methods.prototype, new currency_1.default());
|
|
23
|
+
Object.assign(Methods.prototype, new dates_1.default());
|
|
24
|
+
Object.assign(Methods.prototype, new files_1.default());
|
|
25
|
+
Object.assign(Methods.prototype, new limiter_1.default());
|
|
26
|
+
Object.assign(Methods.prototype, new objects_1.default());
|
|
27
|
+
Object.assign(Methods.prototype, new random_1.default());
|
|
15
28
|
Object.assign(Methods.prototype, new response_1.default());
|
|
16
|
-
Object.assign(Methods.prototype, new
|
|
29
|
+
Object.assign(Methods.prototype, new strings_1.default());
|
|
30
|
+
Object.assign(Methods.prototype, new validation_1.default());
|
|
17
31
|
exports.default = Methods;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RequestHandler } from "express";
|
|
2
2
|
import { RateLimiterOptions } from "../types";
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import Dates from "./dates";
|
|
4
|
+
declare class Limiter extends Dates {
|
|
5
5
|
createRateLimit: (options: RateLimiterOptions) => RequestHandler;
|
|
6
6
|
}
|
|
7
|
+
export default Limiter;
|
package/dist/methods/limiter.js
CHANGED
|
@@ -3,8 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
|
|
7
|
-
const tools_1 = __importDefault(require("./tools"));
|
|
6
|
+
const dates_1 = __importDefault(require("./dates"));
|
|
8
7
|
// 🔹 MemoryStore default
|
|
9
8
|
class MemoryStore {
|
|
10
9
|
store = new Map();
|
|
@@ -45,7 +44,7 @@ class MemoryStore {
|
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
// 🔹 Class Limiter
|
|
48
|
-
class Limiter extends
|
|
47
|
+
class Limiter extends dates_1.default {
|
|
49
48
|
createRateLimit = (options) => {
|
|
50
49
|
const store = options.store ?? new MemoryStore();
|
|
51
50
|
if (options.refreshOnStart) {
|
|
@@ -146,4 +145,4 @@ class Limiter extends tools_1.default {
|
|
|
146
145
|
};
|
|
147
146
|
};
|
|
148
147
|
}
|
|
149
|
-
exports.
|
|
148
|
+
exports.default = Limiter;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare class Objects {
|
|
2
|
+
/**
|
|
3
|
+
* Deep clone objectek
|
|
4
|
+
* @param {T} obj
|
|
5
|
+
* @returns {T
|
|
6
|
+
*/
|
|
7
|
+
deepClone: <T>(obj: T) => T;
|
|
8
|
+
/**
|
|
9
|
+
* Cek apakah objectek kosong
|
|
10
|
+
* @param {object} obj
|
|
11
|
+
* @returns {boolean} true jika objectek kosong, false jika tidak
|
|
12
|
+
*/
|
|
13
|
+
isEmptyObject: (obj: object) => boolean;
|
|
14
|
+
}
|
|
15
|
+
export default Objects;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class Objects {
|
|
4
|
+
/**
|
|
5
|
+
* Deep clone objectek
|
|
6
|
+
* @param {T} obj
|
|
7
|
+
* @returns {T
|
|
8
|
+
*/
|
|
9
|
+
deepClone = (obj) => {
|
|
10
|
+
return JSON.parse(JSON.stringify(obj));
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Cek apakah objectek kosong
|
|
14
|
+
* @param {object} obj
|
|
15
|
+
* @returns {boolean} true jika objectek kosong, false jika tidak
|
|
16
|
+
*/
|
|
17
|
+
isEmptyObject = (obj) => {
|
|
18
|
+
return Object.keys(obj).length === 0;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
exports.default = Objects;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare class Random {
|
|
2
|
+
/**
|
|
3
|
+
* Generate UUID v4 sederhana
|
|
4
|
+
* @returns {string}
|
|
5
|
+
*/
|
|
6
|
+
randomUuid: () => string;
|
|
7
|
+
/**
|
|
8
|
+
* Pick a random from array
|
|
9
|
+
* @param {T[]} array
|
|
10
|
+
* @memberof Random
|
|
11
|
+
* @returns {T} item acak dari array
|
|
12
|
+
*/
|
|
13
|
+
randomItem: <T>(array: T[]) => T | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Ambil beberapa item acak unik dari array
|
|
16
|
+
* @param {T[]} array
|
|
17
|
+
* @param {number} count - jumlah item
|
|
18
|
+
* @returns {T[]} array item acak unik dari array
|
|
19
|
+
*/
|
|
20
|
+
randomMany: <T>(array: T[], count: number | string) => T[];
|
|
21
|
+
}
|
|
22
|
+
export default Random;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class Random {
|
|
4
|
+
/**
|
|
5
|
+
* Generate UUID v4 sederhana
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
randomUuid = () => {
|
|
9
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
10
|
+
const r = (Math.random() * 16) | 0;
|
|
11
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
12
|
+
return v.toString(16);
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Pick a random from array
|
|
17
|
+
* @param {T[]} array
|
|
18
|
+
* @memberof Random
|
|
19
|
+
* @returns {T} item acak dari array
|
|
20
|
+
*/
|
|
21
|
+
randomItem = (array) => {
|
|
22
|
+
return array[Math.floor(Math.random() * array.length)];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Ambil beberapa item acak unik dari array
|
|
26
|
+
* @param {T[]} array
|
|
27
|
+
* @param {number} count - jumlah item
|
|
28
|
+
* @returns {T[]} array item acak unik dari array
|
|
29
|
+
*/
|
|
30
|
+
randomMany = (array, count) => {
|
|
31
|
+
const copy = [...array];
|
|
32
|
+
for (let i = copy.length - 1; i > 0; i--) {
|
|
33
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
34
|
+
[copy[i], copy[j]] = [copy[j], copy[i]];
|
|
35
|
+
}
|
|
36
|
+
return copy.slice(0, Number(count));
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
exports.default = Random;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
declare class Strings {
|
|
2
|
+
/**
|
|
3
|
+
* Generate unique ID dengan pilihan tipe
|
|
4
|
+
* @param {"number"|"string"|"mixed"} type - tipe ID (angka, string, atau campuran)
|
|
5
|
+
* @param {number} length - panjang ID (default 8)
|
|
6
|
+
* @returns {string} ID unik acak
|
|
7
|
+
*/
|
|
8
|
+
uniqueId: ({ type, length, prefix, }: {
|
|
9
|
+
type?: "number" | "string" | "mixed";
|
|
10
|
+
length?: number | string;
|
|
11
|
+
prefix?: string;
|
|
12
|
+
}) => string;
|
|
13
|
+
/**
|
|
14
|
+
* Convert string menjadi camelCase
|
|
15
|
+
* @param {string} input - string yang akan diubah
|
|
16
|
+
* @returns {string} camelCase string
|
|
17
|
+
*/
|
|
18
|
+
toCamelCase: (input: string) => string;
|
|
19
|
+
/**
|
|
20
|
+
* Capitalize string (huruf pertama jadi kapital)
|
|
21
|
+
* @param {string} input - string yang akan diubah
|
|
22
|
+
* @returns {string} string dengan huruf pertama kapital
|
|
23
|
+
*/
|
|
24
|
+
capitalize: (input: string) => string;
|
|
25
|
+
slugify: (str: string) => string;
|
|
26
|
+
}
|
|
27
|
+
export default Strings;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class Strings {
|
|
4
|
+
/**
|
|
5
|
+
* Generate unique ID dengan pilihan tipe
|
|
6
|
+
* @param {"number"|"string"|"mixed"} type - tipe ID (angka, string, atau campuran)
|
|
7
|
+
* @param {number} length - panjang ID (default 8)
|
|
8
|
+
* @returns {string} ID unik acak
|
|
9
|
+
*/
|
|
10
|
+
uniqueId = ({ type = "mixed", length = 8, prefix, }) => {
|
|
11
|
+
let chars;
|
|
12
|
+
switch (type) {
|
|
13
|
+
case "number":
|
|
14
|
+
chars = "0123456789";
|
|
15
|
+
break;
|
|
16
|
+
case "string":
|
|
17
|
+
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
18
|
+
break;
|
|
19
|
+
default:
|
|
20
|
+
chars =
|
|
21
|
+
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
22
|
+
}
|
|
23
|
+
let id = "";
|
|
24
|
+
for (let i = 0; i < Number(length); i++) {
|
|
25
|
+
id += chars[Math.floor(Math.random() * chars.length)];
|
|
26
|
+
}
|
|
27
|
+
return prefix ? prefix + id : id;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Convert string menjadi camelCase
|
|
31
|
+
* @param {string} input - string yang akan diubah
|
|
32
|
+
* @returns {string} camelCase string
|
|
33
|
+
*/
|
|
34
|
+
toCamelCase = (input) => {
|
|
35
|
+
return input
|
|
36
|
+
.toLowerCase()
|
|
37
|
+
.replace(/[-_\s]+(.)?/g, (_, chr) => (chr ? chr.toUpperCase() : ""));
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Capitalize string (huruf pertama jadi kapital)
|
|
41
|
+
* @param {string} input - string yang akan diubah
|
|
42
|
+
* @returns {string} string dengan huruf pertama kapital
|
|
43
|
+
*/
|
|
44
|
+
capitalize = (input) => {
|
|
45
|
+
if (!input)
|
|
46
|
+
return "";
|
|
47
|
+
return input.charAt(0).toUpperCase() + input.slice(1);
|
|
48
|
+
};
|
|
49
|
+
slugify = (str) => {
|
|
50
|
+
return str
|
|
51
|
+
.toLowerCase()
|
|
52
|
+
.replace(/\s+/g, "-")
|
|
53
|
+
.replace(/[^\w-]+/g, "");
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
exports.default = Strings;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare class Validation {
|
|
2
|
+
/**
|
|
3
|
+
* Validasi apakah string adalah email
|
|
4
|
+
* @param {string} str
|
|
5
|
+
* @returns {boolean} true jika string adalah email, false jika bukan
|
|
6
|
+
*/
|
|
7
|
+
isEmail: (str: string) => boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Validasi apakah string adalah URL
|
|
10
|
+
* @param {string} str
|
|
11
|
+
* @returns {boolean} true jika string adalah URL, false jika bukan
|
|
12
|
+
*/
|
|
13
|
+
isUrl: (str: string) => boolean;
|
|
14
|
+
isUUID: (str: string) => boolean;
|
|
15
|
+
}
|
|
16
|
+
export default Validation;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class Validation {
|
|
4
|
+
/**
|
|
5
|
+
* Validasi apakah string adalah email
|
|
6
|
+
* @param {string} str
|
|
7
|
+
* @returns {boolean} true jika string adalah email, false jika bukan
|
|
8
|
+
*/
|
|
9
|
+
isEmail = (str) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
|
|
10
|
+
/**
|
|
11
|
+
* Validasi apakah string adalah URL
|
|
12
|
+
* @param {string} str
|
|
13
|
+
* @returns {boolean} true jika string adalah URL, false jika bukan
|
|
14
|
+
*/
|
|
15
|
+
isUrl = (str) => {
|
|
16
|
+
try {
|
|
17
|
+
new URL(str);
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
isUUID = (str) => {
|
|
25
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
exports.default = Validation;
|
package/package.json
CHANGED
package/dist/methods/tools.d.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { DurationInput } from "../types";
|
|
2
|
-
declare class Tools {
|
|
3
|
-
/**
|
|
4
|
-
* Format money ke string sesuai locale
|
|
5
|
-
* @memberof Tools
|
|
6
|
-
* @param {number | string} amount - jumlah uang
|
|
7
|
-
* @param {Intl.LocalesArgument} locales - default "id-ID"
|
|
8
|
-
* @param {Intl.NumberFormatOptions} options - default currency IDR
|
|
9
|
-
* @returns {string} string
|
|
10
|
-
*/
|
|
11
|
-
formatMoney: (amount: number | string, locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions) => string;
|
|
12
|
-
/**
|
|
13
|
-
* Generate unique ID dengan pilihan tipe
|
|
14
|
-
* @param {"number"|"string"|"mixed"} type - tipe ID (angka, string, atau campuran)
|
|
15
|
-
* @param {number} length - panjang ID (default 8)
|
|
16
|
-
* @returns {string} ID unik acak
|
|
17
|
-
*/
|
|
18
|
-
uniqueId: ({ type, length, prefix, }: {
|
|
19
|
-
type?: "number" | "string" | "mixed";
|
|
20
|
-
length?: number | string;
|
|
21
|
-
prefix?: string;
|
|
22
|
-
}) => string;
|
|
23
|
-
/**
|
|
24
|
-
* Generate UUID v4 sederhana
|
|
25
|
-
* @returns {string}
|
|
26
|
-
*/
|
|
27
|
-
randomUuid: () => string;
|
|
28
|
-
/**
|
|
29
|
-
* Pick a random from array
|
|
30
|
-
* @param {T[]} array
|
|
31
|
-
* @memberof Tools
|
|
32
|
-
* @returns {T} item acak dari array
|
|
33
|
-
*/
|
|
34
|
-
randomItem: <T>(array: T[]) => T | undefined;
|
|
35
|
-
/**
|
|
36
|
-
* Ambil beberapa item acak unik dari array
|
|
37
|
-
* @param {T[]} array
|
|
38
|
-
* @param {number} count - jumlah item
|
|
39
|
-
* @returns {T[]} array item acak unik dari array
|
|
40
|
-
*/
|
|
41
|
-
randomMany: <T>(array: T[], count: number | string) => T[];
|
|
42
|
-
/**
|
|
43
|
-
* Validasi apakah string adalah email
|
|
44
|
-
* @param {string} str
|
|
45
|
-
* @returns {boolean} true jika string adalah email, false jika bukan
|
|
46
|
-
*/
|
|
47
|
-
isEmail: (str: string) => boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Validasi apakah string adalah URL
|
|
50
|
-
* @param {string} str
|
|
51
|
-
* @returns {boolean} true jika string adalah URL, false jika bukan
|
|
52
|
-
*/
|
|
53
|
-
isUrl: (str: string) => boolean;
|
|
54
|
-
/**
|
|
55
|
-
* Format tanggal ke string sesuai locale
|
|
56
|
-
* @param {Date} date
|
|
57
|
-
* @param {Intl.LocalesArgument} locales - default "id-ID"
|
|
58
|
-
* @returns {string} string
|
|
59
|
-
*/
|
|
60
|
-
formatDate: (date: Date, locales?: Intl.LocalesArgument) => string;
|
|
61
|
-
/**
|
|
62
|
-
* Hitung waktu relatif (misalnya "5 menit lalu")
|
|
63
|
-
* @param {Date} date
|
|
64
|
-
* @returns {string} string
|
|
65
|
-
*/
|
|
66
|
-
timeAgo: (date: Date) => string;
|
|
67
|
-
/**
|
|
68
|
-
* Convert string menjadi camelCase
|
|
69
|
-
* @param {string} input - string yang akan diubah
|
|
70
|
-
* @returns {string} camelCase string
|
|
71
|
-
*/
|
|
72
|
-
toCamelCase: (input: string) => string;
|
|
73
|
-
/**
|
|
74
|
-
* Capitalize string (huruf pertama jadi kapital)
|
|
75
|
-
* @param {string} input - string yang akan diubah
|
|
76
|
-
* @returns {string} string dengan huruf pertama kapital
|
|
77
|
-
*/
|
|
78
|
-
capitalize: (input: string) => string;
|
|
79
|
-
slugify: (str: string) => string;
|
|
80
|
-
deepClone: <T>(obj: T) => T;
|
|
81
|
-
isEmptyObject: (obj: object) => boolean;
|
|
82
|
-
sleep: (ms: number) => Promise<void>;
|
|
83
|
-
retry: <T>(fn: () => Promise<T>, retries?: number) => Promise<T>;
|
|
84
|
-
toMilliseconds: ({ hours, minutes, seconds, }: DurationInput) => number;
|
|
85
|
-
formatRemainingTime: (ms: number) => string;
|
|
86
|
-
}
|
|
87
|
-
export default Tools;
|
package/dist/methods/tools.js
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
class Tools {
|
|
4
|
-
/**
|
|
5
|
-
* Format money ke string sesuai locale
|
|
6
|
-
* @memberof Tools
|
|
7
|
-
* @param {number | string} amount - jumlah uang
|
|
8
|
-
* @param {Intl.LocalesArgument} locales - default "id-ID"
|
|
9
|
-
* @param {Intl.NumberFormatOptions} options - default currency IDR
|
|
10
|
-
* @returns {string} string
|
|
11
|
-
*/
|
|
12
|
-
formatMoney = (amount, locales = "id-ID", options = {
|
|
13
|
-
style: "currency",
|
|
14
|
-
currency: "IDR",
|
|
15
|
-
minimumFractionDigits: 0,
|
|
16
|
-
}) => {
|
|
17
|
-
return new Intl.NumberFormat(locales, options).format(Number(amount));
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Generate unique ID dengan pilihan tipe
|
|
21
|
-
* @param {"number"|"string"|"mixed"} type - tipe ID (angka, string, atau campuran)
|
|
22
|
-
* @param {number} length - panjang ID (default 8)
|
|
23
|
-
* @returns {string} ID unik acak
|
|
24
|
-
*/
|
|
25
|
-
uniqueId = ({ type = "mixed", length = 8, prefix, }) => {
|
|
26
|
-
let chars;
|
|
27
|
-
switch (type) {
|
|
28
|
-
case "number":
|
|
29
|
-
chars = "0123456789";
|
|
30
|
-
break;
|
|
31
|
-
case "string":
|
|
32
|
-
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
33
|
-
break;
|
|
34
|
-
default:
|
|
35
|
-
chars =
|
|
36
|
-
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
37
|
-
}
|
|
38
|
-
let id = "";
|
|
39
|
-
for (let i = 0; i < Number(length); i++) {
|
|
40
|
-
id += chars[Math.floor(Math.random() * chars.length)];
|
|
41
|
-
}
|
|
42
|
-
return prefix ? prefix + id : id;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Generate UUID v4 sederhana
|
|
46
|
-
* @returns {string}
|
|
47
|
-
*/
|
|
48
|
-
randomUuid = () => {
|
|
49
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
50
|
-
const r = (Math.random() * 16) | 0;
|
|
51
|
-
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
52
|
-
return v.toString(16);
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* Pick a random from array
|
|
57
|
-
* @param {T[]} array
|
|
58
|
-
* @memberof Tools
|
|
59
|
-
* @returns {T} item acak dari array
|
|
60
|
-
*/
|
|
61
|
-
randomItem = (array) => {
|
|
62
|
-
return array[Math.floor(Math.random() * array.length)];
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Ambil beberapa item acak unik dari array
|
|
66
|
-
* @param {T[]} array
|
|
67
|
-
* @param {number} count - jumlah item
|
|
68
|
-
* @returns {T[]} array item acak unik dari array
|
|
69
|
-
*/
|
|
70
|
-
randomMany = (array, count) => {
|
|
71
|
-
const copy = [...array];
|
|
72
|
-
for (let i = copy.length - 1; i > 0; i--) {
|
|
73
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
74
|
-
[copy[i], copy[j]] = [copy[j], copy[i]];
|
|
75
|
-
}
|
|
76
|
-
return copy.slice(0, Number(count));
|
|
77
|
-
};
|
|
78
|
-
/**
|
|
79
|
-
* Validasi apakah string adalah email
|
|
80
|
-
* @param {string} str
|
|
81
|
-
* @returns {boolean} true jika string adalah email, false jika bukan
|
|
82
|
-
*/
|
|
83
|
-
isEmail = (str) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
|
|
84
|
-
/**
|
|
85
|
-
* Validasi apakah string adalah URL
|
|
86
|
-
* @param {string} str
|
|
87
|
-
* @returns {boolean} true jika string adalah URL, false jika bukan
|
|
88
|
-
*/
|
|
89
|
-
isUrl = (str) => {
|
|
90
|
-
try {
|
|
91
|
-
new URL(str);
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
/**
|
|
99
|
-
* Format tanggal ke string sesuai locale
|
|
100
|
-
* @param {Date} date
|
|
101
|
-
* @param {Intl.LocalesArgument} locales - default "id-ID"
|
|
102
|
-
* @returns {string} string
|
|
103
|
-
*/
|
|
104
|
-
formatDate = (date, locales = "id-ID") => new Intl.DateTimeFormat(locales, {
|
|
105
|
-
year: "numeric",
|
|
106
|
-
month: "long",
|
|
107
|
-
day: "numeric",
|
|
108
|
-
hour: "2-digit",
|
|
109
|
-
minute: "2-digit",
|
|
110
|
-
}).format(date);
|
|
111
|
-
/**
|
|
112
|
-
* Hitung waktu relatif (misalnya "5 menit lalu")
|
|
113
|
-
* @param {Date} date
|
|
114
|
-
* @returns {string} string
|
|
115
|
-
*/
|
|
116
|
-
timeAgo = (date) => {
|
|
117
|
-
const diff = Date.now() - date.getTime();
|
|
118
|
-
const seconds = Math.floor(diff / 1000);
|
|
119
|
-
if (seconds < 60)
|
|
120
|
-
return `${seconds} detik lalu`;
|
|
121
|
-
const minutes = Math.floor(seconds / 60);
|
|
122
|
-
if (minutes < 60)
|
|
123
|
-
return `${minutes} menit lalu`;
|
|
124
|
-
const hours = Math.floor(minutes / 60);
|
|
125
|
-
if (hours < 24)
|
|
126
|
-
return `${hours} jam lalu`;
|
|
127
|
-
const days = Math.floor(hours / 24);
|
|
128
|
-
return `${days} hari lalu`;
|
|
129
|
-
};
|
|
130
|
-
/**
|
|
131
|
-
* Convert string menjadi camelCase
|
|
132
|
-
* @param {string} input - string yang akan diubah
|
|
133
|
-
* @returns {string} camelCase string
|
|
134
|
-
*/
|
|
135
|
-
toCamelCase = (input) => {
|
|
136
|
-
return input
|
|
137
|
-
.toLowerCase()
|
|
138
|
-
.replace(/[-_\s]+(.)?/g, (_, chr) => (chr ? chr.toUpperCase() : ""));
|
|
139
|
-
};
|
|
140
|
-
/**
|
|
141
|
-
* Capitalize string (huruf pertama jadi kapital)
|
|
142
|
-
* @param {string} input - string yang akan diubah
|
|
143
|
-
* @returns {string} string dengan huruf pertama kapital
|
|
144
|
-
*/
|
|
145
|
-
capitalize = (input) => {
|
|
146
|
-
if (!input)
|
|
147
|
-
return "";
|
|
148
|
-
return input.charAt(0).toUpperCase() + input.slice(1);
|
|
149
|
-
};
|
|
150
|
-
slugify = (str) => {
|
|
151
|
-
return str
|
|
152
|
-
.toLowerCase()
|
|
153
|
-
.replace(/\s+/g, "-")
|
|
154
|
-
.replace(/[^\w-]+/g, "");
|
|
155
|
-
};
|
|
156
|
-
deepClone = (obj) => {
|
|
157
|
-
return JSON.parse(JSON.stringify(obj));
|
|
158
|
-
};
|
|
159
|
-
isEmptyObject = (obj) => {
|
|
160
|
-
return Object.keys(obj).length === 0;
|
|
161
|
-
};
|
|
162
|
-
sleep = (ms) => {
|
|
163
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
164
|
-
};
|
|
165
|
-
retry = async (fn, retries = 3) => {
|
|
166
|
-
let error;
|
|
167
|
-
for (let i = 0; i < retries; i++) {
|
|
168
|
-
try {
|
|
169
|
-
return await fn();
|
|
170
|
-
}
|
|
171
|
-
catch (err) {
|
|
172
|
-
error = err;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
throw error;
|
|
176
|
-
};
|
|
177
|
-
toMilliseconds = ({ hours = 0, minutes = 0, seconds = 0, }) => {
|
|
178
|
-
return (hours * 3600 + minutes * 60 + seconds) * 1000;
|
|
179
|
-
};
|
|
180
|
-
formatRemainingTime = (ms) => {
|
|
181
|
-
if (ms <= 0)
|
|
182
|
-
return "0 detik";
|
|
183
|
-
const totalSeconds = Math.floor(ms / 1000);
|
|
184
|
-
const minutes = Math.floor(totalSeconds / 60);
|
|
185
|
-
const seconds = totalSeconds % 60;
|
|
186
|
-
if (minutes > 0) {
|
|
187
|
-
return `${minutes} menit ${seconds} detik lagi`;
|
|
188
|
-
}
|
|
189
|
-
return `${seconds} detik lagi`;
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
exports.default = Tools;
|