superjs-core 0.3.4 → 0.3.5
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/async/index.d.ts +84 -1
- package/dist/async/index.js +151 -0
- package/dist/async/index.js.map +1 -1
- package/dist/collection/index.d.ts +7 -1
- package/dist/collection/index.js +55 -0
- package/dist/collection/index.js.map +1 -1
- package/dist/date/index.d.ts +71 -1
- package/dist/date/index.js +121 -1
- package/dist/date/index.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/math/index.d.ts +59 -1
- package/dist/math/index.js +69 -0
- package/dist/math/index.js.map +1 -1
- package/dist/string/index.d.ts +41 -1
- package/dist/string/index.js +117 -0
- package/dist/string/index.js.map +1 -1
- package/package.json +1 -1
package/dist/math/index.d.ts
CHANGED
|
@@ -113,5 +113,63 @@ declare function randomInt(min: number, max: number): number;
|
|
|
113
113
|
* @returns Whether the value is in range.
|
|
114
114
|
*/
|
|
115
115
|
declare function inRange(value: number, min: number, max: number): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Computes the median of an array of numbers.
|
|
118
|
+
*
|
|
119
|
+
* @param values - Array of numbers.
|
|
120
|
+
* @returns The median value.
|
|
121
|
+
* @throws {RangeError} If the array is empty.
|
|
122
|
+
*/
|
|
123
|
+
declare function median(values: number[]): number;
|
|
124
|
+
/**
|
|
125
|
+
* Computes the population standard deviation.
|
|
126
|
+
*
|
|
127
|
+
* @param values - Array of numbers.
|
|
128
|
+
* @returns The standard deviation.
|
|
129
|
+
* @throws {RangeError} If the array has fewer than 2 values.
|
|
130
|
+
*/
|
|
131
|
+
declare function stddev(values: number[]): number;
|
|
132
|
+
/**
|
|
133
|
+
* Computes the sample standard deviation (Bessel's correction).
|
|
134
|
+
*
|
|
135
|
+
* @param values - Array of numbers.
|
|
136
|
+
* @returns The sample standard deviation.
|
|
137
|
+
* @throws {RangeError} If the array has fewer than 2 values.
|
|
138
|
+
*/
|
|
139
|
+
declare function sampleStddev(values: number[]): number;
|
|
140
|
+
/**
|
|
141
|
+
* Computes the percentile value (0-100) using linear interpolation.
|
|
142
|
+
*
|
|
143
|
+
* @param values - Array of numbers.
|
|
144
|
+
* @param p - Percentile (0-100).
|
|
145
|
+
* @returns The percentile value.
|
|
146
|
+
* @throws {RangeError} If p is outside [0, 100] or array is empty.
|
|
147
|
+
*/
|
|
148
|
+
declare function percentile(values: number[], p: number): number;
|
|
149
|
+
/**
|
|
150
|
+
* Computes the Pearson correlation coefficient between two arrays.
|
|
151
|
+
*
|
|
152
|
+
* @param x - First array.
|
|
153
|
+
* @param y - Second array.
|
|
154
|
+
* @returns The correlation coefficient (-1 to 1).
|
|
155
|
+
* @throws {RangeError} If arrays have different lengths or fewer than 2 pairs.
|
|
156
|
+
*/
|
|
157
|
+
declare function correlation(x: number[], y: number[]): number;
|
|
158
|
+
/**
|
|
159
|
+
* Formats a number as a currency string with locale support.
|
|
160
|
+
*
|
|
161
|
+
* @example formatCurrency(1500000) // "Rp1.500.000"
|
|
162
|
+
* @example formatCurrency(1500000, { notation: 'compact' }) // "Rp1,5 jt"
|
|
163
|
+
* @example formatCurrency(99.99, { locale: 'en-US', currency: 'USD' }) // "$99.99"
|
|
164
|
+
*
|
|
165
|
+
* @param value - The number to format.
|
|
166
|
+
* @param options - Formatting options.
|
|
167
|
+
* @returns The formatted currency string.
|
|
168
|
+
*/
|
|
169
|
+
declare function formatCurrency(value: number, options?: {
|
|
170
|
+
locale?: string;
|
|
171
|
+
currency?: string;
|
|
172
|
+
notation?: 'standard' | 'compact';
|
|
173
|
+
}): string;
|
|
116
174
|
|
|
117
|
-
export { DivisionByZeroError, add, approxEqual, average, ceil, clamp, div, floor, inRange, mul, randomInt, round, sub, sum };
|
|
175
|
+
export { DivisionByZeroError, add, approxEqual, average, ceil, clamp, correlation, div, floor, formatCurrency, inRange, median, mul, percentile, randomInt, round, sampleStddev, stddev, sub, sum };
|
package/dist/math/index.js
CHANGED
|
@@ -86,6 +86,69 @@ function randomInt(min, max) {
|
|
|
86
86
|
function inRange(value, min, max) {
|
|
87
87
|
return value >= min && value <= max;
|
|
88
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
|
+
}
|
|
89
152
|
export {
|
|
90
153
|
DivisionByZeroError,
|
|
91
154
|
add,
|
|
@@ -93,12 +156,18 @@ export {
|
|
|
93
156
|
average,
|
|
94
157
|
ceil,
|
|
95
158
|
clamp,
|
|
159
|
+
correlation,
|
|
96
160
|
div,
|
|
97
161
|
floor,
|
|
162
|
+
formatCurrency,
|
|
98
163
|
inRange,
|
|
164
|
+
median,
|
|
99
165
|
mul,
|
|
166
|
+
percentile,
|
|
100
167
|
randomInt,
|
|
101
168
|
round,
|
|
169
|
+
sampleStddev,
|
|
170
|
+
stddev,
|
|
102
171
|
sub,
|
|
103
172
|
sum
|
|
104
173
|
};
|
package/dist/math/index.js.map
CHANGED
|
@@ -1 +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"],"mappings":"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","names":[]}
|
|
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"],"mappings":"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","names":[]}
|
package/dist/string/index.d.ts
CHANGED
|
@@ -87,5 +87,45 @@ declare function slugify(str: string): string;
|
|
|
87
87
|
* Counts occurrences of a substring in a string.
|
|
88
88
|
*/
|
|
89
89
|
declare function countOccurrences(str: string, substring: string): number;
|
|
90
|
+
/**
|
|
91
|
+
* Computes the Levenshtein distance between two strings.
|
|
92
|
+
* Uses iterative DP with O(min(m,n)) space.
|
|
93
|
+
*/
|
|
94
|
+
declare function levenshtein(a: string, b: string): number;
|
|
95
|
+
/**
|
|
96
|
+
* Performs a simple fuzzy match: checks if all characters of query
|
|
97
|
+
* appear in str in order (case-insensitive).
|
|
98
|
+
*/
|
|
99
|
+
declare function fuzzyMatch(str: string, query: string): boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Masks parts of a string, useful for data compliance (PDPA/GDPR).
|
|
102
|
+
*
|
|
103
|
+
* @example maskString('08123456789') // "0812****789"
|
|
104
|
+
* @example maskString('hello@email.com') // "h***@e***.com"
|
|
105
|
+
* @example maskString('1234567890', { start: 0, end: 4, char: '#' }) // "####567890"
|
|
106
|
+
*/
|
|
107
|
+
declare function maskString(str: string, options?: {
|
|
108
|
+
start?: number;
|
|
109
|
+
end?: number;
|
|
110
|
+
char?: string;
|
|
111
|
+
}): string;
|
|
112
|
+
/**
|
|
113
|
+
* Converts a number to Indonesian words (terbilang).
|
|
114
|
+
*
|
|
115
|
+
* @example terbilang(1500000) // "satu juta lima ratus ribu"
|
|
116
|
+
* @example terbilang(2024) // "dua ribu dua puluh empat"
|
|
117
|
+
* @example terbilang(11) // "sebelas"
|
|
118
|
+
* @example terbilang(100) // "seratus"
|
|
119
|
+
*/
|
|
120
|
+
declare function terbilang(value: number): string;
|
|
121
|
+
/**
|
|
122
|
+
* Formats a number as Indonesian Rupiah string.
|
|
123
|
+
*
|
|
124
|
+
* @example formatRupiah(1500000) // "Rp1.500.000"
|
|
125
|
+
* @example formatRupiah(1500000, { notation: 'compact' }) // "Rp1,5 jt"
|
|
126
|
+
*/
|
|
127
|
+
declare function formatRupiah(value: number, options?: {
|
|
128
|
+
notation?: 'standard' | 'compact';
|
|
129
|
+
}): string;
|
|
90
130
|
|
|
91
|
-
export { camelCase, capitalize, countOccurrences, escapeHtml, kebabCase, nanoid, pad, padEnd, padStart, pascalCase, reverse, slugify, snakeCase, template, trim, trimEnd, trimStart, truncate, unescapeHtml, uuid, words };
|
|
131
|
+
export { camelCase, capitalize, countOccurrences, escapeHtml, formatRupiah, fuzzyMatch, kebabCase, levenshtein, maskString, nanoid, pad, padEnd, padStart, pascalCase, reverse, slugify, snakeCase, template, terbilang, trim, trimEnd, trimStart, truncate, unescapeHtml, uuid, words };
|
package/dist/string/index.js
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
// src/math/index.ts
|
|
2
|
+
function formatCurrency(value, options) {
|
|
3
|
+
const locale = options?.locale ?? "id-ID";
|
|
4
|
+
const currency = options?.currency ?? "IDR";
|
|
5
|
+
const notation = options?.notation ?? "standard";
|
|
6
|
+
try {
|
|
7
|
+
return new Intl.NumberFormat(locale, {
|
|
8
|
+
style: "currency",
|
|
9
|
+
currency,
|
|
10
|
+
notation,
|
|
11
|
+
minimumFractionDigits: 0,
|
|
12
|
+
maximumFractionDigits: 2
|
|
13
|
+
}).format(value);
|
|
14
|
+
} catch {
|
|
15
|
+
return `${currency} ${value.toLocaleString(locale)}`;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
1
19
|
// src/string/index.ts
|
|
2
20
|
var WORD_SPLIT_RE = /[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|\d|\b)|\d+/g;
|
|
3
21
|
function splitWords(str) {
|
|
@@ -120,12 +138,110 @@ function countOccurrences(str, substring) {
|
|
|
120
138
|
}
|
|
121
139
|
return count;
|
|
122
140
|
}
|
|
141
|
+
function levenshtein(a, b) {
|
|
142
|
+
const an = a.length;
|
|
143
|
+
const bn = b.length;
|
|
144
|
+
if (an === 0) return bn;
|
|
145
|
+
if (bn === 0) return an;
|
|
146
|
+
if (an < bn) return levenshtein(b, a);
|
|
147
|
+
let prev = new Uint32Array(bn + 1);
|
|
148
|
+
let curr = new Uint32Array(bn + 1);
|
|
149
|
+
for (let j = 0; j <= bn; j++) prev[j] = j;
|
|
150
|
+
for (let i = 1; i <= an; i++) {
|
|
151
|
+
curr[0] = i;
|
|
152
|
+
for (let j = 1; j <= bn; j++) {
|
|
153
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
154
|
+
curr[j] = Math.min(
|
|
155
|
+
prev[j] + 1,
|
|
156
|
+
curr[j - 1] + 1,
|
|
157
|
+
prev[j - 1] + cost
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
;
|
|
161
|
+
[prev, curr] = [curr, prev];
|
|
162
|
+
}
|
|
163
|
+
return prev[bn];
|
|
164
|
+
}
|
|
165
|
+
function fuzzyMatch(str, query) {
|
|
166
|
+
if (query.length === 0) return true;
|
|
167
|
+
if (str.length === 0) return false;
|
|
168
|
+
const sl = str.toLowerCase();
|
|
169
|
+
const ql = query.toLowerCase();
|
|
170
|
+
let si = 0;
|
|
171
|
+
for (let qi = 0; qi < ql.length; qi++) {
|
|
172
|
+
si = sl.indexOf(ql[qi], si);
|
|
173
|
+
if (si === -1) return false;
|
|
174
|
+
si++;
|
|
175
|
+
}
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
function maskString(str, options) {
|
|
179
|
+
if (str.length === 0) return str;
|
|
180
|
+
const maskChar = options?.char ?? "*";
|
|
181
|
+
const start = options?.start ?? Math.ceil(str.length * 0.25);
|
|
182
|
+
const end = options?.end ?? Math.floor(str.length * 0.75);
|
|
183
|
+
if (start >= end || start < 0) return str;
|
|
184
|
+
const clampedStart = Math.max(0, start);
|
|
185
|
+
const clampedEnd = Math.min(str.length, end);
|
|
186
|
+
return str.slice(0, clampedStart) + maskChar.repeat(clampedEnd - clampedStart) + str.slice(clampedEnd);
|
|
187
|
+
}
|
|
188
|
+
var SATUAN = ["", "satu", "dua", "tiga", "empat", "lima", "enam", "tujuh", "delapan", "sembilan"];
|
|
189
|
+
var BELASAN = ["sepuluh", "sebelas", "dua belas", "tiga belas", "empat belas", "lima belas", "enam belas", "tujuh belas", "delapan belas", "sembilan belas"];
|
|
190
|
+
var PULUHAN = ["", "", "dua puluh", "tiga puluh", "empat puluh", "lima puluh", "enam puluh", "tujuh puluh", "delapan puluh", "sembilan puluh"];
|
|
191
|
+
function _terbilang(n) {
|
|
192
|
+
if (n < 0) return "minus " + _terbilang(-n);
|
|
193
|
+
if (n === 0) return "nol";
|
|
194
|
+
if (n < 10) return SATUAN[n];
|
|
195
|
+
if (n < 20) return n === 10 ? "sepuluh" : n === 11 ? "sebelas" : BELASAN[n - 10];
|
|
196
|
+
if (n < 100) {
|
|
197
|
+
const pul = Math.floor(n / 10);
|
|
198
|
+
const sat = n % 10;
|
|
199
|
+
return PULUHAN[pul] + (sat > 0 ? " " + SATUAN[sat] : "");
|
|
200
|
+
}
|
|
201
|
+
if (n < 1e3) {
|
|
202
|
+
const ratus = Math.floor(n / 100);
|
|
203
|
+
const sis2 = n % 100;
|
|
204
|
+
const ratusStr = ratus === 1 ? "seratus" : SATUAN[ratus] + " ratus";
|
|
205
|
+
return ratusStr + (sis2 > 0 ? " " + _terbilang(sis2) : "");
|
|
206
|
+
}
|
|
207
|
+
if (n < 1e6) {
|
|
208
|
+
const rib = Math.floor(n / 1e3);
|
|
209
|
+
const sis2 = n % 1e3;
|
|
210
|
+
const ribStr = rib === 1 ? "seribu" : _terbilang(rib) + " ribu";
|
|
211
|
+
return ribStr + (sis2 > 0 ? " " + _terbilang(sis2) : "");
|
|
212
|
+
}
|
|
213
|
+
if (n < 1e9) {
|
|
214
|
+
const jut = Math.floor(n / 1e6);
|
|
215
|
+
const sis2 = n % 1e6;
|
|
216
|
+
return _terbilang(jut) + " juta" + (sis2 > 0 ? " " + _terbilang(sis2) : "");
|
|
217
|
+
}
|
|
218
|
+
if (n < 1e12) {
|
|
219
|
+
const mil = Math.floor(n / 1e9);
|
|
220
|
+
const sis2 = n % 1e9;
|
|
221
|
+
return _terbilang(mil) + " miliar" + (sis2 > 0 ? " " + _terbilang(sis2) : "");
|
|
222
|
+
}
|
|
223
|
+
const tril = Math.floor(n / 1e12);
|
|
224
|
+
const sis = n % 1e12;
|
|
225
|
+
return _terbilang(tril) + " triliun" + (sis > 0 ? " " + _terbilang(sis) : "");
|
|
226
|
+
}
|
|
227
|
+
function terbilang(value) {
|
|
228
|
+
if (!Number.isFinite(value)) throw new RangeError("Input must be a finite number");
|
|
229
|
+
if (value > Number.MAX_SAFE_INTEGER) throw new RangeError("Input terlalu besar");
|
|
230
|
+
return _terbilang(Math.floor(Math.abs(value)));
|
|
231
|
+
}
|
|
232
|
+
function formatRupiah(value, options) {
|
|
233
|
+
return formatCurrency(value, { locale: "id-ID", currency: "IDR", notation: options?.notation });
|
|
234
|
+
}
|
|
123
235
|
export {
|
|
124
236
|
camelCase,
|
|
125
237
|
capitalize,
|
|
126
238
|
countOccurrences,
|
|
127
239
|
escapeHtml,
|
|
240
|
+
formatRupiah,
|
|
241
|
+
fuzzyMatch,
|
|
128
242
|
kebabCase,
|
|
243
|
+
levenshtein,
|
|
244
|
+
maskString,
|
|
129
245
|
nanoid,
|
|
130
246
|
pad,
|
|
131
247
|
padEnd,
|
|
@@ -135,6 +251,7 @@ export {
|
|
|
135
251
|
slugify,
|
|
136
252
|
snakeCase,
|
|
137
253
|
template,
|
|
254
|
+
terbilang,
|
|
138
255
|
trim,
|
|
139
256
|
trimEnd,
|
|
140
257
|
trimStart,
|
package/dist/string/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/string/index.ts"],"sourcesContent":["const WORD_SPLIT_RE = /[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|\\d|\\b)|\\d+/g\r\n\r\nfunction splitWords(str: string): string[] {\r\n return str.match(WORD_SPLIT_RE) ?? []\r\n}\r\n\r\n/**\r\n * Capitalizes the first character and lowercases the rest.\r\n */\r\nexport function capitalize(str: string): string {\r\n if (str.length === 0) return str\r\n return str[0]!.toUpperCase() + str.slice(1).toLowerCase()\r\n}\r\n\r\n/**\r\n * Converts a string to camelCase.\r\n */\r\nexport function camelCase(str: string): string {\r\n const words = splitWords(str)\r\n if (words.length === 0) return ''\r\n const [firstWord, ...rest] = words\r\n return firstWord!.toLowerCase() + rest.map(w => w[0]!.toUpperCase() + w.slice(1).toLowerCase()).join('')\r\n}\r\n\r\n/**\r\n * Converts a string to kebab-case.\r\n */\r\nexport function kebabCase(str: string): string {\r\n return splitWords(str).map(w => w.toLowerCase()).join('-')\r\n}\r\n\r\n/**\r\n * Converts a string to snake_case.\r\n */\r\nexport function snakeCase(str: string): string {\r\n return splitWords(str).map(w => w.toLowerCase()).join('_')\r\n}\r\n\r\n/**\r\n * Converts a string to PascalCase.\r\n */\r\nexport function pascalCase(str: string): string {\r\n return splitWords(str).map(w => w[0]!.toUpperCase() + w.slice(1).toLowerCase()).join('')\r\n}\r\n\r\n/**\r\n * Truncates a string to the specified length, appending a suffix (default \"...\").\r\n */\r\nexport function truncate(str: string, maxLength: number, suffix = '...'): string {\r\n if (str.length <= maxLength) return str\r\n return str.slice(0, Math.max(0, maxLength - suffix.length)) + suffix\r\n}\r\n\r\n/**\r\n * Simple string interpolation using {{key}} syntax.\r\n *\r\n * @example template(\"Hello {{name}}\", { name: \"world\" }) // => \"Hello world\"\r\n */\r\nexport function template(str: string, data: Record<string, string | number>): string {\r\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key: string) => {\r\n const value = data[key]\r\n return value !== undefined ? String(value) : `{{${key}}}`\r\n })\r\n}\r\n\r\n/**\r\n * Generates a UUID v4 string.\r\n * Uses crypto.randomUUID when available, falls back to manual implementation.\r\n */\r\nexport function uuid(): string {\r\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\r\n return crypto.randomUUID()\r\n }\r\n const hex = '0123456789abcdef'\r\n const chars: string[] = []\r\n for (let i = 0; i < 36; i++) {\r\n if (i === 8 || i === 13 || i === 18 || i === 23) {\r\n chars.push('-')\r\n } else if (i === 14) {\r\n chars.push('4')\r\n } else if (i === 19) {\r\n chars.push(hex[Math.floor(Math.random() * 4) + 8]!)\r\n } else {\r\n chars.push(hex[Math.floor(Math.random() * 16)]!)\r\n }\r\n }\r\n return chars.join('')\r\n}\r\n\r\n/**\r\n * Generates a short random ID with configurable length and alphabet.\r\n *\r\n * @default size = 21, alphabet = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-\"\r\n */\r\nexport function nanoid(size = 21, alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-'): string {\r\n const len = alphabet.length\r\n let result = ''\r\n for (let i = 0; i < size; i++) {\r\n result += alphabet[Math.floor(Math.random() * len)]!\r\n }\r\n return result\r\n}\r\n\r\nconst HTML_ESCAPE_MAP: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n}\r\n\r\nconst HTML_UNESCAPE_MAP: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '"': '\"',\r\n ''': \"'\",\r\n ''': \"'\",\r\n}\r\n\r\n/**\r\n * Escapes HTML special characters (&, <, >, \", ').\r\n */\r\nexport function escapeHtml(str: string): string {\r\n return str.replace(/[&<>\"']/g, ch => HTML_ESCAPE_MAP[ch] ?? ch)\r\n}\r\n\r\n/**\r\n * Unescapes common HTML entities.\r\n */\r\nexport function unescapeHtml(str: string): string {\r\n return str.replace(/&(?:amp|lt|gt|quot|#39|#x27);/g, entity => HTML_UNESCAPE_MAP[entity] ?? entity)\r\n}\r\n\r\n/**\r\n * Removes whitespace from both ends of a string.\r\n */\r\nexport function trim(str: string): string {\r\n return str.trim()\r\n}\r\n\r\n/**\r\n * Removes whitespace from the start of a string.\r\n */\r\nexport function trimStart(str: string): string {\r\n return str.trimStart()\r\n}\r\n\r\n/**\r\n * Removes whitespace from the end of a string.\r\n */\r\nexport function trimEnd(str: string): string {\r\n return str.trimEnd()\r\n}\r\n\r\n/**\r\n * Pads a string to the given length by adding characters to both sides.\r\n */\r\nexport function pad(str: string, length: number, char = ' '): string {\r\n const totalPadding = Math.max(0, length - str.length)\r\n const leftPad = Math.floor(totalPadding / 2)\r\n const rightPad = totalPadding - leftPad\r\n return char.repeat(leftPad) + str + char.repeat(rightPad)\r\n}\r\n\r\n/**\r\n * Pads the start of a string to the given length.\r\n */\r\nexport function padStart(str: string, length: number, char = ' '): string {\r\n return str.padStart(length, char)\r\n}\r\n\r\n/**\r\n * Pads the end of a string to the given length.\r\n */\r\nexport function padEnd(str: string, length: number, char = ' '): string {\r\n return str.padEnd(length, char)\r\n}\r\n\r\n/**\r\n * Reverses a string.\r\n */\r\nexport function reverse(str: string): string {\r\n return str.split('').reverse().join('')\r\n}\r\n\r\n/**\r\n * Splits a string into words.\r\n */\r\nexport function words(str: string): string[] {\r\n return splitWords(str)\r\n}\r\n\r\n/**\r\n * Converts a string to a URL-friendly slug.\r\n */\r\nexport function slugify(str: string): string {\r\n return str\r\n .toLowerCase()\r\n .replace(/[^\\w\\s-]/g, '')\r\n .replace(/[\\s_]+/g, '-')\r\n .replace(/-+/g, '-')\r\n .replace(/^-+/, '')\r\n .replace(/-+$/, '')\r\n}\r\n\r\n/**\r\n * Counts occurrences of a substring in a string.\r\n */\r\nexport function countOccurrences(str: string, substring: string): number {\r\n if (substring.length === 0 || str.length === 0) return 0\r\n let count = 0\r\n let pos = 0\r\n while ((pos = str.indexOf(substring, pos)) !== -1) {\r\n count++\r\n pos += substring.length\r\n }\r\n return count\r\n}\r\n"],"mappings":"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","names":["words"]}
|
|
1
|
+
{"version":3,"sources":["../../src/math/index.ts","../../src/string/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","import { formatCurrency } from '../math/index.js'\r\n\r\nconst WORD_SPLIT_RE = /[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|\\d|\\b)|\\d+/g\r\n\r\nfunction splitWords(str: string): string[] {\r\n return str.match(WORD_SPLIT_RE) ?? []\r\n}\r\n\r\n/**\r\n * Capitalizes the first character and lowercases the rest.\r\n */\r\nexport function capitalize(str: string): string {\r\n if (str.length === 0) return str\r\n return str[0]!.toUpperCase() + str.slice(1).toLowerCase()\r\n}\r\n\r\n/**\r\n * Converts a string to camelCase.\r\n */\r\nexport function camelCase(str: string): string {\r\n const words = splitWords(str)\r\n if (words.length === 0) return ''\r\n const [firstWord, ...rest] = words\r\n return firstWord!.toLowerCase() + rest.map(w => w[0]!.toUpperCase() + w.slice(1).toLowerCase()).join('')\r\n}\r\n\r\n/**\r\n * Converts a string to kebab-case.\r\n */\r\nexport function kebabCase(str: string): string {\r\n return splitWords(str).map(w => w.toLowerCase()).join('-')\r\n}\r\n\r\n/**\r\n * Converts a string to snake_case.\r\n */\r\nexport function snakeCase(str: string): string {\r\n return splitWords(str).map(w => w.toLowerCase()).join('_')\r\n}\r\n\r\n/**\r\n * Converts a string to PascalCase.\r\n */\r\nexport function pascalCase(str: string): string {\r\n return splitWords(str).map(w => w[0]!.toUpperCase() + w.slice(1).toLowerCase()).join('')\r\n}\r\n\r\n/**\r\n * Truncates a string to the specified length, appending a suffix (default \"...\").\r\n */\r\nexport function truncate(str: string, maxLength: number, suffix = '...'): string {\r\n if (str.length <= maxLength) return str\r\n return str.slice(0, Math.max(0, maxLength - suffix.length)) + suffix\r\n}\r\n\r\n/**\r\n * Simple string interpolation using {{key}} syntax.\r\n *\r\n * @example template(\"Hello {{name}}\", { name: \"world\" }) // => \"Hello world\"\r\n */\r\nexport function template(str: string, data: Record<string, string | number>): string {\r\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key: string) => {\r\n const value = data[key]\r\n return value !== undefined ? String(value) : `{{${key}}}`\r\n })\r\n}\r\n\r\n/**\r\n * Generates a UUID v4 string.\r\n * Uses crypto.randomUUID when available, falls back to manual implementation.\r\n */\r\nexport function uuid(): string {\r\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\r\n return crypto.randomUUID()\r\n }\r\n const hex = '0123456789abcdef'\r\n const chars: string[] = []\r\n for (let i = 0; i < 36; i++) {\r\n if (i === 8 || i === 13 || i === 18 || i === 23) {\r\n chars.push('-')\r\n } else if (i === 14) {\r\n chars.push('4')\r\n } else if (i === 19) {\r\n chars.push(hex[Math.floor(Math.random() * 4) + 8]!)\r\n } else {\r\n chars.push(hex[Math.floor(Math.random() * 16)]!)\r\n }\r\n }\r\n return chars.join('')\r\n}\r\n\r\n/**\r\n * Generates a short random ID with configurable length and alphabet.\r\n *\r\n * @default size = 21, alphabet = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-\"\r\n */\r\nexport function nanoid(size = 21, alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-'): string {\r\n const len = alphabet.length\r\n let result = ''\r\n for (let i = 0; i < size; i++) {\r\n result += alphabet[Math.floor(Math.random() * len)]!\r\n }\r\n return result\r\n}\r\n\r\nconst HTML_ESCAPE_MAP: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n}\r\n\r\nconst HTML_UNESCAPE_MAP: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '"': '\"',\r\n ''': \"'\",\r\n ''': \"'\",\r\n}\r\n\r\n/**\r\n * Escapes HTML special characters (&, <, >, \", ').\r\n */\r\nexport function escapeHtml(str: string): string {\r\n return str.replace(/[&<>\"']/g, ch => HTML_ESCAPE_MAP[ch] ?? ch)\r\n}\r\n\r\n/**\r\n * Unescapes common HTML entities.\r\n */\r\nexport function unescapeHtml(str: string): string {\r\n return str.replace(/&(?:amp|lt|gt|quot|#39|#x27);/g, entity => HTML_UNESCAPE_MAP[entity] ?? entity)\r\n}\r\n\r\n/**\r\n * Removes whitespace from both ends of a string.\r\n */\r\nexport function trim(str: string): string {\r\n return str.trim()\r\n}\r\n\r\n/**\r\n * Removes whitespace from the start of a string.\r\n */\r\nexport function trimStart(str: string): string {\r\n return str.trimStart()\r\n}\r\n\r\n/**\r\n * Removes whitespace from the end of a string.\r\n */\r\nexport function trimEnd(str: string): string {\r\n return str.trimEnd()\r\n}\r\n\r\n/**\r\n * Pads a string to the given length by adding characters to both sides.\r\n */\r\nexport function pad(str: string, length: number, char = ' '): string {\r\n const totalPadding = Math.max(0, length - str.length)\r\n const leftPad = Math.floor(totalPadding / 2)\r\n const rightPad = totalPadding - leftPad\r\n return char.repeat(leftPad) + str + char.repeat(rightPad)\r\n}\r\n\r\n/**\r\n * Pads the start of a string to the given length.\r\n */\r\nexport function padStart(str: string, length: number, char = ' '): string {\r\n return str.padStart(length, char)\r\n}\r\n\r\n/**\r\n * Pads the end of a string to the given length.\r\n */\r\nexport function padEnd(str: string, length: number, char = ' '): string {\r\n return str.padEnd(length, char)\r\n}\r\n\r\n/**\r\n * Reverses a string.\r\n */\r\nexport function reverse(str: string): string {\r\n return str.split('').reverse().join('')\r\n}\r\n\r\n/**\r\n * Splits a string into words.\r\n */\r\nexport function words(str: string): string[] {\r\n return splitWords(str)\r\n}\r\n\r\n/**\r\n * Converts a string to a URL-friendly slug.\r\n */\r\nexport function slugify(str: string): string {\r\n return str\r\n .toLowerCase()\r\n .replace(/[^\\w\\s-]/g, '')\r\n .replace(/[\\s_]+/g, '-')\r\n .replace(/-+/g, '-')\r\n .replace(/^-+/, '')\r\n .replace(/-+$/, '')\r\n}\r\n\r\n/**\r\n * Counts occurrences of a substring in a string.\r\n */\r\nexport function countOccurrences(str: string, substring: string): number {\r\n if (substring.length === 0 || str.length === 0) return 0\r\n let count = 0\r\n let pos = 0\r\n while ((pos = str.indexOf(substring, pos)) !== -1) {\r\n count++\r\n pos += substring.length\r\n }\r\n return count\r\n}\r\n\r\n/**\r\n * Computes the Levenshtein distance between two strings.\r\n * Uses iterative DP with O(min(m,n)) space.\r\n */\r\nexport function levenshtein(a: string, b: string): number {\r\n const an = a.length\r\n const bn = b.length\r\n if (an === 0) return bn\r\n if (bn === 0) return an\r\n if (an < bn) return levenshtein(b, a)\r\n\r\n let prev = new Uint32Array(bn + 1)\r\n let curr = new Uint32Array(bn + 1)\r\n for (let j = 0; j <= bn; j++) prev[j] = j\r\n\r\n for (let i = 1; i <= an; i++) {\r\n curr[0] = i\r\n for (let j = 1; j <= bn; j++) {\r\n const cost = a[i - 1] === b[j - 1] ? 0 : 1\r\n curr[j] = Math.min(\r\n prev[j]! + 1,\r\n curr[j - 1]! + 1,\r\n prev[j - 1]! + cost,\r\n )\r\n }\r\n ;[prev, curr] = [curr, prev]\r\n }\r\n return prev[bn]!\r\n}\r\n\r\n/**\r\n * Performs a simple fuzzy match: checks if all characters of query\r\n * appear in str in order (case-insensitive).\r\n */\r\nexport function fuzzyMatch(str: string, query: string): boolean {\r\n if (query.length === 0) return true\r\n if (str.length === 0) return false\r\n const sl = str.toLowerCase()\r\n const ql = query.toLowerCase()\r\n let si = 0\r\n for (let qi = 0; qi < ql.length; qi++) {\r\n si = sl.indexOf(ql[qi]!, si)\r\n if (si === -1) return false\r\n si++\r\n }\r\n return true\r\n}\r\n\r\n/**\r\n * Masks parts of a string, useful for data compliance (PDPA/GDPR).\r\n *\r\n * @example maskString('08123456789') // \"0812****789\"\r\n * @example maskString('hello@email.com') // \"h***@e***.com\"\r\n * @example maskString('1234567890', { start: 0, end: 4, char: '#' }) // \"####567890\"\r\n */\r\nexport function maskString(\r\n str: string,\r\n options?: {\r\n start?: number\r\n end?: number\r\n char?: string\r\n },\r\n): string {\r\n if (str.length === 0) return str\r\n const maskChar = options?.char ?? '*'\r\n const start = options?.start ?? Math.ceil(str.length * 0.25)\r\n const end = options?.end ?? Math.floor(str.length * 0.75)\r\n\r\n if (start >= end || start < 0) return str\r\n const clampedStart = Math.max(0, start)\r\n const clampedEnd = Math.min(str.length, end)\r\n return (\r\n str.slice(0, clampedStart) +\r\n maskChar.repeat(clampedEnd - clampedStart) +\r\n str.slice(clampedEnd)\r\n )\r\n}\r\n\r\n// ─── Indonesian Locale Utilities ────────────────────────\r\n\r\nconst SATUAN = ['', 'satu', 'dua', 'tiga', 'empat', 'lima', 'enam', 'tujuh', 'delapan', 'sembilan'] as const\r\nconst BELASAN = ['sepuluh', 'sebelas', 'dua belas', 'tiga belas', 'empat belas', 'lima belas', 'enam belas', 'tujuh belas', 'delapan belas', 'sembilan belas'] as const\r\nconst PULUHAN = ['', '', 'dua puluh', 'tiga puluh', 'empat puluh', 'lima puluh', 'enam puluh', 'tujuh puluh', 'delapan puluh', 'sembilan puluh'] as const\r\n\r\nfunction _terbilang(n: number): string {\r\n if (n < 0) return 'minus ' + _terbilang(-n)\r\n if (n === 0) return 'nol'\r\n if (n < 10) return SATUAN[n]!\r\n if (n < 20) return n === 10 ? 'sepuluh' : n === 11 ? 'sebelas' : BELASAN[n - 10]!\r\n if (n < 100) {\r\n const pul = Math.floor(n / 10)\r\n const sat = n % 10\r\n return PULUHAN[pul]! + (sat > 0 ? ' ' + SATUAN[sat]! : '')\r\n }\r\n if (n < 1000) {\r\n const ratus = Math.floor(n / 100)\r\n const sis = n % 100\r\n const ratusStr = ratus === 1 ? 'seratus' : SATUAN[ratus]! + ' ratus'\r\n return ratusStr + (sis > 0 ? ' ' + _terbilang(sis) : '')\r\n }\r\n if (n < 1_000_000) {\r\n const rib = Math.floor(n / 1000)\r\n const sis = n % 1000\r\n const ribStr = rib === 1 ? 'seribu' : _terbilang(rib) + ' ribu'\r\n return ribStr + (sis > 0 ? ' ' + _terbilang(sis) : '')\r\n }\r\n if (n < 1_000_000_000) {\r\n const jut = Math.floor(n / 1_000_000)\r\n const sis = n % 1_000_000\r\n return _terbilang(jut) + ' juta' + (sis > 0 ? ' ' + _terbilang(sis) : '')\r\n }\r\n if (n < 1_000_000_000_000) {\r\n const mil = Math.floor(n / 1_000_000_000)\r\n const sis = n % 1_000_000_000\r\n return _terbilang(mil) + ' miliar' + (sis > 0 ? ' ' + _terbilang(sis) : '')\r\n }\r\n const tril = Math.floor(n / 1_000_000_000_000)\r\n const sis = n % 1_000_000_000_000\r\n return _terbilang(tril) + ' triliun' + (sis > 0 ? ' ' + _terbilang(sis) : '')\r\n}\r\n\r\n/**\r\n * Converts a number to Indonesian words (terbilang).\r\n *\r\n * @example terbilang(1500000) // \"satu juta lima ratus ribu\"\r\n * @example terbilang(2024) // \"dua ribu dua puluh empat\"\r\n * @example terbilang(11) // \"sebelas\"\r\n * @example terbilang(100) // \"seratus\"\r\n */\r\nexport function terbilang(value: number): string {\r\n if (!Number.isFinite(value)) throw new RangeError('Input must be a finite number')\r\n if (value > Number.MAX_SAFE_INTEGER) throw new RangeError('Input terlalu besar')\r\n return _terbilang(Math.floor(Math.abs(value)))\r\n}\r\n\r\n/**\r\n * Formats a number as Indonesian Rupiah string.\r\n *\r\n * @example formatRupiah(1500000) // \"Rp1.500.000\"\r\n * @example formatRupiah(1500000, { notation: 'compact' }) // \"Rp1,5 jt\"\r\n */\r\nexport function formatRupiah(\r\n value: number,\r\n options?: { notation?: 'standard' | 'compact' },\r\n): string {\r\n return formatCurrency(value, { locale: 'id-ID', currency: 'IDR', notation: options?.notation })\r\n}\r\n"],"mappings":"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","names":["words","sis"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superjs-core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "Zero-dependency JavaScript standard library + dependency health scanner — core, math, date, collection, string, async, io, type, crypto, path & dep-exray",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|