strict-money-parse 1.0.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/README.md +111 -167
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -5,219 +5,163 @@
5
5
  [![Bundle Size](https://img.shields.io/bundlephobia/minzip/strict-money-parse?style=flat-square)](https://bundlephobia.com/package/strict-money-parse)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue?style=flat-square&logo=typescript)](https://www.typescriptlang.org/)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
8
- [![Test Coverage](https://img.shields.io/badge/coverage-99.2%25-brightgreen?style=flat-square)](https://github.com/yourusername/strict-money-parse)
9
8
  [![Build Status](https://img.shields.io/github/actions/workflow/status/MoneyConverter/strict-money-parse/ci.yml?style=flat-square)](https://github.com/MoneyConverter/strict-money-parse/actions)
10
9
 
11
- **A production-ready TypeScript library for parsing monetary values from real-world strings with evidence-based currency detection.**
10
+ Strict TypeScript library for parsing monetary values from strings with evidence-based currency detection.
12
11
 
13
- _Originally developed for [MoneyConvert.net](https://moneyconvert.net/) — a currency conversion service._
12
+ Originally developed for [MoneyConvert.net](https://moneyconvert.net/).
14
13
 
15
- Zero runtime dependencies • Fully typed • Extensively tested against real e-commerce data from 40+ countries • Only **3.82 kB gzipped** (ESM) / **2.92 kB** (CJS)
14
+ ## Table of contents
16
15
 
17
- ## 📑 Table of Contents
16
+ - [Installation](#installation)
17
+ - [🚀 Quick start](#-quick-start)
18
+ - [API](#api)
19
+ - [Options](#options)
20
+ - [Notes](#notes)
21
+ - [License](#license)
18
22
 
19
- - [🌍 Battle-Tested with Real-World Data](#-battle-tested-with-real-world-data)
20
- - [✨ Features](#-features)
21
- - [📦 Installation](#-installation)
22
- - [🚀 Quick Start](#-quick-start)
23
- - [📖 API Reference](#-api-reference)
24
- - [💡 Usage Examples](#-usage-examples)
25
- - [European Number Formats](#european-number-formats)
26
- - [Asian Currencies](#asian-currencies)
27
- - [Handling Ambiguous Symbols](#handling-ambiguous-symbols)
28
- - [ISO 4217 Code Detection](#iso-4217-code-detection)
29
- - [False Positive Prevention](#false-positive-prevention)
30
- - [HTML Content Parsing](#html-content-parsing)
23
+ ## Installation
31
24
 
32
- - [🔍 Advanced API](#-advanced-api)
33
- - [🧮 Number Format Detection](#-number-format-detection)
34
- - [🗂️ Project Structure](#️-project-structure)
35
- - [🧪 Testing Methodology](#-testing-methodology)
36
- - [📊 Data Sources & Methodology](#-data-sources--methodology)
37
- - [�� Design Principles](#-design-principles)
38
- - [📈 Performance](#-performance)
39
- - [🛠️ Development](#️-development)
40
- - [📝 License](#-license)
41
- - [🤝 Contributing](#-contributing)
42
- - [🙏 Acknowledgments](#-acknowledgments)
43
- - [📞 Support](#-support)
44
- - [🗺️ Roadmap](#️-roadmap)
45
-
46
- ---
47
-
48
- ---
49
-
50
- ## 🌍 Battle-Tested with Real-World Data
25
+ ```bash
26
+ npm install strict-money-parse
27
+ # or
28
+ yarn add strict-money-parse
29
+ # or
30
+ pnpm add strict-money-parse
31
+ # or
32
+ bun add strict-money-parse
33
+ ```
51
34
 
52
- We've conducted **extensive testing** with actual HTML snippets and price formats from e-commerce sites across **40+ countries**, including:
35
+ Node.js >= 18 is required.
53
36
 
54
- - 🇺🇸 **Americas:** USA, Canada, Mexico, Brazil, Argentina, Chile, Colombia, Peru, Uruguay, Bolivia, Guatemala, Dominican Republic, Jamaica, Bahamas, Barbados
55
- - 🇪🇺 **Europe:** Germany, UK, France, Spain, Italy, Poland, Czech Republic, Switzerland, Sweden, Norway, Denmark, Hungary, Romania, Bulgaria, Greece, Albania
56
- - 🇦🇸 **Asia:** Japan, China, South Korea, India, Indonesia, Thailand, Vietnam, Kazakhstan, Uzbekistan, Armenia, Israel, Georgia, Azerbaijan, Pakistan
57
- - 🇿🇦 **Africa:** South Africa, Nigeria, Kenya, Ghana, Morocco, Algeria, Tunisia, Ethiopia
58
- - 🇦🇺 **Oceania:** Australia, New Zealand, Papua New Guinea, Fiji, Vanuatu, Maldives
37
+ ## 🚀 Quick Start
59
38
 
60
- **540+ test cases** covering edge cases, ambiguous symbols, regional formatting, and all 181 ISO 4217 currency codes.
39
+ ```ts
40
+ import { parsePriceString } from "strict-money-parse";
61
41
 
62
- ---
42
+ // Basic usage
43
+ parsePriceString("€1,234.56");
44
+ parsePriceString("1.234,56 €");
45
+ parsePriceString("USD 99.99");
46
+ parsePriceString("¥125,000");
47
+ ```
63
48
 
64
- ## ✨ Features
49
+ ## API
65
50
 
66
- - ✅ **Zero Dependencies** – No external runtime dependencies, minimal bundle size
67
- - ✅ **Evidence-Based Detection** – Provides proof of currency detection with confidence levels
68
- - ✅ **Global Format Support** – Handles comma/dot decimals, space separators, European formats (\`.-\`, \`—\`, \`:-\`)
69
- - ✅ **181 ISO 4217 Codes** – Complete support for all official currency codes
70
- - ✅ **75+ Currency Symbols** – Including Unicode symbols (€, ₴, ₸, ₪, ฿, ₫, Rp, KSh, Kč, zł, TL, etc.)
71
- - ✅ **Ambiguity Resolution** – Smart handling of \`$\`, \`£\`, \`¥\`, \`kr\`, \`Lei\`, \`Rs\`, \`р.\`, \`Fr\` symbols
72
- - ✅ **False Positive Prevention** – Filters out phone numbers, dates, years, percentages, ranges, dimensions
73
- - ✅ **Fully Typed** – Complete TypeScript support with strict types
74
- - ✅ **Production-Ready** – 99.2% test coverage, extensively validated against real-world data
51
+ ### `parsePriceString(input, options?)`
75
52
 
76
- ---
53
+ Parses a single price string and returns the best match.
77
54
 
78
- ## 📦 Installation
55
+ **Parameters:**
79
56
 
80
- ```bash
81
- npm install strict-money-parse
82
- ```
57
+ - `input` (`string`): The string to parse (e.g., "$10.50", "1 200 RUB").
58
+ - `options` (`ParseOptions?`): Optional configuration object. See [Options](#options) below.
83
59
 
84
- ```bash
85
- yarn add strict-money-parse
86
- ```
60
+ **Returns:** `ParseResult`
87
61
 
88
- ```bash
89
- pnpm add strict-money-parse
62
+ ```ts
63
+ type CurrencyStatus = "CONFIRMED" | "AMBIGUOUS" | "UNKNOWN";
90
64
 
91
- ```bash
92
- bun add strict-money-parse
65
+ type ParseResult = {
66
+ status: CurrencyStatus; // Confidence level of the currency detection
67
+ rawAmount: number | null; // The parsed numeric value (e.g., 10.5)
68
+ currency: string | null; // ISO 4217 code (e.g., "USD") or symbol if unknown
69
+ symbol: string | null; // The detected currency symbol (e.g., "$")
70
+ currencyHints: string[]; // List of potential currency codes if ambiguous
71
+ evidence: {
72
+ matchedText: string; // The substring that was parsed
73
+ normalizedText: string; // Text after normalization
74
+ amountToken?: string; // The numeric part as a string
75
+ isoCodeFound?: string; // Detected ISO code
76
+ symbolFound?: string; // Detected symbol
77
+ };
78
+ };
93
79
  ```
94
80
 
95
- ```groovy
81
+ ### `parsePriceCandidates(input, options?)`
96
82
 
97
- **Requirements:** Node.js ≥18.0.0
83
+ Finds all potential price candidates in a string. Useful when the input might contain multiple prices or noise.
98
84
 
99
- ---
85
+ **Parameters:**
100
86
 
101
- ## 🚀 Quick Start
87
+ - `input` (`string`): The text to search.
88
+ - `options` (`ParseCandidatesOptions?`): Configuration object. Extends `ParseOptions` with:
89
+ - `maxCandidates` (`number?`): Maximum number of candidates to return.
102
90
 
103
- ```typescript
104
- import { parsePriceString } from 'strict-money-parse';
91
+ **Returns:** `Candidate[]` (Array of `ParseResult` with additional scoring info)
105
92
 
106
- // Basic usage
107
- const result = parsePriceString('€1,234.56');
108
- console.log(result);
109
- // {
110
- // status: 'CONFIRMED',
111
- // rawAmount: 1234.56,
112
- // currency: 'EUR',
113
- // symbol: '€',
114
- // currencyHints: [],
115
- // evidence: { ... }
116
- // }
117
-
118
- // Works with various formats
119
- parsePriceString('$1,999.99'); // US format
120
- parsePriceString('1.234,56 €'); // European format
121
- parsePriceString('2 499 Kč'); // Czech format with space separator
122
- parsePriceString('¥125,000'); // Japanese yen
123
- parsePriceString('₴5,678.90'); // Ukrainian hryvnia
124
- parsePriceString('USD 99.99'); // ISO code
125
- parsePriceString('12.500,00 TL'); // Turkish lira
93
+ ```ts
94
+ type Candidate = ParseResult & {
95
+ score: number; // Relevance score
96
+ indexStart: number; // Start index in the original string
97
+ indexEnd: number; // End index in the original string
98
+ };
126
99
  ```
127
100
 
128
- ---
129
-
130
- ## 📖 API Reference
101
+ ### `buildCurrencyTables()`
131
102
 
132
- ### \`parsePriceString(input: string, options?: ParseOptions): ParseResult\`
103
+ Pre-builds currency data tables.
133
104
 
134
- Parses a monetary value from a string with automatic currency detection.
105
+ **Returns:** `CurrencyTables`
135
106
 
136
- #### Parameters
107
+ **Usage:**
108
+ If you are parsing thousands of strings, you can build the tables once and pass them to `parsePriceString` via options to improve performance.
137
109
 
138
- - **\`input\`** (string) – The string containing a price/monetary value
139
- - **\`options\`** (ParseOptions, optional):
140
- - \`domain?: string\` – Domain/URL hint for ambiguous currency resolution
141
- - \`ignorePercentages?: boolean\` – Whether to ignore percentages (default: \`false\`)
142
- - \`maxFractionDigits?: number\` – Maximum decimal places (default: \`3\`)
110
+ ```ts
111
+ import { buildCurrencyTables, parsePriceString } from "strict-money-parse";
143
112
 
144
- #### Returns: \`ParseResult\`
113
+ const tables = buildCurrencyTables(); // Build once
145
114
 
146
- ```typescript
147
- interface ParseResult {
148
- status: 'CONFIRMED' | 'AMBIGUOUS' | 'UNKNOWN';
149
- rawAmount: number | null; // Parsed numeric value
150
- currency: string | null; // ISO 4217 code or null
151
- symbol: string | null; // Original currency symbol
152
- currencyHints: string[]; // Possible currencies (when ambiguous)
153
- evidence: Evidence; // Detection metadata
154
- }
115
+ // Reuse in loop
116
+ data.forEach(str => {
117
+ parsePriceString(str, { tables });
118
+ });
155
119
  ```
156
120
 
157
- #### Status Values
121
+ ## Options
158
122
 
159
- - **\`CONFIRMED\`** Currency definitively identified with high confidence
160
- - **\`AMBIGUOUS\`** – Multiple currencies possible (e.g., \`$\` could be USD, CAD, AUD, etc.)
161
- - **\`UNKNOWN\`** – No currency detected or false positive filtered out
123
+ The `options` object allows you to fine-tune the parsing behavior.
162
124
 
163
- ---
125
+ ### `domain`
164
126
 
165
- ## 💡 Usage Examples
127
+ - **Type:** `"price" | "fx" | "crypto"`
128
+ - **Default:** `"price"`
129
+ - **Description:** Sets the default `maxFractionDigits` based on the expected domain.
130
+ - `price`: 2 decimal places (standard retail prices).
131
+ - `fx`: 4 decimal places (foreign exchange rates).
132
+ - `crypto`: 8 decimal places (cryptocurrencies).
166
133
 
167
- ### European Number Formats
134
+ ### `maxFractionDigits`
168
135
 
169
- ```typescript
170
- // German format (dot thousands, comma decimal)
171
- parsePriceString('1.234,56 €');
172
- // → { status: 'CONFIRMED', rawAmount: 1234.56, currency: 'EUR' }
136
+ - **Type:** `number`
137
+ - **Default:** Depends on `domain` (2, 4, or 8).
138
+ - **Description:** Explicitly limits the number of decimal places allowed. If the number in the string has more decimal places than this, it might be split or parsed differently. Overrides the `domain` default.
173
139
 
174
- // Swiss format (apostrophe thousands)
175
- parsePriceString("CHF 1'234.56");
176
- // → { status: 'CONFIRMED', rawAmount: 1234.56, currency: 'CHF' }
140
+ ### `maxSymbolDistance`
177
141
 
178
- // Czech "dash for zero cents" format
179
- parsePriceString('1 234,— Kč');
180
- // { status: 'CONFIRMED', rawAmount: 1234, currency: 'CZK' }
181
- ```
142
+ - **Type:** `number`
143
+ - **Default:** `6`
144
+ - **Description:** The maximum number of characters allowed between the currency symbol/code and the numeric value. Useful to avoid matching unrelated symbols far from the number.
182
145
 
183
- ### Handling Ambiguous Symbols
184
-
185
- ```typescript
186
- // Dollar sign without additional context
187
- const result = parsePriceString('$99.99');
188
- console.log(result);
189
- // {
190
- // status: 'AMBIGUOUS',
191
- // rawAmount: 99.99,
192
- // currency: 'USD', // Default assumption
193
- // currencyHints: ['USD', 'CAD', 'AUD', 'NZD', ...] // All 26 possibilities
194
- // }
195
-
196
- // Use explicit ISO codes when currency is known
197
- parsePriceString('CAD 99.99');
198
- // → { status: 'CONFIRMED', rawAmount: 99.99, currency: 'CAD' }
199
-
200
- parsePriceString('99.99 AUD');
201
- // → { status: 'CONFIRMED', rawAmount: 99.99, currency: 'AUD' }
202
-
203
- // Or use unambiguous prefixed symbols
204
- parsePriceString('CA$ 99.99');
205
- // → { status: 'CONFIRMED', rawAmount: 99.99, currency: 'CAD' }
206
- ```
146
+ ### `ignorePercentages`
207
147
 
208
- ### Asian Currencies
148
+ - **Type:** `boolean`
149
+ - **Default:** `true`
150
+ - **Description:** If `true`, ignores numeric values followed immediately by a `%` sign (e.g., "50% off").
209
151
 
210
- ```typescript
211
- // Japanese yen with kanji
212
- parsePriceString('¥1,234 円');
213
- // → { status: 'CONFIRMED', rawAmount: 1234, currency: 'JPY' }
152
+ ### `tables`
214
153
 
215
- // Indian rupee with lakh separator
216
- parsePriceString('₹12,34,567.00');
217
- // { status: 'CONFIRMED', rawAmount: 1234567, currency: 'INR' }
154
+ - **Type:** `CurrencyTables`
155
+ - **Default:** `undefined` (tables are built on the fly)
156
+ - **Description:** Pre-computed currency tables from `buildCurrencyTables()`. Pass this to avoid rebuilding tables for every call.
218
157
 
219
- // Indonesian rupiah
220
- parsePriceString('Rp 125.000');
221
- // { status: 'CONFIRMED', rawAmount: 125000, currency: 'IDR' }
222
- ```
158
+ ## Notes
159
+
160
+ - `domain` does not map website domains like `amazon.ca` to a currency. It only selects a precision profile (`price`/`fx`/`crypto`).
161
+ - ISO 4217 currency list (`src/data/iso4217.json`) last downloaded: 2026-01-02.
162
+ - Real-world HTML-based test notes: [`REAL_WORLD_HTML_TESTS.md`](REAL_WORLD_HTML_TESTS.md)
163
+ - Third-party notices: [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)
164
+
165
+ ## License
223
166
 
167
+ MIT. See [`LICENSE`](LICENSE).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strict-money-parse",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Strict TypeScript library for parsing monetary values from strings with evidence-based currency detection",
5
5
  "author": {
6
6
  "name": "Yurii Dejurin",