numeric-unit-parse-kit
v0.1.0
Published
Parse generic numeric values with units into structured numbers, units, diagnostics, and normalized strings.
Maintainers
Readme
numeric-unit-parse-kit
Parse numeric values with units such as 12px, 50 gold, -1.5turn, 100%, or 0 into structured results with readable diagnostics.
numeric-unit-parse-kit is a small clean-room toolkit for forms, config editors, import tools and design-token utilities that need to validate a single number plus an optional unit. It is deliberately narrower than a CSS parser, expression parser or unit converter.
Package quality
- TypeScript types are generated from the source.
- ESM-only package with no runtime dependencies.
- Marked as side-effect free for bundlers.
- Browser-friendly implementation with no Node-only APIs.
- CI runs
npm ci,typecheck,build, andtest. - Tested on Node.js 20 and 22 with GitHub Actions.
Publication status
This package is currently a GitHub preview and is queued for npm publication. The browser demo is available now, and the install command below is the command to use once the npm package is published.
Install after npm publication
npm install numeric-unit-parse-kitQuick Start
import {
createNumericUnitParser,
formatNumericUnit,
isNumericUnit,
parseNumericUnit
} from "numeric-unit-parse-kit";
const parsed = parseNumericUnit(" 50 gold ", {
allowedUnits: ["gold", "silver"],
requireUnit: true
});
if (parsed.ok) {
parsed.value.amount;
// 50
parsed.value.unit;
// "gold"
parsed.value.normalized;
// "50gold"
}
isNumericUnit("12px", { allowedUnits: ["px", "rem"] });
// true
formatNumericUnit({ amount: 12, unit: "gold" }, { separator: " " });
// "12 gold"
const cssLength = createNumericUnitParser({
allowedUnits: ["px", "rem", "%"],
requireUnit: true
});
cssLength.isValid("1.5rem");
// trueWhy this package
Small numeric-unit inputs show up in many places: design tokens, spacing controls, game configs, quota settings, billing quantities, virtual currencies, custom measurements and import columns.
Boolean validation is often not enough. This package returns stable issue codes and keeps the parsed value small:
const result = parseNumericUnit("12bananas", {
allowedUnits: ["px", "rem"]
});
result.issues;
// [
// {
// code: "unit-not-allowed",
// message: "Unit \"bananas\" is not in the allowed unit list.",
// input: "12bananas",
// normalizedInput: "12bananas",
// unit: "bananas"
// }
// ]API
parseNumericUnit(input, options?)
Returns a discriminated result:
type ParseNumericUnitResult =
| { ok: true; value: NumericUnit; issues: [] }
| { ok: false; value: null; issues: NumericUnitIssue[] };
type NumericUnit = {
amount: number;
unit: string;
raw: string;
normalized: string;
};Example:
const result = parseNumericUnit("-1.5turn", {
allowedUnits: ["deg", "rad", "turn"],
allowNegative: true
});isNumericUnit(input, options?)
Boolean shortcut for parseNumericUnit(input, options).ok.
isNumericUnit("100%", { allowPercent: true });
// trueformatNumericUnit(value, options?)
Formats { amount, unit } back to a string.
formatNumericUnit({ amount: 1.2345, unit: "px" }, { maximumFractionDigits: 2 });
// "1.23px"
formatNumericUnit({ amount: 12, unit: "gold" }, { separator: " " });
// "12 gold"By default, formatNumericUnit({ amount: 0, unit: "px" }) returns "0". Pass { unitlessZero: false } when the unit should be preserved.
createNumericUnitParser(defaultOptions?)
Creates a small parser object that reuses the same defaults across a form, importer or config validator. Per-call options override the defaults.
const cssLength = createNumericUnitParser({
allowedUnits: ["px", "rem"],
allowPercent: false,
requireUnit: true
});
cssLength.parse("12px");
cssLength.isValid("12rem");
cssLength.format({ amount: 12, unit: "px" });
cssLength.isValid("50%", {
allowPercent: true,
allowedUnits: ["px", "%"]
});
// trueOptions
Parse options
| Option | Default | Description |
| --- | --- | --- |
| allowedUnits | none | Optional list of accepted units. Empty unit values are still allowed unless requireUnit rejects them. |
| caseSensitiveUnits | true | Compare allowedUnits using exact casing by default. |
| requireUnit | false | Reject values without units. |
| allowUnitlessZero | true | Allow 0 when requireUnit is enabled. |
| allowNegative | true | Allow negative numeric amounts. |
| allowPercent | true | Allow % as a unit. |
| trim | true | Trim surrounding whitespace before parsing. |
Format options
| Option | Default | Description |
| --- | --- | --- |
| unitlessZero | true | Format zero as 0 even when a unit is present. |
| maximumFractionDigits | none | Round the amount with Intl.NumberFormat. |
| separator | "" | String placed between amount and unit. |
Diagnostics
Issue codes are stable and intended for UI messages, logs or localization:
emptyinvalid-typeinvalid-syntaxnon-finitenegative-not-allowedunit-requiredunit-not-allowedpercent-not-allowed
Limits
This package parses one numeric value and one unit. It does not:
- parse formulas such as
calc(100% - 1rem); - parse ranges such as
1-3px; - parse compound dimensions such as
10px 20px; - convert between units;
- validate CSS grammar;
- infer whether a unit makes sense for a domain.
Use it as a small validation layer before domain-specific checks.
License
MPL-2.0
