npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

numis

v1.1.2

Published

Natural-language Monetary Parser

Readme

numis

npm version

Natural-language parser for monetary values. Extract money from text like a human would read it.


Quick Start

npm install numis
import { parseMoney } from "numis";

parseMoney("$12.50");
// => { original: "$12.50", amount: 12.5, currency: "USD" }

Works in:

  • Node.js >= 18 (tested on 22.x)
  • Modern browsers (ESM and CJS)

Requirements

  • Node.js >= 18 (tested on 22.x)
  • npm >= 9

Features

Single Values

Extract one monetary value from text:

parseMoney("The total is $49.99");
// => { original: "The total is $49.99", amount: 49.99, currency: "USD" }

Multiple Values

Extract all monetary values from text:

import { parseAll } from "numis";

parseAll("Price is $100-$200 or $500");
// => [
//     { type: 'range', min: 100, max: 200, currency: 'USD', isRange: true },
//     { type: 'single', amount: 500, currency: 'USD', isRange: false }
//   ]

Supported Formats

Symbols

$100, €50, £20.50, ¥1000, ₹500

ISO Codes

USD 100, 50 EUR, GBP 20.50

Magnitude Suffixes

10k, $5m, 2.5 billion, 500k EUR

Worded Numbers

one hundred dollars, fifty euros, half a million

Fractional Magnitudes

quarter million dollars, half a billion euros, two thirds of a million

Slang Terms

buck, quid, fiver (5), tenner (10), grand (1000)

Minor Units Only

75 cents, 50 pence, a quarter

Compound Expressions

a dollar and 23 cents, five euros and fifty cents

Regional Formats

€1.234,56 (European), 1'234.56 CHF (Swiss), R$150 (Brazilian)

Negative Values

-$100, ($50), -€25.99

Ranges

$500 - $1000, €50 to €100, between $100 and $200, 10k to 20k

Comparison Bounds

< 30k (max: 30000), > 2 Million USD (min: 2000000)


API Reference

parseMoney(text, options?)

Extracts one monetary value from text.

Parameters: | Param | Type | Description | |-------|------|-------------| | text | string | The text to parse | | options.defaultCurrency | string | ISO-4217 code when none detected (e.g., "USD") |

Returns:

{
  original: string;           // Original input text
  amount?: number;            // Parsed amount
  currency?: string;          // ISO-4217 code (e.g., "USD", "EUR")
  currencyWasDefault?: boolean; // true if currency came from defaultCurrency option
  isRange?: boolean;          // true if value is a range
  min?: number;               // Minimum (for ranges)
  max?: number;               // Maximum (for ranges)
  isNegative?: boolean;        // true if amount is negative
}

Examples:

// Basic
parseMoney("$50");
// => { original: "$50", amount: 50, currency: "USD" }

// Range
parseMoney("$500 - $1000");
// => { original: "$500 - $1000", isRange: true, min: 500, max: 1000, currency: "USD" }

// Default currency
parseMoney("I have 100", { defaultCurrency: "EUR" });
// => { original: "I have 100", amount: 100, currency: "EUR", currencyWasDefault: true }

// Negative
parseMoney("-$50");
// => { original: "-$50", amount: -50, currency: "USD", isNegative: true }

parseAll(text)

Extracts all monetary values from text.

Parameters: | Param | Type | Description | |-------|------|-------------| | text | string | The text to search |

Returns: MonetaryExpression[]

interface MonetaryExpression {
  type: "single" | "range";
  raw: string;                // Matched text
  startIndex: number;       // Position in input
  endIndex: number;
  amount?: number;           // For single values
  min?: number;              // For ranges
  max?: number;              // For ranges
  currency?: string;         // ISO-4217 code
  isRange?: boolean;
}

Examples:

// Multiple values
parseAll("Base: $100, shipping: $10-$20, tax: $8");
// => [
//     { type: 'single', raw: '$100', amount: 100, currency: 'USD' },
//     { type: 'range', raw: '$10-$20', min: 10, max: 20, currency: 'USD' },
//     { type: 'single', raw: '$8', amount: 8, currency: 'USD' }
//   ]

// Mixed currencies
parseAll("$100 USD or €50 EUR");
// => [
//     { type: 'single', amount: 100, currency: 'USD' },
//     { type: 'single', amount: 50, currency: 'EUR' }
//   ]

Options

defaultCurrency

Use when your text has amounts but no currency indicator:

// No currency detected
parseMoney("I have 100");
// => { original: "I have 100", amount: 100, currency: undefined }

// With default
parseMoney("I have 100", { defaultCurrency: "USD" });
// => { original: "I have 100", amount: 100, currency: "USD", currencyWasDefault: true }

// Detected currency beats default
parseMoney("$50", { defaultCurrency: "EUR" });
// => { original: "$50", amount: 50, currency: "USD" }

Errors

MoneyParseError

Thrown when you pass an invalid defaultCurrency:

import { MoneyParseError } from "numis";

try {
  parseMoney("test", { defaultCurrency: "INVALID" });
} catch (err) {
  if (err instanceof MoneyParseError) {
    console.log(err.message);
    // => "Invalid defaultCurrency: "INVALID" is not a valid ISO-4217 currency code"
  }
}

ValueOverflowError

Thrown when a number exceeds JavaScript's safe integer limit (~9 quadrillion):

import { ValueOverflowError } from "numis";

try {
  parseMoney("$999999999999999999");
} catch (err) {
  if (err instanceof ValueOverflowError) {
    console.log("Number too large!");
  }
}

Common Gotchas

No Currency in Text

Plain numbers without currency symbols/codes/names return currency: undefined:

parseMoney("I have 100");
// => { original: "I have 100", amount: 100, currency: undefined }

Use defaultCurrency option to handle this.

Input Length Limit

For performance and security, parseMoney() and parseAll() reject inputs longer than 5000 characters:

parseMoney("a".repeat(5001));
// throws MoneyParseError: Input length (5001) exceeds maximum allowed (5000).

This prevents ReDoS (Regular Expression Denial of Service) attacks on pathological inputs.

Ambiguous Formats

"1.500" could be 1.5 (US) or 1,500 (European):

parseMoney("€1.500");  // European symbol → 1,500
parseMoney("$1.500");  // US symbol → 1.5

Use clear formats: $1,500.00 or €1.500,00.


Demo

Try it live: https://numis.ritvij.dev

The demo site is a Vite + React SPA optimized for search engine and AI crawler visibility:

  • Structured data — JSON-LD schema for SoftwareApplication and WebSite (Google Rich Results compatible)
  • Open Graph / Twitter Cards — Social sharing previews with title, description, and OG image
  • <noscript> fallback — Full documentation content embedded as static HTML for crawlers without JavaScript
  • robots.txt — Explicit Allow directives for AI crawlers (GPTBot, ClaudeBot, PerplexityBot)
  • llms.txt — Attribution file for LLM ingestion
  • Preload hintsdns-prefetch and modulepreload for faster loading
  • Build-time injectionscripts/inject-noscript.cjs keeps the <noscript> block in sync with the React documentation component automatically

License

MIT