feat(pure): parseTarget with comma and magnitude suffix support
This commit is contained in:
+1
-1
@@ -4,6 +4,6 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node --test tests/"
|
"test": "node --test"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
const SUFFIXES = { k: 1e3, m: 1e6, b: 1e9, t: 1e12 };
|
||||||
|
|
||||||
|
export function parseTarget(input) {
|
||||||
|
if (input === null || input === undefined || input === '') return null;
|
||||||
|
|
||||||
|
if (typeof input === 'number') {
|
||||||
|
if (!Number.isFinite(input) || input <= 0) return null;
|
||||||
|
return Math.floor(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof input !== 'string') return null;
|
||||||
|
|
||||||
|
const cleaned = input.replace(/,/g, '').trim().toLowerCase();
|
||||||
|
if (cleaned === '') return null;
|
||||||
|
|
||||||
|
// Reject anything other than digits, optional decimal, and optional single trailing suffix letter
|
||||||
|
if (!/^\d+(\.\d+)?[kmbt]?$/.test(cleaned)) return null;
|
||||||
|
|
||||||
|
const match = cleaned.match(/^(\d+(?:\.\d+)?)([kmbt])?$/);
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
const num = parseFloat(match[1]);
|
||||||
|
if (!Number.isFinite(num) || num <= 0) return null;
|
||||||
|
|
||||||
|
const suffix = match[2];
|
||||||
|
const multiplier = suffix ? SUFFIXES[suffix] : 1;
|
||||||
|
return Math.floor(num * multiplier);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { test } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { parseTarget } from '../src/pure.js';
|
||||||
|
|
||||||
|
test('parseTarget: integer numbers', () => {
|
||||||
|
assert.equal(parseTarget(25), 25);
|
||||||
|
assert.equal(parseTarget(25000000), 25_000_000);
|
||||||
|
assert.equal(parseTarget(2.5e7), 25_000_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parseTarget: string numbers with commas', () => {
|
||||||
|
assert.equal(parseTarget('25'), 25);
|
||||||
|
assert.equal(parseTarget('25,000,000'), 25_000_000);
|
||||||
|
assert.equal(parseTarget('25,000,000.5'), 25_000_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parseTarget: magnitude suffixes (case-insensitive)', () => {
|
||||||
|
assert.equal(parseTarget('25K'), 25_000);
|
||||||
|
assert.equal(parseTarget('25m'), 25_000_000);
|
||||||
|
assert.equal(parseTarget('1.5B'), 1_500_000_000);
|
||||||
|
assert.equal(parseTarget('100t'), 100_000_000_000_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parseTarget: rejects invalid input', () => {
|
||||||
|
assert.equal(parseTarget(0), null);
|
||||||
|
assert.equal(parseTarget(-1), null);
|
||||||
|
assert.equal(parseTarget('abc'), null);
|
||||||
|
assert.equal(parseTarget(''), null);
|
||||||
|
assert.equal(parseTarget(null), null);
|
||||||
|
assert.equal(parseTarget(undefined), null);
|
||||||
|
assert.equal(parseTarget('25M.5'), null);
|
||||||
|
assert.equal(parseTarget('1.5.5M'), null);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user