superjs-core 0.4.4 → 0.6.0
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/CHANGELOG.md +26 -0
- package/CONTRIBUTING.md +1 -1
- package/PUBLISH.md +2 -2
- package/README.md +9 -5
- package/ROADMAP.md +1 -1
- package/SUMMARY.md +6 -2
- package/dist/async/index.d.ts +106 -1
- package/dist/async/index.js +128 -1
- package/dist/async/index.js.map +1 -1
- package/dist/collection/index.d.ts +135 -1
- package/dist/collection/index.js +145 -1
- package/dist/collection/index.js.map +1 -1
- package/dist/color/index.d.ts +79 -1
- package/dist/color/index.js +101 -0
- package/dist/color/index.js.map +1 -1
- package/dist/date/index.d.ts +316 -1
- package/dist/date/index.js +339 -1
- package/dist/date/index.js.map +1 -1
- package/dist/dep-exray/cli.js +95 -43
- package/dist/dep-exray/cli.js.map +1 -1
- package/dist/dep-exray/index.js +48 -34
- package/dist/dep-exray/index.js.map +1 -1
- package/dist/dep-exray/reporter/index.js +48 -34
- package/dist/dep-exray/reporter/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +50 -36
- package/dist/index.js.map +1 -1
- package/dist/isNoRekening-CHSpgD4P.d.ts +167 -0
- package/dist/math/index.d.ts +188 -1
- package/dist/math/index.js +199 -1
- package/dist/math/index.js.map +1 -1
- package/dist/string/index.d.ts +71 -1
- package/dist/string/index.js +94 -0
- package/dist/string/index.js.map +1 -1
- package/dist/validation/index.d.ts +22 -150
- package/dist/validation/index.js +27 -0
- package/dist/validation/index.js.map +1 -1
- package/package.json +2 -6
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates an Indonesian NIK (Nomor Induk Kependudukan / Resident Identity Number).
|
|
3
|
+
*
|
|
4
|
+
* A valid NIK:
|
|
5
|
+
* - Must be exactly 16 digits
|
|
6
|
+
* - Structure: PP CC DD DDMMYY SSSS
|
|
7
|
+
* - PP: Province code (2 digits)
|
|
8
|
+
* - CC: City code (2 digits)
|
|
9
|
+
* - DD: District code (2 digits)
|
|
10
|
+
* - DDMMYY: Birth date (6 digits; for women the day is incremented by 40)
|
|
11
|
+
* - SSSS: Serial number (4 digits)
|
|
12
|
+
* - The birth date must correspond to a valid calendar date
|
|
13
|
+
*
|
|
14
|
+
* @param value - The NIK string (digits only or with dots)
|
|
15
|
+
* @returns `true` if the value is a valid NIK
|
|
16
|
+
*
|
|
17
|
+
* @example isNIK('3201010203940001') // => true (male, born 2 March 1994)
|
|
18
|
+
* @example isNIK('3201015203940001') // => true (female, born 12 March 1994)
|
|
19
|
+
* @example isNIK('1234567890123456') // => false (invalid birth date)
|
|
20
|
+
* @example isNIK('320101') // => false (too short)
|
|
21
|
+
*/
|
|
22
|
+
declare function isNIK(value: string): boolean;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validates an Indonesian NPWP (Nomor Pokok Wajib Pajak / Tax Identification Number).
|
|
26
|
+
*
|
|
27
|
+
* A valid NPWP:
|
|
28
|
+
* - Must be 15 or 16 digits (formatted: `XX.XXX.XXX.X-XXX.XXX` or plain digits)
|
|
29
|
+
* - The last digit is a checksum computed from the preceding digits
|
|
30
|
+
*
|
|
31
|
+
* The checksum uses a weighted-sum algorithm with a repeating weight pattern of
|
|
32
|
+
* `[3, 7, 1]`. The computed checksum must equal the last digit.
|
|
33
|
+
*
|
|
34
|
+
* @param value - The NPWP string (formatted with dots & dash, or plain digits)
|
|
35
|
+
* @returns `true` if the value is a valid NPWP
|
|
36
|
+
*
|
|
37
|
+
* @example isNPWP('12.345.678.9-012.344') // => true
|
|
38
|
+
* @example isNPWP('123456789012344') // => true (plain digits)
|
|
39
|
+
* @example isNPWP('12.345.678.9-012.345') // => false (invalid checksum)
|
|
40
|
+
*/
|
|
41
|
+
declare function isNPWP(value: string): boolean;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Validates a phone number.
|
|
45
|
+
*
|
|
46
|
+
* For Indonesian numbers (`country = 'id'`):
|
|
47
|
+
* - Accepted formats: `08xx…`, `+628xx…`, `628xx…`
|
|
48
|
+
* - Must start with a valid operator prefix:
|
|
49
|
+
* 0811-0819, 0821-0829, 0851-0859, 0877-0879, 0895-0899
|
|
50
|
+
* - 10–13 digits after the country code
|
|
51
|
+
*
|
|
52
|
+
* For generic numbers (`country = 'any'`):
|
|
53
|
+
* - Any string with 10–15 digits is accepted
|
|
54
|
+
*
|
|
55
|
+
* @param value - The phone number string
|
|
56
|
+
* @param country - Country to validate against (`'id'` or `'any'`; default `'id'`)
|
|
57
|
+
* @returns `true` if the value is a valid phone number
|
|
58
|
+
*
|
|
59
|
+
* @example isPhone('08123456789') // => true
|
|
60
|
+
* @example isPhone('+628123456789') // => true
|
|
61
|
+
* @example isPhone('628123456789') // => true
|
|
62
|
+
* @example isPhone('081234567') // => false (too short)
|
|
63
|
+
* @example isPhone('089123456789') // => false (invalid prefix 91)
|
|
64
|
+
*/
|
|
65
|
+
declare function isPhone(value: string, country?: 'id' | 'any'): boolean;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* RFC‑compliant email address validation.
|
|
69
|
+
*
|
|
70
|
+
* Validation rules:
|
|
71
|
+
* - Total length ≤ 254 characters
|
|
72
|
+
* - Local part ≤ 64 characters; supports quoted strings (including escaped
|
|
73
|
+
* characters), unquoted letters / digits / `!#$%&'*+/=?^_`{|}~-`, and dots
|
|
74
|
+
* (no leading, trailing, or consecutive dots)
|
|
75
|
+
* - Domain part ≤ 255 characters; valid DNS labels separated by dots, each
|
|
76
|
+
* label ≤ 63 characters, no leading/trailing hyphens, at least two labels
|
|
77
|
+
*
|
|
78
|
+
* @param value - The email address string
|
|
79
|
+
* @returns `true` if the value is a syntactically valid email address
|
|
80
|
+
*
|
|
81
|
+
* @example isEmail('user@example.com') // => true
|
|
82
|
+
* @example isEmail('user.name+tag@example.co.id') // => true
|
|
83
|
+
* @example isEmail('"quoted@local"@example.com') // => true
|
|
84
|
+
* @example isEmail('not-an-email') // => false
|
|
85
|
+
*/
|
|
86
|
+
declare function isEmail(value: string): boolean;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Validates a URL.
|
|
90
|
+
*
|
|
91
|
+
* A valid URL:
|
|
92
|
+
* - Must use the `http` or `https` protocol
|
|
93
|
+
* - Must have a valid hostname (DNS name, IPv4, IPv6 literal, or `localhost`)
|
|
94
|
+
* - May include an optional port, path, query string, and fragment
|
|
95
|
+
*
|
|
96
|
+
* @param value - The URL string
|
|
97
|
+
* @returns `true` if the value is a valid http/https URL
|
|
98
|
+
*
|
|
99
|
+
* @example isURL('https://example.com') // => true
|
|
100
|
+
* @example isURL('http://example.com:8080/path?q=1#f') // => true
|
|
101
|
+
* @example isURL('ftp://example.com') // => false
|
|
102
|
+
* @example isURL('not-a-url') // => false
|
|
103
|
+
*/
|
|
104
|
+
declare function isURL(value: string): boolean;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Parse data dari NIK (Nomor Induk Kependudukan).
|
|
108
|
+
*
|
|
109
|
+
* @example parseNIK('3201010203940001')
|
|
110
|
+
* // { nik: '3201010203940001', valid: true, gender: 'LAKI-LAKI', birthDate: Date(1994-03-02), province: 'JAWA BARAT', city: 'BOGOR', district: 'CIAWI' }
|
|
111
|
+
*
|
|
112
|
+
* @example parseNIK('3201015203940001')
|
|
113
|
+
* // { nik: '3201015203940001', valid: true, gender: 'PEREMPUAN', birthDate: Date(1994-03-12), province: 'JAWA BARAT', ... }
|
|
114
|
+
*/
|
|
115
|
+
declare function parseNIK(value: string): NIKInfo;
|
|
116
|
+
interface NIKInfo {
|
|
117
|
+
nik: string;
|
|
118
|
+
valid: boolean;
|
|
119
|
+
gender: 'LAKI-LAKI' | 'PEREMPUAN' | null;
|
|
120
|
+
birthDate: Date | null;
|
|
121
|
+
province: string | null;
|
|
122
|
+
provinceCode: string | null;
|
|
123
|
+
city: string | null;
|
|
124
|
+
cityCode: string | null;
|
|
125
|
+
district: string | null;
|
|
126
|
+
districtCode: string | null;
|
|
127
|
+
uniqueCode: string | null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Validasi Plat Nomor Kendaraan Bermotor Indonesia.
|
|
132
|
+
*
|
|
133
|
+
* Format: [KODE_DEPAN] [ANGKA] [KODE_BELAKANG]
|
|
134
|
+
* - Kode depan: 1-2 huruf (kode daerah)
|
|
135
|
+
* - Angka: 1-4 digit
|
|
136
|
+
* - Kode belakang: 1-3 huruf (opsional)
|
|
137
|
+
*
|
|
138
|
+
* @example isPlatNomor('B 1234 CD') // true (Jakarta)
|
|
139
|
+
* @example isPlatNomor('AB 5678 XYZ') // true
|
|
140
|
+
* @example isPlatNomor('B 1 A') // true
|
|
141
|
+
* @example isPlatNomor('INVALID') // false
|
|
142
|
+
*/
|
|
143
|
+
declare function isPlatNomor(value: string): boolean;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Validasi kode pos Indonesia.
|
|
147
|
+
* Kode pos Indonesia terdiri dari 5 digit angka.
|
|
148
|
+
*
|
|
149
|
+
* @example isKodepos('16110') // true (Bogor)
|
|
150
|
+
* @example isKodepos('12345') // true
|
|
151
|
+
* @example isKodepos('1234') // false (kurang)
|
|
152
|
+
* @example isKodepos('ABCDE') // false
|
|
153
|
+
*/
|
|
154
|
+
declare function isKodepos(value: string): boolean;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Validasi nomor rekening bank Indonesia.
|
|
158
|
+
* Format: 8-16 digit angka (tergantung bank).
|
|
159
|
+
*
|
|
160
|
+
* @example isNoRekening('1234567890') // true (10 digit)
|
|
161
|
+
* @example isNoRekening('12345678') // true (8 digit - minimum)
|
|
162
|
+
* @example isNoRekening('1234567890123456') // true (16 digit - maksimum)
|
|
163
|
+
* @example isNoRekening('12345') // false (kurang dari 8 digit)
|
|
164
|
+
*/
|
|
165
|
+
declare function isNoRekening(value: string): boolean;
|
|
166
|
+
|
|
167
|
+
export { type NIKInfo as N, isKodepos as a, isNIK as b, isNPWP as c, isNoRekening as d, isPhone as e, isPlatNomor as f, isURL as g, isEmail as i, parseNIK as p };
|
package/dist/math/index.d.ts
CHANGED
|
@@ -171,5 +171,192 @@ declare function formatCurrency(value: number, options?: {
|
|
|
171
171
|
currency?: string;
|
|
172
172
|
notation?: 'standard' | 'compact';
|
|
173
173
|
}): string;
|
|
174
|
+
/**
|
|
175
|
+
* Checks if a number is even.
|
|
176
|
+
*
|
|
177
|
+
* @example isEven(4) // true
|
|
178
|
+
* @example isEven(7) // false
|
|
179
|
+
*
|
|
180
|
+
* @param n - The number to check.
|
|
181
|
+
* @returns Whether the number is even.
|
|
182
|
+
*/
|
|
183
|
+
declare function isEven(n: number): boolean;
|
|
184
|
+
/**
|
|
185
|
+
* Checks if a number is odd.
|
|
186
|
+
*
|
|
187
|
+
* @example isOdd(3) // true
|
|
188
|
+
* @example isOdd(8) // false
|
|
189
|
+
*
|
|
190
|
+
* @param n - The number to check.
|
|
191
|
+
* @returns Whether the number is odd.
|
|
192
|
+
*/
|
|
193
|
+
declare function isOdd(n: number): boolean;
|
|
194
|
+
/**
|
|
195
|
+
* Computes the greatest common divisor (GCD) using the Euclidean algorithm.
|
|
196
|
+
*
|
|
197
|
+
* @example gcd(12, 8) // 4
|
|
198
|
+
* @example gcd(17, 5) // 1
|
|
199
|
+
*
|
|
200
|
+
* @param a - First integer.
|
|
201
|
+
* @param b - Second integer.
|
|
202
|
+
* @returns The GCD.
|
|
203
|
+
*/
|
|
204
|
+
declare function gcd(a: number, b: number): number;
|
|
205
|
+
/**
|
|
206
|
+
* Computes the least common multiple (LCM).
|
|
207
|
+
*
|
|
208
|
+
* @example lcm(4, 6) // 12
|
|
209
|
+
* @example lcm(7, 5) // 35
|
|
210
|
+
*
|
|
211
|
+
* @param a - First integer.
|
|
212
|
+
* @param b - Second integer.
|
|
213
|
+
* @returns The LCM.
|
|
214
|
+
* @throws {RangeError} If either argument is zero.
|
|
215
|
+
*/
|
|
216
|
+
declare function lcm(a: number, b: number): number;
|
|
217
|
+
/**
|
|
218
|
+
* Computes the factorial of a non-negative integer.
|
|
219
|
+
*
|
|
220
|
+
* @example factorial(5) // 120
|
|
221
|
+
* @example factorial(0) // 1
|
|
222
|
+
*
|
|
223
|
+
* @param n - Non-negative integer.
|
|
224
|
+
* @returns The factorial.
|
|
225
|
+
* @throws {RangeError} If n is negative or not an integer.
|
|
226
|
+
*/
|
|
227
|
+
declare function factorial(n: number): number;
|
|
228
|
+
/**
|
|
229
|
+
* Tests whether a number is prime (optimized trial division).
|
|
230
|
+
*
|
|
231
|
+
* @example isPrime(7) // true
|
|
232
|
+
* @example isPrime(10) // false
|
|
233
|
+
*
|
|
234
|
+
* @param n - Positive integer.
|
|
235
|
+
* @returns Whether the number is prime.
|
|
236
|
+
* @throws {RangeError} If n is not an integer or is less than 2.
|
|
237
|
+
*/
|
|
238
|
+
declare function isPrime(n: number): boolean;
|
|
239
|
+
/**
|
|
240
|
+
* Converts degrees to radians.
|
|
241
|
+
*
|
|
242
|
+
* @example toRadians(180) // ~3.14159
|
|
243
|
+
*
|
|
244
|
+
* @param degrees - Angle in degrees.
|
|
245
|
+
* @returns Angle in radians.
|
|
246
|
+
*/
|
|
247
|
+
declare function toRadians(degrees: number): number;
|
|
248
|
+
/**
|
|
249
|
+
* Converts radians to degrees.
|
|
250
|
+
*
|
|
251
|
+
* @example toDegrees(Math.PI) // 180
|
|
252
|
+
*
|
|
253
|
+
* @param radians - Angle in radians.
|
|
254
|
+
* @returns Angle in degrees.
|
|
255
|
+
*/
|
|
256
|
+
declare function toDegrees(radians: number): number;
|
|
257
|
+
/**
|
|
258
|
+
* Linearly interpolates between `a` and `b` by `t`.
|
|
259
|
+
*
|
|
260
|
+
* @example lerp(0, 100, 0.5) // 50
|
|
261
|
+
*
|
|
262
|
+
* @param a - Start value.
|
|
263
|
+
* @param b - End value.
|
|
264
|
+
* @param t - Interpolation factor (typically 0–1).
|
|
265
|
+
* @returns The interpolated value.
|
|
266
|
+
*/
|
|
267
|
+
declare function lerp(a: number, b: number, t: number): number;
|
|
268
|
+
/**
|
|
269
|
+
* Calculates what percentage `value` is of `total`.
|
|
270
|
+
*
|
|
271
|
+
* @example percentageOf(25, 200) // 12.5
|
|
272
|
+
*
|
|
273
|
+
* @param value - The part value.
|
|
274
|
+
* @param total - The total value.
|
|
275
|
+
* @returns The percentage.
|
|
276
|
+
* @throws {RangeError} If total is zero.
|
|
277
|
+
*/
|
|
278
|
+
declare function percentageOf(value: number, total: number): number;
|
|
279
|
+
/**
|
|
280
|
+
* Maps a value from one range to another.
|
|
281
|
+
*
|
|
282
|
+
* @example mapRange(0.5, 0, 1, 0, 100) // 50
|
|
283
|
+
*
|
|
284
|
+
* @param value - The value to map.
|
|
285
|
+
* @param inMin - Lower bound of the input range.
|
|
286
|
+
* @param inMax - Upper bound of the input range.
|
|
287
|
+
* @param outMin - Lower bound of the output range.
|
|
288
|
+
* @param outMax - Upper bound of the output range.
|
|
289
|
+
* @returns The mapped value.
|
|
290
|
+
* @throws {RangeError} If the input range is zero.
|
|
291
|
+
*/
|
|
292
|
+
declare function mapRange(value: number, inMin: number, inMax: number, outMin: number, outMax: number): number;
|
|
293
|
+
/**
|
|
294
|
+
* Computes the statistical mode(s) — the most frequently occurring value(s).
|
|
295
|
+
*
|
|
296
|
+
* @example mode([1, 2, 2, 3]) // [2]
|
|
297
|
+
* @example mode([1, 1, 2, 2]) // [1, 2]
|
|
298
|
+
*
|
|
299
|
+
* @param values - Array of numbers.
|
|
300
|
+
* @returns Array of mode value(s).
|
|
301
|
+
* @throws {RangeError} If the array is empty.
|
|
302
|
+
*/
|
|
303
|
+
declare function mode(values: number[]): number[];
|
|
304
|
+
/**
|
|
305
|
+
* Generates an array of numbers from `start` to `end` (inclusive),
|
|
306
|
+
* incremented by `step`.
|
|
307
|
+
*
|
|
308
|
+
* @example range(1, 5) // [1, 2, 3, 4, 5]
|
|
309
|
+
* @example range(0, 10, 2) // [0, 2, 4, 6, 8, 10]
|
|
310
|
+
*
|
|
311
|
+
* @param start - Start of the range.
|
|
312
|
+
* @param end - End of the range (inclusive).
|
|
313
|
+
* @param step - Increment (defaults to 1 or -1 based on direction).
|
|
314
|
+
* @returns Array of numbers.
|
|
315
|
+
* @throws {RangeError} If step is zero.
|
|
316
|
+
*/
|
|
317
|
+
declare function range(start: number, end: number, step?: number): number[];
|
|
318
|
+
/**
|
|
319
|
+
* Computes the weighted mean of values with corresponding weights.
|
|
320
|
+
*
|
|
321
|
+
* @example weightedAverage([10, 20], [1, 4]) // 18
|
|
322
|
+
*
|
|
323
|
+
* @param values - Array of values.
|
|
324
|
+
* @param weights - Array of weights.
|
|
325
|
+
* @returns The weighted average.
|
|
326
|
+
* @throws {RangeError} If arrays are empty, differ in length, or sum of weights is zero.
|
|
327
|
+
*/
|
|
328
|
+
declare function weightedAverage(values: number[], weights: number[]): number;
|
|
329
|
+
/**
|
|
330
|
+
* Computes the geometric mean of an array of numbers.
|
|
331
|
+
*
|
|
332
|
+
* @example geometricMean([4, 9]) // 6
|
|
333
|
+
*
|
|
334
|
+
* @param values - Array of positive numbers.
|
|
335
|
+
* @returns The geometric mean.
|
|
336
|
+
* @throws {RangeError} If the array is empty or contains negative values.
|
|
337
|
+
*/
|
|
338
|
+
declare function geometricMean(values: number[]): number;
|
|
339
|
+
/**
|
|
340
|
+
* Computes the number of combinations (n choose k) — selecting k items from n without order.
|
|
341
|
+
*
|
|
342
|
+
* @example combinations(5, 2) // 10
|
|
343
|
+
*
|
|
344
|
+
* @param n - Total items.
|
|
345
|
+
* @param k - Chosen items.
|
|
346
|
+
* @returns The number of combinations.
|
|
347
|
+
* @throws {RangeError} If n < k, or either is negative / non-integer.
|
|
348
|
+
*/
|
|
349
|
+
declare function combinations(n: number, k: number): number;
|
|
350
|
+
/**
|
|
351
|
+
* Computes the number of permutations — selecting k items from n in order.
|
|
352
|
+
*
|
|
353
|
+
* @example permutations(5, 2) // 20
|
|
354
|
+
*
|
|
355
|
+
* @param n - Total items.
|
|
356
|
+
* @param k - Chosen items.
|
|
357
|
+
* @returns The number of permutations.
|
|
358
|
+
* @throws {RangeError} If n < k, or either is negative / non-integer.
|
|
359
|
+
*/
|
|
360
|
+
declare function permutations(n: number, k: number): number;
|
|
174
361
|
|
|
175
|
-
export { DivisionByZeroError, add, approxEqual, average, ceil, clamp, correlation, div, floor, formatCurrency, inRange, median, mul, percentile, randomInt, round, sampleStddev, stddev, sub, sum };
|
|
362
|
+
export { DivisionByZeroError, add, approxEqual, average, ceil, clamp, combinations, correlation, div, factorial, floor, formatCurrency, gcd, geometricMean, inRange, isEven, isOdd, isPrime, lcm, lerp, mapRange, median, mode, mul, percentageOf, percentile, permutations, randomInt, range, round, sampleStddev, stddev, sub, sum, toDegrees, toRadians, weightedAverage };
|
package/dist/math/index.js
CHANGED
|
@@ -149,6 +149,187 @@ function formatCurrency(value, options) {
|
|
|
149
149
|
return `${currency} ${value.toLocaleString(locale)}`;
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
+
function isEven(n) {
|
|
153
|
+
return n % 2 === 0;
|
|
154
|
+
}
|
|
155
|
+
function isOdd(n) {
|
|
156
|
+
return n % 2 !== 0;
|
|
157
|
+
}
|
|
158
|
+
function gcd(a, b) {
|
|
159
|
+
if (!Number.isInteger(a) || !Number.isInteger(b)) {
|
|
160
|
+
throw new RangeError("Arguments must be integers");
|
|
161
|
+
}
|
|
162
|
+
a = Math.abs(a);
|
|
163
|
+
b = Math.abs(b);
|
|
164
|
+
while (b !== 0) {
|
|
165
|
+
const t = b;
|
|
166
|
+
b = a % b;
|
|
167
|
+
a = t;
|
|
168
|
+
}
|
|
169
|
+
return a;
|
|
170
|
+
}
|
|
171
|
+
function lcm(a, b) {
|
|
172
|
+
if (!Number.isInteger(a) || !Number.isInteger(b)) {
|
|
173
|
+
throw new RangeError("Arguments must be integers");
|
|
174
|
+
}
|
|
175
|
+
if (a === 0 || b === 0) {
|
|
176
|
+
throw new RangeError("Arguments must be non-zero");
|
|
177
|
+
}
|
|
178
|
+
return Math.abs(a * b) / gcd(a, b);
|
|
179
|
+
}
|
|
180
|
+
function factorial(n) {
|
|
181
|
+
if (!Number.isInteger(n)) {
|
|
182
|
+
throw new RangeError("Argument must be an integer");
|
|
183
|
+
}
|
|
184
|
+
if (n < 0) {
|
|
185
|
+
throw new RangeError("Factorial is not defined for negative numbers");
|
|
186
|
+
}
|
|
187
|
+
let result = 1;
|
|
188
|
+
for (let i = 2; i <= n; i++) {
|
|
189
|
+
result *= i;
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
function isPrime(n) {
|
|
194
|
+
if (!Number.isInteger(n)) {
|
|
195
|
+
throw new RangeError("Argument must be an integer");
|
|
196
|
+
}
|
|
197
|
+
if (n < 2) return false;
|
|
198
|
+
if (n === 2 || n === 3) return true;
|
|
199
|
+
if (n % 2 === 0 || n % 3 === 0) return false;
|
|
200
|
+
const limit = Math.sqrt(n);
|
|
201
|
+
for (let i = 5; i <= limit; i += 6) {
|
|
202
|
+
if (n % i === 0 || n % (i + 2) === 0) return false;
|
|
203
|
+
}
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
function toRadians(degrees) {
|
|
207
|
+
return degrees * Math.PI / 180;
|
|
208
|
+
}
|
|
209
|
+
function toDegrees(radians) {
|
|
210
|
+
return radians * 180 / Math.PI;
|
|
211
|
+
}
|
|
212
|
+
function lerp(a, b, t) {
|
|
213
|
+
return a + (b - a) * t;
|
|
214
|
+
}
|
|
215
|
+
function percentageOf(value, total) {
|
|
216
|
+
if (total === 0) {
|
|
217
|
+
throw new RangeError("Total must be non-zero");
|
|
218
|
+
}
|
|
219
|
+
return value / total * 100;
|
|
220
|
+
}
|
|
221
|
+
function mapRange(value, inMin, inMax, outMin, outMax) {
|
|
222
|
+
if (inMin === inMax) {
|
|
223
|
+
throw new RangeError("Input range must not be zero");
|
|
224
|
+
}
|
|
225
|
+
return (value - inMin) / (inMax - inMin) * (outMax - outMin) + outMin;
|
|
226
|
+
}
|
|
227
|
+
function mode(values) {
|
|
228
|
+
if (values.length === 0) {
|
|
229
|
+
throw new RangeError("Cannot compute mode of an empty array");
|
|
230
|
+
}
|
|
231
|
+
const freq = /* @__PURE__ */ new Map();
|
|
232
|
+
let maxFreq = 0;
|
|
233
|
+
for (const v of values) {
|
|
234
|
+
const count = (freq.get(v) ?? 0) + 1;
|
|
235
|
+
freq.set(v, count);
|
|
236
|
+
if (count > maxFreq) maxFreq = count;
|
|
237
|
+
}
|
|
238
|
+
const result = [];
|
|
239
|
+
for (const [v, count] of freq) {
|
|
240
|
+
if (count === maxFreq) result.push(v);
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
244
|
+
function range(start, end, step) {
|
|
245
|
+
const dir = end >= start ? 1 : -1;
|
|
246
|
+
const s = step ?? dir;
|
|
247
|
+
if (s === 0) {
|
|
248
|
+
throw new RangeError("Step must not be zero");
|
|
249
|
+
}
|
|
250
|
+
if ((end - start) * s < 0) {
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
const result = [];
|
|
254
|
+
let i = start;
|
|
255
|
+
if (s > 0) {
|
|
256
|
+
while (i <= end) {
|
|
257
|
+
result.push(i);
|
|
258
|
+
i += s;
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
while (i >= end) {
|
|
262
|
+
result.push(i);
|
|
263
|
+
i += s;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
function weightedAverage(values, weights) {
|
|
269
|
+
if (values.length === 0 || weights.length === 0) {
|
|
270
|
+
throw new RangeError("Arrays must not be empty");
|
|
271
|
+
}
|
|
272
|
+
if (values.length !== weights.length) {
|
|
273
|
+
throw new RangeError("Values and weights must have the same length");
|
|
274
|
+
}
|
|
275
|
+
let weightedSum = 0;
|
|
276
|
+
let weightSum = 0;
|
|
277
|
+
for (let i = 0; i < values.length; i++) {
|
|
278
|
+
weightedSum += values[i] * weights[i];
|
|
279
|
+
weightSum += weights[i];
|
|
280
|
+
}
|
|
281
|
+
if (weightSum === 0) {
|
|
282
|
+
throw new RangeError("Sum of weights must be non-zero");
|
|
283
|
+
}
|
|
284
|
+
return weightedSum / weightSum;
|
|
285
|
+
}
|
|
286
|
+
function geometricMean(values) {
|
|
287
|
+
if (values.length === 0) {
|
|
288
|
+
throw new RangeError("Cannot compute geometric mean of an empty array");
|
|
289
|
+
}
|
|
290
|
+
for (const v of values) {
|
|
291
|
+
if (v < 0) {
|
|
292
|
+
throw new RangeError("Values must be non-negative for geometric mean");
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const logSum = values.reduce((acc, v) => v === 0 ? acc : acc + Math.log(v), 0);
|
|
296
|
+
if (logSum === -Infinity) return 0;
|
|
297
|
+
return Math.exp(logSum / values.length);
|
|
298
|
+
}
|
|
299
|
+
function combinations(n, k) {
|
|
300
|
+
if (!Number.isInteger(n) || !Number.isInteger(k)) {
|
|
301
|
+
throw new RangeError("Arguments must be integers");
|
|
302
|
+
}
|
|
303
|
+
if (n < 0 || k < 0) {
|
|
304
|
+
throw new RangeError("Arguments must be non-negative");
|
|
305
|
+
}
|
|
306
|
+
if (k > n) {
|
|
307
|
+
throw new RangeError("k must not exceed n");
|
|
308
|
+
}
|
|
309
|
+
if (k === 0 || k === n) return 1;
|
|
310
|
+
const r = Math.min(k, n - k);
|
|
311
|
+
let result = 1;
|
|
312
|
+
for (let i = 1; i <= r; i++) {
|
|
313
|
+
result = result * (n - r + i) / i;
|
|
314
|
+
}
|
|
315
|
+
return result;
|
|
316
|
+
}
|
|
317
|
+
function permutations(n, k) {
|
|
318
|
+
if (!Number.isInteger(n) || !Number.isInteger(k)) {
|
|
319
|
+
throw new RangeError("Arguments must be integers");
|
|
320
|
+
}
|
|
321
|
+
if (n < 0 || k < 0) {
|
|
322
|
+
throw new RangeError("Arguments must be non-negative");
|
|
323
|
+
}
|
|
324
|
+
if (k > n) {
|
|
325
|
+
throw new RangeError("k must not exceed n");
|
|
326
|
+
}
|
|
327
|
+
let result = 1;
|
|
328
|
+
for (let i = n; i > n - k; i--) {
|
|
329
|
+
result *= i;
|
|
330
|
+
}
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
152
333
|
export {
|
|
153
334
|
DivisionByZeroError,
|
|
154
335
|
add,
|
|
@@ -156,19 +337,36 @@ export {
|
|
|
156
337
|
average,
|
|
157
338
|
ceil,
|
|
158
339
|
clamp,
|
|
340
|
+
combinations,
|
|
159
341
|
correlation,
|
|
160
342
|
div,
|
|
343
|
+
factorial,
|
|
161
344
|
floor,
|
|
162
345
|
formatCurrency,
|
|
346
|
+
gcd,
|
|
347
|
+
geometricMean,
|
|
163
348
|
inRange,
|
|
349
|
+
isEven,
|
|
350
|
+
isOdd,
|
|
351
|
+
isPrime,
|
|
352
|
+
lcm,
|
|
353
|
+
lerp,
|
|
354
|
+
mapRange,
|
|
164
355
|
median,
|
|
356
|
+
mode,
|
|
165
357
|
mul,
|
|
358
|
+
percentageOf,
|
|
166
359
|
percentile,
|
|
360
|
+
permutations,
|
|
167
361
|
randomInt,
|
|
362
|
+
range,
|
|
168
363
|
round,
|
|
169
364
|
sampleStddev,
|
|
170
365
|
stddev,
|
|
171
366
|
sub,
|
|
172
|
-
sum
|
|
367
|
+
sum,
|
|
368
|
+
toDegrees,
|
|
369
|
+
toRadians,
|
|
370
|
+
weightedAverage
|
|
173
371
|
};
|
|
174
372
|
//# sourceMappingURL=index.js.map
|