speexjs-core 0.7.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 +117 -0
- package/CONTRIBUTING.md +55 -0
- package/PUBLISH.md +45 -0
- package/README.md +174 -0
- package/ROADMAP.md +72 -0
- package/SECURITY.md +35 -0
- package/SUMMARY.md +321 -0
- package/dist/async/index.d.ts +232 -0
- package/dist/async/index.js +366 -0
- package/dist/async/index.js.map +1 -0
- package/dist/collection/index.d.ts +230 -0
- package/dist/collection/index.js +375 -0
- package/dist/collection/index.js.map +1 -0
- package/dist/color/index.d.ts +128 -0
- package/dist/color/index.js +167 -0
- package/dist/color/index.js.map +1 -0
- package/dist/core/index.d.ts +119 -0
- package/dist/core/index.js +324 -0
- package/dist/core/index.js.map +1 -0
- package/dist/crypto/index.d.ts +84 -0
- package/dist/crypto/index.js +144 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/date/index.d.ts +588 -0
- package/dist/date/index.js +737 -0
- package/dist/date/index.js.map +1 -0
- package/dist/dep-exray/analyzer/index.d.ts +7 -0
- package/dist/dep-exray/analyzer/index.js +68 -0
- package/dist/dep-exray/analyzer/index.js.map +1 -0
- package/dist/dep-exray/cli.d.ts +1 -0
- package/dist/dep-exray/cli.js +441 -0
- package/dist/dep-exray/cli.js.map +1 -0
- package/dist/dep-exray/index.d.ts +5 -0
- package/dist/dep-exray/index.js +454 -0
- package/dist/dep-exray/index.js.map +1 -0
- package/dist/dep-exray/known-mappings.d.ts +17 -0
- package/dist/dep-exray/known-mappings.js +122 -0
- package/dist/dep-exray/known-mappings.js.map +1 -0
- package/dist/dep-exray/reporter/index.d.ts +5 -0
- package/dist/dep-exray/reporter/index.js +89 -0
- package/dist/dep-exray/reporter/index.js.map +1 -0
- package/dist/dep-exray/scanner/index.d.ts +5 -0
- package/dist/dep-exray/scanner/index.js +299 -0
- package/dist/dep-exray/scanner/index.js.map +1 -0
- package/dist/dep-exray/types.d.ts +38 -0
- package/dist/dep-exray/types.js +1 -0
- package/dist/dep-exray/types.js.map +1 -0
- package/dist/error/index.d.ts +148 -0
- package/dist/error/index.js +115 -0
- package/dist/error/index.js.map +1 -0
- package/dist/index-BgG21uJC.d.ts +166 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +4378 -0
- package/dist/index.js.map +1 -0
- package/dist/io/index.d.ts +39 -0
- package/dist/io/index.js +111 -0
- package/dist/io/index.js.map +1 -0
- package/dist/logger/index.d.ts +1 -0
- package/dist/logger/index.js +214 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/transports.d.ts +1 -0
- package/dist/logger/transports.js +122 -0
- package/dist/logger/transports.js.map +1 -0
- package/dist/math/index.d.ts +362 -0
- package/dist/math/index.js +372 -0
- package/dist/math/index.js.map +1 -0
- package/dist/path/index.d.ts +81 -0
- package/dist/path/index.js +134 -0
- package/dist/path/index.js.map +1 -0
- package/dist/string/index.d.ts +234 -0
- package/dist/string/index.js +411 -0
- package/dist/string/index.js.map +1 -0
- package/dist/type/index.d.ts +85 -0
- package/dist/type/index.js +107 -0
- package/dist/type/index.js.map +1 -0
- package/dist/validation/index.d.ts +203 -0
- package/dist/validation/index.js +402 -0
- package/dist/validation/index.js.map +1 -0
- package/package.json +172 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
// src/math/index.ts
|
|
2
|
+
var DivisionByZeroError = class extends Error {
|
|
3
|
+
constructor() {
|
|
4
|
+
super("Division by zero");
|
|
5
|
+
this.name = "DivisionByZeroError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
function getPrecision(value) {
|
|
9
|
+
if (!isFinite(value)) return 0;
|
|
10
|
+
const eIndex = String(value).indexOf("e");
|
|
11
|
+
if (eIndex > -1) {
|
|
12
|
+
const exp = parseInt(String(value).slice(eIndex + 1), 10);
|
|
13
|
+
if (exp < 0) return Math.abs(exp);
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
const str = String(value);
|
|
17
|
+
const dot = str.indexOf(".");
|
|
18
|
+
return dot === -1 ? 0 : str.length - dot - 1;
|
|
19
|
+
}
|
|
20
|
+
function toPrecisionFactor(a, b) {
|
|
21
|
+
return Math.pow(10, Math.max(getPrecision(a), getPrecision(b)));
|
|
22
|
+
}
|
|
23
|
+
function add(a, b) {
|
|
24
|
+
const factor = toPrecisionFactor(a, b);
|
|
25
|
+
return (Math.round(a * factor) + Math.round(b * factor)) / factor;
|
|
26
|
+
}
|
|
27
|
+
function sub(a, b) {
|
|
28
|
+
const factor = toPrecisionFactor(a, b);
|
|
29
|
+
return (Math.round(a * factor) - Math.round(b * factor)) / factor;
|
|
30
|
+
}
|
|
31
|
+
function mul(a, b) {
|
|
32
|
+
const factorA = toPrecisionFactor(a, 1);
|
|
33
|
+
const factorB = toPrecisionFactor(1, b);
|
|
34
|
+
const result = Math.round(a * factorA) * Math.round(b * factorB) / (factorA * factorB);
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function div(a, b) {
|
|
38
|
+
if (b === 0) throw new DivisionByZeroError();
|
|
39
|
+
const factor = toPrecisionFactor(a, b);
|
|
40
|
+
return Math.round(a * factor) / Math.round(b * factor);
|
|
41
|
+
}
|
|
42
|
+
function round(value, precision = 0) {
|
|
43
|
+
const factor = Math.pow(10, precision);
|
|
44
|
+
const shifted = Number((value * factor).toPrecision(15));
|
|
45
|
+
return Math.round(shifted) / factor;
|
|
46
|
+
}
|
|
47
|
+
function floor(value, precision = 0) {
|
|
48
|
+
const factor = Math.pow(10, precision);
|
|
49
|
+
return Math.floor(value * factor) / factor;
|
|
50
|
+
}
|
|
51
|
+
function ceil(value, precision = 0) {
|
|
52
|
+
const factor = Math.pow(10, precision);
|
|
53
|
+
return Math.ceil(value * factor) / factor;
|
|
54
|
+
}
|
|
55
|
+
function approxEqual(a, b, tolerance = Number.EPSILON) {
|
|
56
|
+
return Math.abs(a - b) <= tolerance;
|
|
57
|
+
}
|
|
58
|
+
function clamp(value, min, max) {
|
|
59
|
+
if (min > max) {
|
|
60
|
+
throw new RangeError("Minimum value cannot exceed maximum value");
|
|
61
|
+
}
|
|
62
|
+
return Math.min(Math.max(value, min), max);
|
|
63
|
+
}
|
|
64
|
+
function sum(values) {
|
|
65
|
+
let total = 0;
|
|
66
|
+
for (let i = 0; i < values.length; i++) {
|
|
67
|
+
total += values[i];
|
|
68
|
+
}
|
|
69
|
+
return total;
|
|
70
|
+
}
|
|
71
|
+
function average(values) {
|
|
72
|
+
if (values.length === 0) {
|
|
73
|
+
throw new RangeError("Cannot compute average of an empty array");
|
|
74
|
+
}
|
|
75
|
+
return sum(values) / values.length;
|
|
76
|
+
}
|
|
77
|
+
function randomInt(min, max) {
|
|
78
|
+
if (!Number.isInteger(min) || !Number.isInteger(max)) {
|
|
79
|
+
throw new RangeError("Arguments must be integers");
|
|
80
|
+
}
|
|
81
|
+
if (min > max) {
|
|
82
|
+
throw new RangeError("Minimum value cannot exceed maximum value");
|
|
83
|
+
}
|
|
84
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
85
|
+
}
|
|
86
|
+
function inRange(value, min, max) {
|
|
87
|
+
return value >= min && value <= max;
|
|
88
|
+
}
|
|
89
|
+
function median(values) {
|
|
90
|
+
if (values.length === 0) throw new RangeError("Cannot compute median of an empty array");
|
|
91
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
92
|
+
const mid = Math.floor(sorted.length / 2);
|
|
93
|
+
return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
94
|
+
}
|
|
95
|
+
function stddev(values) {
|
|
96
|
+
if (values.length < 2) throw new RangeError("Need at least 2 values for stddev");
|
|
97
|
+
const mean = sum(values) / values.length;
|
|
98
|
+
const sqDiffs = values.map((v) => (v - mean) ** 2);
|
|
99
|
+
return Math.sqrt(sqDiffs.reduce((a, b) => a + b, 0) / values.length);
|
|
100
|
+
}
|
|
101
|
+
function sampleStddev(values) {
|
|
102
|
+
if (values.length < 2) throw new RangeError("Need at least 2 values for sample stddev");
|
|
103
|
+
const mean = sum(values) / values.length;
|
|
104
|
+
const sqDiffs = values.map((v) => (v - mean) ** 2);
|
|
105
|
+
return Math.sqrt(sqDiffs.reduce((a, b) => a + b, 0) / (values.length - 1));
|
|
106
|
+
}
|
|
107
|
+
function percentile(values, p) {
|
|
108
|
+
if (values.length === 0) throw new RangeError("Cannot compute percentile of empty array");
|
|
109
|
+
if (p < 0 || p > 100) throw new RangeError("Percentile must be between 0 and 100");
|
|
110
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
111
|
+
const rank = p / 100 * (sorted.length - 1);
|
|
112
|
+
const lower = Math.floor(rank);
|
|
113
|
+
const upper = Math.ceil(rank);
|
|
114
|
+
if (lower === upper) return sorted[lower];
|
|
115
|
+
return sorted[lower] + (sorted[upper] - sorted[lower]) * (rank - lower);
|
|
116
|
+
}
|
|
117
|
+
function correlation(x, y) {
|
|
118
|
+
if (x.length !== y.length) throw new RangeError("Arrays must have the same length");
|
|
119
|
+
if (x.length < 2) throw new RangeError("Need at least 2 pairs for correlation");
|
|
120
|
+
const n = x.length;
|
|
121
|
+
const meanX = sum(x) / n;
|
|
122
|
+
const meanY = sum(y) / n;
|
|
123
|
+
let num = 0;
|
|
124
|
+
let denX = 0;
|
|
125
|
+
let denY = 0;
|
|
126
|
+
for (let i = 0; i < n; i++) {
|
|
127
|
+
const dx = x[i] - meanX;
|
|
128
|
+
const dy = y[i] - meanY;
|
|
129
|
+
num += dx * dy;
|
|
130
|
+
denX += dx * dx;
|
|
131
|
+
denY += dy * dy;
|
|
132
|
+
}
|
|
133
|
+
if (denX === 0 || denY === 0) return 0;
|
|
134
|
+
return num / Math.sqrt(denX * denY);
|
|
135
|
+
}
|
|
136
|
+
function formatCurrency(value, options) {
|
|
137
|
+
const locale = options?.locale ?? "id-ID";
|
|
138
|
+
const currency = options?.currency ?? "IDR";
|
|
139
|
+
const notation = options?.notation ?? "standard";
|
|
140
|
+
try {
|
|
141
|
+
return new Intl.NumberFormat(locale, {
|
|
142
|
+
style: "currency",
|
|
143
|
+
currency,
|
|
144
|
+
notation,
|
|
145
|
+
minimumFractionDigits: 0,
|
|
146
|
+
maximumFractionDigits: 2
|
|
147
|
+
}).format(value);
|
|
148
|
+
} catch {
|
|
149
|
+
return `${currency} ${value.toLocaleString(locale)}`;
|
|
150
|
+
}
|
|
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
|
+
}
|
|
333
|
+
export {
|
|
334
|
+
DivisionByZeroError,
|
|
335
|
+
add,
|
|
336
|
+
approxEqual,
|
|
337
|
+
average,
|
|
338
|
+
ceil,
|
|
339
|
+
clamp,
|
|
340
|
+
combinations,
|
|
341
|
+
correlation,
|
|
342
|
+
div,
|
|
343
|
+
factorial,
|
|
344
|
+
floor,
|
|
345
|
+
formatCurrency,
|
|
346
|
+
gcd,
|
|
347
|
+
geometricMean,
|
|
348
|
+
inRange,
|
|
349
|
+
isEven,
|
|
350
|
+
isOdd,
|
|
351
|
+
isPrime,
|
|
352
|
+
lcm,
|
|
353
|
+
lerp,
|
|
354
|
+
mapRange,
|
|
355
|
+
median,
|
|
356
|
+
mode,
|
|
357
|
+
mul,
|
|
358
|
+
percentageOf,
|
|
359
|
+
percentile,
|
|
360
|
+
permutations,
|
|
361
|
+
randomInt,
|
|
362
|
+
range,
|
|
363
|
+
round,
|
|
364
|
+
sampleStddev,
|
|
365
|
+
stddev,
|
|
366
|
+
sub,
|
|
367
|
+
sum,
|
|
368
|
+
toDegrees,
|
|
369
|
+
toRadians,
|
|
370
|
+
weightedAverage
|
|
371
|
+
};
|
|
372
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/math/index.ts"],"sourcesContent":["/**\r\n * Error thrown when attempting to divide by zero.\r\n */\r\nexport class DivisionByZeroError extends Error {\r\n constructor() {\r\n super('Division by zero')\r\n this.name = 'DivisionByZeroError'\r\n }\r\n}\r\n\r\nfunction getPrecision(value: number): number {\r\n if (!isFinite(value)) return 0\r\n const eIndex = String(value).indexOf('e')\r\n if (eIndex > -1) {\r\n const exp = parseInt(String(value).slice(eIndex + 1), 10)\r\n if (exp < 0) return Math.abs(exp)\r\n return 0\r\n }\r\n const str = String(value)\r\n const dot = str.indexOf('.')\r\n return dot === -1 ? 0 : str.length - dot - 1\r\n}\r\n\r\nfunction toPrecisionFactor(a: number, b: number): number {\r\n return Math.pow(10, Math.max(getPrecision(a), getPrecision(b)))\r\n}\r\n\r\n/**\r\n * Safely adds two numbers, handling floating-point precision.\r\n *\r\n * @param a - First number.\r\n * @param b - Second number.\r\n * @returns The sum.\r\n */\r\nexport function add(a: number, b: number): number {\r\n const factor = toPrecisionFactor(a, b)\r\n return (Math.round(a * factor) + Math.round(b * factor)) / factor\r\n}\r\n\r\n/**\r\n * Safely subtracts two numbers, handling floating-point precision.\r\n *\r\n * @param a - First number.\r\n * @param b - Second number.\r\n * @returns The difference.\r\n */\r\nexport function sub(a: number, b: number): number {\r\n const factor = toPrecisionFactor(a, b)\r\n return (Math.round(a * factor) - Math.round(b * factor)) / factor\r\n}\r\n\r\n/**\r\n * Safely multiplies two numbers, handling floating-point precision.\r\n *\r\n * @param a - First number.\r\n * @param b - Second number.\r\n * @returns The product.\r\n */\r\nexport function mul(a: number, b: number): number {\r\n const factorA = toPrecisionFactor(a, 1)\r\n const factorB = toPrecisionFactor(1, b)\r\n const result = (Math.round(a * factorA) * Math.round(b * factorB)) / (factorA * factorB)\r\n return result\r\n}\r\n\r\n/**\r\n * Safely divides two numbers.\r\n *\r\n * @param a - The dividend.\r\n * @param b - The divisor.\r\n * @returns The quotient.\r\n * @throws {DivisionByZeroError} If `b` is zero.\r\n */\r\nexport function div(a: number, b: number): number {\r\n if (b === 0) throw new DivisionByZeroError()\r\n const factor = toPrecisionFactor(a, b)\r\n return Math.round(a * factor) / Math.round(b * factor)\r\n}\r\n\r\n/**\r\n * Rounds a number to the given precision.\r\n *\r\n * @param value - The number to round.\r\n * @param precision - Number of decimal places (default 0).\r\n * @returns The rounded value.\r\n */\r\nexport function round(value: number, precision: number = 0): number {\r\n const factor = Math.pow(10, precision)\r\n // Use toPrecision to avoid floating-point multiplication errors\r\n // e.g. 1.005 * 100 = 100.49999999999999 without this fix\r\n const shifted = Number((value * factor).toPrecision(15))\r\n return Math.round(shifted) / factor\r\n}\r\n\r\n/**\r\n * Floors a number to the given precision.\r\n *\r\n * @param value - The number to floor.\r\n * @param precision - Number of decimal places (default 0).\r\n * @returns The floored value.\r\n */\r\nexport function floor(value: number, precision: number = 0): number {\r\n const factor = Math.pow(10, precision)\r\n return Math.floor(value * factor) / factor\r\n}\r\n\r\n/**\r\n * Ceils a number to the given precision.\r\n *\r\n * @param value - The number to ceil.\r\n * @param precision - Number of decimal places (default 0).\r\n * @returns The ceiled value.\r\n */\r\nexport function ceil(value: number, precision: number = 0): number {\r\n const factor = Math.pow(10, precision)\r\n return Math.ceil(value * factor) / factor\r\n}\r\n\r\n/**\r\n * Checks if two numbers are approximately equal within a tolerance.\r\n *\r\n * @param a - First number.\r\n * @param b - Second number.\r\n * @param tolerance - Maximum difference (default `Number.EPSILON`).\r\n * @returns Whether the numbers are approximately equal.\r\n */\r\nexport function approxEqual(a: number, b: number, tolerance: number = Number.EPSILON): boolean {\r\n return Math.abs(a - b) <= tolerance\r\n}\r\n\r\n/**\r\n * Clamps a value within the inclusive range [min, max].\r\n *\r\n * @param value - The value to clamp.\r\n * @param min - The lower bound.\r\n * @param max - The upper bound.\r\n * @returns The clamped value.\r\n * @throws {RangeError} If `min` exceeds `max`.\r\n */\r\nexport function clamp(value: number, min: number, max: number): number {\r\n if (min > max) {\r\n throw new RangeError('Minimum value cannot exceed maximum value')\r\n }\r\n return Math.min(Math.max(value, min), max)\r\n}\r\n\r\n/**\r\n * Computes the sum of an array of numbers.\r\n *\r\n * @param values - Array of numbers.\r\n * @returns The total sum.\r\n */\r\nexport function sum(values: number[]): number {\r\n let total = 0\r\n for (let i = 0; i < values.length; i++) {\r\n total += values[i]!\r\n }\r\n return total\r\n}\r\n\r\n/**\r\n * Computes the average (mean) of an array of numbers.\r\n *\r\n * @param values - Array of numbers.\r\n * @returns The average.\r\n * @throws {RangeError} If the array is empty.\r\n */\r\nexport function average(values: number[]): number {\r\n if (values.length === 0) {\r\n throw new RangeError('Cannot compute average of an empty array')\r\n }\r\n return sum(values) / values.length\r\n}\r\n\r\n/**\r\n * Generates a random integer between `min` and `max` (inclusive).\r\n *\r\n * @param min - The minimum integer.\r\n * @param max - The maximum integer.\r\n * @returns A random integer.\r\n * @throws {RangeError} If arguments are not integers or `min > max`.\r\n */\r\nexport function randomInt(min: number, max: number): number {\r\n if (!Number.isInteger(min) || !Number.isInteger(max)) {\r\n throw new RangeError('Arguments must be integers')\r\n }\r\n if (min > max) {\r\n throw new RangeError('Minimum value cannot exceed maximum value')\r\n }\r\n return Math.floor(Math.random() * (max - min + 1)) + min\r\n}\r\n\r\n/**\r\n * Checks if a number is within the inclusive range [min, max].\r\n *\r\n * @param value - The number to check.\r\n * @param min - The lower bound.\r\n * @param max - The upper bound.\r\n * @returns Whether the value is in range.\r\n */\r\nexport function inRange(value: number, min: number, max: number): boolean {\r\n return value >= min && value <= max\r\n}\r\n\r\n// ─── Statistics ─────────────────────────────────────────\r\n\r\n/**\r\n * Computes the median of an array of numbers.\r\n *\r\n * @param values - Array of numbers.\r\n * @returns The median value.\r\n * @throws {RangeError} If the array is empty.\r\n */\r\nexport function median(values: number[]): number {\r\n if (values.length === 0) throw new RangeError('Cannot compute median of an empty array')\r\n const sorted = [...values].sort((a, b) => a - b)\r\n const mid = Math.floor(sorted.length / 2)\r\n return sorted.length % 2 === 0 ? (sorted[mid - 1]! + sorted[mid]!) / 2 : sorted[mid]!\r\n}\r\n\r\n/**\r\n * Computes the population standard deviation.\r\n *\r\n * @param values - Array of numbers.\r\n * @returns The standard deviation.\r\n * @throws {RangeError} If the array has fewer than 2 values.\r\n */\r\nexport function stddev(values: number[]): number {\r\n if (values.length < 2) throw new RangeError('Need at least 2 values for stddev')\r\n const mean = sum(values) / values.length\r\n const sqDiffs = values.map((v) => (v - mean) ** 2)\r\n return Math.sqrt(sqDiffs.reduce((a, b) => a + b, 0) / values.length)\r\n}\r\n\r\n/**\r\n * Computes the sample standard deviation (Bessel's correction).\r\n *\r\n * @param values - Array of numbers.\r\n * @returns The sample standard deviation.\r\n * @throws {RangeError} If the array has fewer than 2 values.\r\n */\r\nexport function sampleStddev(values: number[]): number {\r\n if (values.length < 2) throw new RangeError('Need at least 2 values for sample stddev')\r\n const mean = sum(values) / values.length\r\n const sqDiffs = values.map((v) => (v - mean) ** 2)\r\n return Math.sqrt(sqDiffs.reduce((a, b) => a + b, 0) / (values.length - 1))\r\n}\r\n\r\n/**\r\n * Computes the percentile value (0-100) using linear interpolation.\r\n *\r\n * @param values - Array of numbers.\r\n * @param p - Percentile (0-100).\r\n * @returns The percentile value.\r\n * @throws {RangeError} If p is outside [0, 100] or array is empty.\r\n */\r\nexport function percentile(values: number[], p: number): number {\r\n if (values.length === 0) throw new RangeError('Cannot compute percentile of empty array')\r\n if (p < 0 || p > 100) throw new RangeError('Percentile must be between 0 and 100')\r\n const sorted = [...values].sort((a, b) => a - b)\r\n const rank = (p / 100) * (sorted.length - 1)\r\n const lower = Math.floor(rank)\r\n const upper = Math.ceil(rank)\r\n if (lower === upper) return sorted[lower]!\r\n return sorted[lower]! + (sorted[upper]! - sorted[lower]!) * (rank - lower)\r\n}\r\n\r\n/**\r\n * Computes the Pearson correlation coefficient between two arrays.\r\n *\r\n * @param x - First array.\r\n * @param y - Second array.\r\n * @returns The correlation coefficient (-1 to 1).\r\n * @throws {RangeError} If arrays have different lengths or fewer than 2 pairs.\r\n */\r\nexport function correlation(x: number[], y: number[]): number {\r\n if (x.length !== y.length) throw new RangeError('Arrays must have the same length')\r\n if (x.length < 2) throw new RangeError('Need at least 2 pairs for correlation')\r\n const n = x.length\r\n const meanX = sum(x) / n\r\n const meanY = sum(y) / n\r\n let num = 0\r\n let denX = 0\r\n let denY = 0\r\n for (let i = 0; i < n; i++) {\r\n const dx = x[i]! - meanX\r\n const dy = y[i]! - meanY\r\n num += dx * dy\r\n denX += dx * dx\r\n denY += dy * dy\r\n }\r\n if (denX === 0 || denY === 0) return 0\r\n return num / Math.sqrt(denX * denY)\r\n}\r\n\r\n/**\r\n * Formats a number as a currency string with locale support.\r\n *\r\n * @example formatCurrency(1500000) // \"Rp1.500.000\"\r\n * @example formatCurrency(1500000, { notation: 'compact' }) // \"Rp1,5 jt\"\r\n * @example formatCurrency(99.99, { locale: 'en-US', currency: 'USD' }) // \"$99.99\"\r\n *\r\n * @param value - The number to format.\r\n * @param options - Formatting options.\r\n * @returns The formatted currency string.\r\n */\r\nexport function formatCurrency(\r\n value: number,\r\n options?: { locale?: string; currency?: string; notation?: 'standard' | 'compact' },\r\n): string {\r\n const locale = options?.locale ?? 'id-ID'\r\n const currency = options?.currency ?? 'IDR'\r\n const notation = options?.notation ?? 'standard'\r\n\r\n try {\r\n return new Intl.NumberFormat(locale, {\r\n style: 'currency',\r\n currency,\r\n notation,\r\n minimumFractionDigits: 0,\r\n maximumFractionDigits: 2,\r\n }).format(value)\r\n } catch {\r\n return `${currency} ${value.toLocaleString(locale)}`\r\n }\r\n}\r\n\r\n// ─── Parity ─────────────────────────────────────────────\r\n\r\n/**\r\n * Checks if a number is even.\r\n *\r\n * @example isEven(4) // true\r\n * @example isEven(7) // false\r\n *\r\n * @param n - The number to check.\r\n * @returns Whether the number is even.\r\n */\r\nexport function isEven(n: number): boolean {\r\n return n % 2 === 0\r\n}\r\n\r\n/**\r\n * Checks if a number is odd.\r\n *\r\n * @example isOdd(3) // true\r\n * @example isOdd(8) // false\r\n *\r\n * @param n - The number to check.\r\n * @returns Whether the number is odd.\r\n */\r\nexport function isOdd(n: number): boolean {\r\n return n % 2 !== 0\r\n}\r\n\r\n// ─── Number Theory ──────────────────────────────────────\r\n\r\n/**\r\n * Computes the greatest common divisor (GCD) using the Euclidean algorithm.\r\n *\r\n * @example gcd(12, 8) // 4\r\n * @example gcd(17, 5) // 1\r\n *\r\n * @param a - First integer.\r\n * @param b - Second integer.\r\n * @returns The GCD.\r\n */\r\nexport function gcd(a: number, b: number): number {\r\n if (!Number.isInteger(a) || !Number.isInteger(b)) {\r\n throw new RangeError('Arguments must be integers')\r\n }\r\n a = Math.abs(a)\r\n b = Math.abs(b)\r\n while (b !== 0) {\r\n const t = b\r\n b = a % b\r\n a = t\r\n }\r\n return a\r\n}\r\n\r\n/**\r\n * Computes the least common multiple (LCM).\r\n *\r\n * @example lcm(4, 6) // 12\r\n * @example lcm(7, 5) // 35\r\n *\r\n * @param a - First integer.\r\n * @param b - Second integer.\r\n * @returns The LCM.\r\n * @throws {RangeError} If either argument is zero.\r\n */\r\nexport function lcm(a: number, b: number): number {\r\n if (!Number.isInteger(a) || !Number.isInteger(b)) {\r\n throw new RangeError('Arguments must be integers')\r\n }\r\n if (a === 0 || b === 0) {\r\n throw new RangeError('Arguments must be non-zero')\r\n }\r\n return Math.abs(a * b) / gcd(a, b)\r\n}\r\n\r\n/**\r\n * Computes the factorial of a non-negative integer.\r\n *\r\n * @example factorial(5) // 120\r\n * @example factorial(0) // 1\r\n *\r\n * @param n - Non-negative integer.\r\n * @returns The factorial.\r\n * @throws {RangeError} If n is negative or not an integer.\r\n */\r\nexport function factorial(n: number): number {\r\n if (!Number.isInteger(n)) {\r\n throw new RangeError('Argument must be an integer')\r\n }\r\n if (n < 0) {\r\n throw new RangeError('Factorial is not defined for negative numbers')\r\n }\r\n let result = 1\r\n for (let i = 2; i <= n; i++) {\r\n result *= i\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Tests whether a number is prime (optimized trial division).\r\n *\r\n * @example isPrime(7) // true\r\n * @example isPrime(10) // false\r\n *\r\n * @param n - Positive integer.\r\n * @returns Whether the number is prime.\r\n * @throws {RangeError} If n is not an integer or is less than 2.\r\n */\r\nexport function isPrime(n: number): boolean {\r\n if (!Number.isInteger(n)) {\r\n throw new RangeError('Argument must be an integer')\r\n }\r\n if (n < 2) return false\r\n if (n === 2 || n === 3) return true\r\n if (n % 2 === 0 || n % 3 === 0) return false\r\n const limit = Math.sqrt(n)\r\n for (let i = 5; i <= limit; i += 6) {\r\n if (n % i === 0 || n % (i + 2) === 0) return false\r\n }\r\n return true\r\n}\r\n\r\n// ─── Angle Conversion ───────────────────────────────────\r\n\r\n/**\r\n * Converts degrees to radians.\r\n *\r\n * @example toRadians(180) // ~3.14159\r\n *\r\n * @param degrees - Angle in degrees.\r\n * @returns Angle in radians.\r\n */\r\nexport function toRadians(degrees: number): number {\r\n return (degrees * Math.PI) / 180\r\n}\r\n\r\n/**\r\n * Converts radians to degrees.\r\n *\r\n * @example toDegrees(Math.PI) // 180\r\n *\r\n * @param radians - Angle in radians.\r\n * @returns Angle in degrees.\r\n */\r\nexport function toDegrees(radians: number): number {\r\n return (radians * 180) / Math.PI\r\n}\r\n\r\n// ─── Interpolation & Mapping ────────────────────────────\r\n\r\n/**\r\n * Linearly interpolates between `a` and `b` by `t`.\r\n *\r\n * @example lerp(0, 100, 0.5) // 50\r\n *\r\n * @param a - Start value.\r\n * @param b - End value.\r\n * @param t - Interpolation factor (typically 0–1).\r\n * @returns The interpolated value.\r\n */\r\nexport function lerp(a: number, b: number, t: number): number {\r\n return a + (b - a) * t\r\n}\r\n\r\n/**\r\n * Calculates what percentage `value` is of `total`.\r\n *\r\n * @example percentageOf(25, 200) // 12.5\r\n *\r\n * @param value - The part value.\r\n * @param total - The total value.\r\n * @returns The percentage.\r\n * @throws {RangeError} If total is zero.\r\n */\r\nexport function percentageOf(value: number, total: number): number {\r\n if (total === 0) {\r\n throw new RangeError('Total must be non-zero')\r\n }\r\n return (value / total) * 100\r\n}\r\n\r\n/**\r\n * Maps a value from one range to another.\r\n *\r\n * @example mapRange(0.5, 0, 1, 0, 100) // 50\r\n *\r\n * @param value - The value to map.\r\n * @param inMin - Lower bound of the input range.\r\n * @param inMax - Upper bound of the input range.\r\n * @param outMin - Lower bound of the output range.\r\n * @param outMax - Upper bound of the output range.\r\n * @returns The mapped value.\r\n * @throws {RangeError} If the input range is zero.\r\n */\r\nexport function mapRange(value: number, inMin: number, inMax: number, outMin: number, outMax: number): number {\r\n if (inMin === inMax) {\r\n throw new RangeError('Input range must not be zero')\r\n }\r\n return ((value - inMin) / (inMax - inMin)) * (outMax - outMin) + outMin\r\n}\r\n\r\n// ─── Statistics ─────────────────────────────────────────\r\n\r\n/**\r\n * Computes the statistical mode(s) — the most frequently occurring value(s).\r\n *\r\n * @example mode([1, 2, 2, 3]) // [2]\r\n * @example mode([1, 1, 2, 2]) // [1, 2]\r\n *\r\n * @param values - Array of numbers.\r\n * @returns Array of mode value(s).\r\n * @throws {RangeError} If the array is empty.\r\n */\r\nexport function mode(values: number[]): number[] {\r\n if (values.length === 0) {\r\n throw new RangeError('Cannot compute mode of an empty array')\r\n }\r\n const freq = new Map<number, number>()\r\n let maxFreq = 0\r\n for (const v of values) {\r\n const count = (freq.get(v) ?? 0) + 1\r\n freq.set(v, count)\r\n if (count > maxFreq) maxFreq = count\r\n }\r\n const result: number[] = []\r\n for (const [v, count] of freq) {\r\n if (count === maxFreq) result.push(v)\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Generates an array of numbers from `start` to `end` (inclusive),\r\n * incremented by `step`.\r\n *\r\n * @example range(1, 5) // [1, 2, 3, 4, 5]\r\n * @example range(0, 10, 2) // [0, 2, 4, 6, 8, 10]\r\n *\r\n * @param start - Start of the range.\r\n * @param end - End of the range (inclusive).\r\n * @param step - Increment (defaults to 1 or -1 based on direction).\r\n * @returns Array of numbers.\r\n * @throws {RangeError} If step is zero.\r\n */\r\nexport function range(start: number, end: number, step?: number): number[] {\r\n const dir = end >= start ? 1 : -1\r\n const s = step ?? dir\r\n if (s === 0) {\r\n throw new RangeError('Step must not be zero')\r\n }\r\n if ((end - start) * s < 0) {\r\n return []\r\n }\r\n const result: number[] = []\r\n let i = start\r\n if (s > 0) {\r\n while (i <= end) {\r\n result.push(i)\r\n i += s\r\n }\r\n } else {\r\n while (i >= end) {\r\n result.push(i)\r\n i += s\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Computes the weighted mean of values with corresponding weights.\r\n *\r\n * @example weightedAverage([10, 20], [1, 4]) // 18\r\n *\r\n * @param values - Array of values.\r\n * @param weights - Array of weights.\r\n * @returns The weighted average.\r\n * @throws {RangeError} If arrays are empty, differ in length, or sum of weights is zero.\r\n */\r\nexport function weightedAverage(values: number[], weights: number[]): number {\r\n if (values.length === 0 || weights.length === 0) {\r\n throw new RangeError('Arrays must not be empty')\r\n }\r\n if (values.length !== weights.length) {\r\n throw new RangeError('Values and weights must have the same length')\r\n }\r\n let weightedSum = 0\r\n let weightSum = 0\r\n for (let i = 0; i < values.length; i++) {\r\n weightedSum += values[i]! * weights[i]!\r\n weightSum += weights[i]!\r\n }\r\n if (weightSum === 0) {\r\n throw new RangeError('Sum of weights must be non-zero')\r\n }\r\n return weightedSum / weightSum\r\n}\r\n\r\n/**\r\n * Computes the geometric mean of an array of numbers.\r\n *\r\n * @example geometricMean([4, 9]) // 6\r\n *\r\n * @param values - Array of positive numbers.\r\n * @returns The geometric mean.\r\n * @throws {RangeError} If the array is empty or contains negative values.\r\n */\r\nexport function geometricMean(values: number[]): number {\r\n if (values.length === 0) {\r\n throw new RangeError('Cannot compute geometric mean of an empty array')\r\n }\r\n for (const v of values) {\r\n if (v < 0) {\r\n throw new RangeError('Values must be non-negative for geometric mean')\r\n }\r\n }\r\n const logSum = values.reduce((acc, v) => (v === 0 ? acc : acc + Math.log(v)), 0)\r\n if (logSum === -Infinity) return 0\r\n return Math.exp(logSum / values.length)\r\n}\r\n\r\n/**\r\n * Computes the number of combinations (n choose k) — selecting k items from n without order.\r\n *\r\n * @example combinations(5, 2) // 10\r\n *\r\n * @param n - Total items.\r\n * @param k - Chosen items.\r\n * @returns The number of combinations.\r\n * @throws {RangeError} If n < k, or either is negative / non-integer.\r\n */\r\nexport function combinations(n: number, k: number): number {\r\n if (!Number.isInteger(n) || !Number.isInteger(k)) {\r\n throw new RangeError('Arguments must be integers')\r\n }\r\n if (n < 0 || k < 0) {\r\n throw new RangeError('Arguments must be non-negative')\r\n }\r\n if (k > n) {\r\n throw new RangeError('k must not exceed n')\r\n }\r\n if (k === 0 || k === n) return 1\r\n const r = Math.min(k, n - k)\r\n let result = 1\r\n for (let i = 1; i <= r; i++) {\r\n result = (result * (n - r + i)) / i\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Computes the number of permutations — selecting k items from n in order.\r\n *\r\n * @example permutations(5, 2) // 20\r\n *\r\n * @param n - Total items.\r\n * @param k - Chosen items.\r\n * @returns The number of permutations.\r\n * @throws {RangeError} If n < k, or either is negative / non-integer.\r\n */\r\nexport function permutations(n: number, k: number): number {\r\n if (!Number.isInteger(n) || !Number.isInteger(k)) {\r\n throw new RangeError('Arguments must be integers')\r\n }\r\n if (n < 0 || k < 0) {\r\n throw new RangeError('Arguments must be non-negative')\r\n }\r\n if (k > n) {\r\n throw new RangeError('k must not exceed n')\r\n }\r\n let result = 1\r\n for (let i = n; i > n - k; i--) {\r\n result *= i\r\n }\r\n return result\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Joins path segments with the proper separator.
|
|
3
|
+
*
|
|
4
|
+
* @param segments - Path segments to join.
|
|
5
|
+
* @returns The joined path.
|
|
6
|
+
*/
|
|
7
|
+
declare function join(...segments: string[]): string;
|
|
8
|
+
/**
|
|
9
|
+
* Resolves path segments to an absolute path.
|
|
10
|
+
*
|
|
11
|
+
* @param segments - Path segments to resolve.
|
|
12
|
+
* @returns The resolved absolute path.
|
|
13
|
+
*/
|
|
14
|
+
declare function resolve(...segments: string[]): string;
|
|
15
|
+
/**
|
|
16
|
+
* Returns the filename from a path.
|
|
17
|
+
*
|
|
18
|
+
* @param p - The path.
|
|
19
|
+
* @param ext - Optional extension to strip.
|
|
20
|
+
* @returns The filename.
|
|
21
|
+
*/
|
|
22
|
+
declare function basename(p: string, ext?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the directory portion of a path.
|
|
25
|
+
*
|
|
26
|
+
* @param p - The path.
|
|
27
|
+
* @returns The directory path.
|
|
28
|
+
*/
|
|
29
|
+
declare function dirname(p: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Returns the file extension from a path.
|
|
32
|
+
*
|
|
33
|
+
* @param p - The path.
|
|
34
|
+
* @returns The extension including the dot, or empty string.
|
|
35
|
+
*/
|
|
36
|
+
declare function extname(p: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Normalizes a path, resolving '..' and '.' segments.
|
|
39
|
+
*
|
|
40
|
+
* @param p - The path to normalize.
|
|
41
|
+
* @returns The normalized path.
|
|
42
|
+
*/
|
|
43
|
+
declare function normalize(p: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Checks if a path is absolute.
|
|
46
|
+
*
|
|
47
|
+
* @param p - The path to check.
|
|
48
|
+
* @returns Whether the path is absolute.
|
|
49
|
+
*/
|
|
50
|
+
declare function isAbsolute(p: string): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Computes the relative path from `from` to `to`.
|
|
53
|
+
*
|
|
54
|
+
* @param from - The base path.
|
|
55
|
+
* @param to - The target path.
|
|
56
|
+
* @returns The relative path.
|
|
57
|
+
*/
|
|
58
|
+
declare function relative(from: string, to: string): string;
|
|
59
|
+
interface ParsedPath {
|
|
60
|
+
root: string;
|
|
61
|
+
dir: string;
|
|
62
|
+
base: string;
|
|
63
|
+
name: string;
|
|
64
|
+
ext: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Parses a path into its components.
|
|
68
|
+
*
|
|
69
|
+
* @param p - The path to parse.
|
|
70
|
+
* @returns An object with root, dir, base, name, and ext.
|
|
71
|
+
*/
|
|
72
|
+
declare function parse(p: string): ParsedPath;
|
|
73
|
+
/**
|
|
74
|
+
* Formats a parsed path object back into a path string.
|
|
75
|
+
*
|
|
76
|
+
* @param parsed - The parsed path components.
|
|
77
|
+
* @returns The formatted path string.
|
|
78
|
+
*/
|
|
79
|
+
declare function format(parsed: Partial<ParsedPath>): string;
|
|
80
|
+
|
|
81
|
+
export { type ParsedPath, basename, dirname, extname, format, isAbsolute, join, normalize, parse, relative, resolve };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// src/path/index.ts
|
|
2
|
+
var SEP = "/";
|
|
3
|
+
function join(...segments) {
|
|
4
|
+
const parts = [];
|
|
5
|
+
for (const seg of segments) {
|
|
6
|
+
if (seg === "") continue;
|
|
7
|
+
const split = seg.split(/[\\/]/);
|
|
8
|
+
for (const part of split) {
|
|
9
|
+
if (part === "" || part === ".") continue;
|
|
10
|
+
if (part === "..") {
|
|
11
|
+
if (parts.length > 0 && parts[parts.length - 1] !== "..") {
|
|
12
|
+
parts.pop();
|
|
13
|
+
} else {
|
|
14
|
+
parts.push("..");
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
parts.push(part);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (parts.length === 0) return ".";
|
|
22
|
+
const result = parts.join(SEP);
|
|
23
|
+
if (segments.length > 0 && segments[0].startsWith("/")) {
|
|
24
|
+
return SEP + result;
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
function resolve(...segments) {
|
|
29
|
+
let resolved = "";
|
|
30
|
+
let isAbs = false;
|
|
31
|
+
for (const seg of segments) {
|
|
32
|
+
if (seg.startsWith("/")) {
|
|
33
|
+
resolved = seg;
|
|
34
|
+
isAbs = true;
|
|
35
|
+
} else if (isAbs) {
|
|
36
|
+
resolved = join(resolved, seg);
|
|
37
|
+
} else {
|
|
38
|
+
resolved = resolved ? join(resolved, seg) : seg;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!isAbs) {
|
|
42
|
+
resolved = join(SEP, resolved);
|
|
43
|
+
}
|
|
44
|
+
return normalize(resolved);
|
|
45
|
+
}
|
|
46
|
+
function basename(p, ext) {
|
|
47
|
+
const normalized = p.replace(/[\\/]+$/, "");
|
|
48
|
+
const idx = normalized.lastIndexOf(SEP);
|
|
49
|
+
let base = idx === -1 ? normalized : normalized.slice(idx + 1);
|
|
50
|
+
if (ext && base.endsWith(ext)) {
|
|
51
|
+
base = base.slice(0, -ext.length);
|
|
52
|
+
}
|
|
53
|
+
return base;
|
|
54
|
+
}
|
|
55
|
+
function dirname(p) {
|
|
56
|
+
if (p === SEP) return SEP;
|
|
57
|
+
const normalized = p.replace(/[\\/]+$/, "");
|
|
58
|
+
if (normalized === "") return ".";
|
|
59
|
+
const idx = normalized.lastIndexOf(SEP);
|
|
60
|
+
if (idx === -1) return ".";
|
|
61
|
+
if (idx === 0) return SEP;
|
|
62
|
+
return normalized.slice(0, idx);
|
|
63
|
+
}
|
|
64
|
+
function extname(p) {
|
|
65
|
+
const base = basename(p);
|
|
66
|
+
const idx = base.lastIndexOf(".");
|
|
67
|
+
if (idx === -1 || idx === 0) return "";
|
|
68
|
+
return base.slice(idx);
|
|
69
|
+
}
|
|
70
|
+
function normalize(p) {
|
|
71
|
+
const parts = p.split(/[\\/]+/);
|
|
72
|
+
const stack = [];
|
|
73
|
+
let isAbs = p.startsWith("/");
|
|
74
|
+
for (const part of parts) {
|
|
75
|
+
if (part === "" || part === ".") continue;
|
|
76
|
+
if (part === "..") {
|
|
77
|
+
if (stack.length > 0 && stack[stack.length - 1] !== "..") {
|
|
78
|
+
stack.pop();
|
|
79
|
+
} else if (!isAbs) {
|
|
80
|
+
stack.push("..");
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
stack.push(part);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const result = stack.join(SEP);
|
|
87
|
+
if (isAbs) return SEP + result;
|
|
88
|
+
if (result === "") return ".";
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
function isAbsolute(p) {
|
|
92
|
+
return p.startsWith("/");
|
|
93
|
+
}
|
|
94
|
+
function relative(from, to) {
|
|
95
|
+
const fromParts = normalize(from).split(SEP);
|
|
96
|
+
const toParts = normalize(to).split(SEP);
|
|
97
|
+
let i = 0;
|
|
98
|
+
while (i < fromParts.length && i < toParts.length && fromParts[i] === toParts[i]) {
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
const up = fromParts.slice(i).map(() => "..");
|
|
102
|
+
const down = toParts.slice(i);
|
|
103
|
+
const result = [...up, ...down].join(SEP);
|
|
104
|
+
return result || ".";
|
|
105
|
+
}
|
|
106
|
+
function parse(p) {
|
|
107
|
+
const root = p.startsWith(SEP) ? SEP : "";
|
|
108
|
+
const base = basename(p);
|
|
109
|
+
const ext = extname(base);
|
|
110
|
+
const name = ext ? base.slice(0, -ext.length) : base;
|
|
111
|
+
const dir = root ? dirname(p) : dirname(p) === "." ? "" : dirname(p);
|
|
112
|
+
return { root, dir, base, name, ext };
|
|
113
|
+
}
|
|
114
|
+
function format(parsed) {
|
|
115
|
+
const { root = "", dir = "", base = "", name = "", ext = "" } = parsed;
|
|
116
|
+
const baseName = base || name + ext;
|
|
117
|
+
if (dir) {
|
|
118
|
+
return dir + SEP + baseName;
|
|
119
|
+
}
|
|
120
|
+
return root + baseName;
|
|
121
|
+
}
|
|
122
|
+
export {
|
|
123
|
+
basename,
|
|
124
|
+
dirname,
|
|
125
|
+
extname,
|
|
126
|
+
format,
|
|
127
|
+
isAbsolute,
|
|
128
|
+
join,
|
|
129
|
+
normalize,
|
|
130
|
+
parse,
|
|
131
|
+
relative,
|
|
132
|
+
resolve
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/path/index.ts"],"sourcesContent":["const SEP = '/'\r\n\r\n/**\r\n * Joins path segments with the proper separator.\r\n *\r\n * @param segments - Path segments to join.\r\n * @returns The joined path.\r\n */\r\nexport function join(...segments: string[]): string {\r\n const parts: string[] = []\r\n for (const seg of segments) {\r\n if (seg === '') continue\r\n const split = seg.split(/[\\\\/]/)\r\n for (const part of split) {\r\n if (part === '' || part === '.') continue\r\n if (part === '..') {\r\n if (parts.length > 0 && parts[parts.length - 1] !== '..') {\r\n parts.pop()\r\n } else {\r\n parts.push('..')\r\n }\r\n } else {\r\n parts.push(part)\r\n }\r\n }\r\n }\r\n if (parts.length === 0) return '.'\r\n const result = parts.join(SEP)\r\n if (segments.length > 0 && segments[0]!.startsWith('/')) {\r\n return SEP + result\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Resolves path segments to an absolute path.\r\n *\r\n * @param segments - Path segments to resolve.\r\n * @returns The resolved absolute path.\r\n */\r\nexport function resolve(...segments: string[]): string {\r\n let resolved = ''\r\n let isAbs = false\r\n\r\n for (const seg of segments) {\r\n if (seg.startsWith('/')) {\r\n resolved = seg\r\n isAbs = true\r\n } else if (isAbs) {\r\n resolved = join(resolved, seg)\r\n } else {\r\n resolved = resolved ? join(resolved, seg) : seg\r\n }\r\n }\r\n\r\n if (!isAbs) {\r\n resolved = join(SEP, resolved)\r\n }\r\n\r\n return normalize(resolved)\r\n}\r\n\r\n/**\r\n * Returns the filename from a path.\r\n *\r\n * @param p - The path.\r\n * @param ext - Optional extension to strip.\r\n * @returns The filename.\r\n */\r\nexport function basename(p: string, ext?: string): string {\r\n const normalized = p.replace(/[\\\\/]+$/, '')\r\n const idx = normalized.lastIndexOf(SEP)\r\n let base = idx === -1 ? normalized : normalized.slice(idx + 1)\r\n if (ext && base.endsWith(ext)) {\r\n base = base.slice(0, -ext.length)\r\n }\r\n return base\r\n}\r\n\r\n/**\r\n * Returns the directory portion of a path.\r\n *\r\n * @param p - The path.\r\n * @returns The directory path.\r\n */\r\nexport function dirname(p: string): string {\r\n if (p === SEP) return SEP\r\n const normalized = p.replace(/[\\\\/]+$/, '')\r\n if (normalized === '') return '.'\r\n const idx = normalized.lastIndexOf(SEP)\r\n if (idx === -1) return '.'\r\n if (idx === 0) return SEP\r\n return normalized.slice(0, idx)\r\n}\r\n\r\n/**\r\n * Returns the file extension from a path.\r\n *\r\n * @param p - The path.\r\n * @returns The extension including the dot, or empty string.\r\n */\r\nexport function extname(p: string): string {\r\n const base = basename(p)\r\n const idx = base.lastIndexOf('.')\r\n if (idx === -1 || idx === 0) return ''\r\n return base.slice(idx)\r\n}\r\n\r\n/**\r\n * Normalizes a path, resolving '..' and '.' segments.\r\n *\r\n * @param p - The path to normalize.\r\n * @returns The normalized path.\r\n */\r\nexport function normalize(p: string): string {\r\n const parts = p.split(/[\\\\/]+/)\r\n const stack: string[] = []\r\n let isAbs = p.startsWith('/')\r\n\r\n for (const part of parts) {\r\n if (part === '' || part === '.') continue\r\n if (part === '..') {\r\n if (stack.length > 0 && stack[stack.length - 1] !== '..') {\r\n stack.pop()\r\n } else if (!isAbs) {\r\n stack.push('..')\r\n }\r\n } else {\r\n stack.push(part)\r\n }\r\n }\r\n\r\n const result = stack.join(SEP)\r\n if (isAbs) return SEP + result\r\n if (result === '') return '.'\r\n return result\r\n}\r\n\r\n/**\r\n * Checks if a path is absolute.\r\n *\r\n * @param p - The path to check.\r\n * @returns Whether the path is absolute.\r\n */\r\nexport function isAbsolute(p: string): boolean {\r\n return p.startsWith('/')\r\n}\r\n\r\n/**\r\n * Computes the relative path from `from` to `to`.\r\n *\r\n * @param from - The base path.\r\n * @param to - The target path.\r\n * @returns The relative path.\r\n */\r\nexport function relative(from: string, to: string): string {\r\n const fromParts = normalize(from).split(SEP)\r\n const toParts = normalize(to).split(SEP)\r\n\r\n let i = 0\r\n while (i < fromParts.length && i < toParts.length && fromParts[i] === toParts[i]) {\r\n i++\r\n }\r\n\r\n const up = fromParts.slice(i).map(() => '..')\r\n const down = toParts.slice(i)\r\n const result = [...up, ...down].join(SEP)\r\n\r\n return result || '.'\r\n}\r\n\r\nexport interface ParsedPath {\r\n root: string\r\n dir: string\r\n base: string\r\n name: string\r\n ext: string\r\n}\r\n\r\n/**\r\n * Parses a path into its components.\r\n *\r\n * @param p - The path to parse.\r\n * @returns An object with root, dir, base, name, and ext.\r\n */\r\nexport function parse(p: string): ParsedPath {\r\n const root = p.startsWith(SEP) ? SEP : ''\r\n const base = basename(p)\r\n const ext = extname(base)\r\n const name = ext ? base.slice(0, -ext.length) : base\r\n const dir = root ? dirname(p) : (dirname(p) === '.' ? '' : dirname(p))\r\n\r\n return { root, dir, base, name, ext }\r\n}\r\n\r\n/**\r\n * Formats a parsed path object back into a path string.\r\n *\r\n * @param parsed - The parsed path components.\r\n * @returns The formatted path string.\r\n */\r\nexport function format(parsed: Partial<ParsedPath>): string {\r\n const { root = '', dir = '', base = '', name = '', ext = '' } = parsed\r\n const baseName = base || name + ext\r\n if (dir) {\r\n return dir + SEP + baseName\r\n }\r\n return root + baseName\r\n}\r\n"],"mappings":"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","names":[]}
|