@nicholasdly/subscript
Evaluate arithmetic, unit conversions, and time zones from natural language — zero dependencies or network requests.
{
"ok": true,
"value": {
"value": 1.8034,
"unit": {
"id": "metre",
"symbol": "m"
}
},
"text": "1.8034 m"
}
Installation
Usage
Evaluate natural language queries anywhere in your project using the default configured evaluate function.
import { evaluate } from "@nicholasdly/subscript";
evaluate("20 c to f");
// { ok: true, text: "68 °F", ... }
evaluate("1 m in ft");
// { ok: true, text: "3.28084 ft", ... }
evaluate("(2 + 3) * 4 km in miles");
// { ok: true, text: "12.4274 mi", ... }Configuration
Use createSubscript to configure the clock, locale, and format of the parser.
import { createSubscript, isZonedTime } from "@nicholasdly/subscript";
const subscript = createSubscript({
now: () => ({ epochMilliseconds: Date.UTC(2026, 0, 15, 18, 0, 0) }),
});
const time = subscript.evaluate("3pm PST in Tokyo");
// time.text === "8:00 AM JST, Jan 16"
// isZonedTime(time.value) === trueSpans
spans returns highlight ranges for the original string. It does not evaluate.
createSubscript().spans("20 c to f");
// [
// { start: 0, end: 2, kind: "number" },
// { start: 3, end: 4, kind: "unit" },
// { start: 5, end: 7, kind: "converter" },
// { start: 8, end: 9, kind: "unit" },
// ]Results
The result of an evaluation is a Result object, representing either a successful answer or a typed failure. Nothing in the API throws for bad input — you check ok and then read value or reason .
type Result =
| {
ok: true;
value: Quantity | ZonedTime;
text: string;
alternates?: Alternate[];
}
| { ok: false; reason: Failure };