strict-money-parse 1.0.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yurii Derevych
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # strict-money-parse
2
+
3
+ [![npm version](https://img.shields.io/npm/v/strict-money-parse.svg?style=flat-square)](https://www.npmjs.com/package/strict-money-parse)
4
+ [![npm downloads](https://img.shields.io/npm/dm/strict-money-parse.svg?style=flat-square)](https://www.npmjs.com/package/strict-money-parse)
5
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/strict-money-parse?style=flat-square)](https://bundlephobia.com/package/strict-money-parse)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue?style=flat-square&logo=typescript)](https://www.typescriptlang.org/)
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
+ [![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
+
11
+ **A production-ready TypeScript library for parsing monetary values from real-world strings with evidence-based currency detection.**
12
+
13
+ _Originally developed for [MoneyConvert.net](https://moneyconvert.net/) โ€” a currency conversion service._
14
+
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)
16
+
17
+ ## ๐Ÿ“‘ Table of Contents
18
+
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)
31
+
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
51
+
52
+ We've conducted **extensive testing** with actual HTML snippets and price formats from e-commerce sites across **40+ countries**, including:
53
+
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
59
+
60
+ **540+ test cases** covering edge cases, ambiguous symbols, regional formatting, and all 181 ISO 4217 currency codes.
61
+
62
+ ---
63
+
64
+ ## โœจ Features
65
+
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
75
+
76
+ ---
77
+
78
+ ## ๐Ÿ“ฆ Installation
79
+
80
+ ```bash
81
+ npm install strict-money-parse
82
+ ```
83
+
84
+ ```bash
85
+ yarn add strict-money-parse
86
+ ```
87
+
88
+ ```bash
89
+ pnpm add strict-money-parse
90
+
91
+ ```bash
92
+ bun add strict-money-parse
93
+ ```
94
+
95
+ ```groovy
96
+
97
+ **Requirements:** Node.js โ‰ฅ18.0.0
98
+
99
+ ---
100
+
101
+ ## ๐Ÿš€ Quick Start
102
+
103
+ ```typescript
104
+ import { parsePriceString } from 'strict-money-parse';
105
+
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
126
+ ```
127
+
128
+ ---
129
+
130
+ ## ๐Ÿ“– API Reference
131
+
132
+ ### \`parsePriceString(input: string, options?: ParseOptions): ParseResult\`
133
+
134
+ Parses a monetary value from a string with automatic currency detection.
135
+
136
+ #### Parameters
137
+
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\`)
143
+
144
+ #### Returns: \`ParseResult\`
145
+
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
+ }
155
+ ```
156
+
157
+ #### Status Values
158
+
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
162
+
163
+ ---
164
+
165
+ ## ๐Ÿ’ก Usage Examples
166
+
167
+ ### European Number Formats
168
+
169
+ ```typescript
170
+ // German format (dot thousands, comma decimal)
171
+ parsePriceString('1.234,56 โ‚ฌ');
172
+ // โ†’ { status: 'CONFIRMED', rawAmount: 1234.56, currency: 'EUR' }
173
+
174
+ // Swiss format (apostrophe thousands)
175
+ parsePriceString("CHF 1'234.56");
176
+ // โ†’ { status: 'CONFIRMED', rawAmount: 1234.56, currency: 'CHF' }
177
+
178
+ // Czech "dash for zero cents" format
179
+ parsePriceString('1 234,โ€” Kฤ');
180
+ // โ†’ { status: 'CONFIRMED', rawAmount: 1234, currency: 'CZK' }
181
+ ```
182
+
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
+ ```
207
+
208
+ ### Asian Currencies
209
+
210
+ ```typescript
211
+ // Japanese yen with kanji
212
+ parsePriceString('ยฅ1,234 ๅ††');
213
+ // โ†’ { status: 'CONFIRMED', rawAmount: 1234, currency: 'JPY' }
214
+
215
+ // Indian rupee with lakh separator
216
+ parsePriceString('โ‚น12,34,567.00');
217
+ // โ†’ { status: 'CONFIRMED', rawAmount: 1234567, currency: 'INR' }
218
+
219
+ // Indonesian rupiah
220
+ parsePriceString('Rp 125.000');
221
+ // โ†’ { status: 'CONFIRMED', rawAmount: 125000, currency: 'IDR' }
222
+ ```
223
+
@@ -0,0 +1,91 @@
1
+ # Third-Party Notices
2
+
3
+ This project uses the following third-party data and resources:
4
+
5
+ ---
6
+
7
+ ## ISO 4217 Currency Codes
8
+
9
+ **Source:** International Organization for Standardization (ISO)
10
+ **License:** Public Domain
11
+ **URL:** https://www.iso.org/iso-4217-currency-codes.html
12
+
13
+ ISO 4217 currency codes are international standards published by ISO. The standard defines three-letter alphabetic codes and three-digit numeric codes for currencies.
14
+
15
+ **Usage in this project:**
16
+ - File: `src/data/iso4217.json`
17
+ - Contains: 181 active currency codes
18
+ - Purpose: Official currency code validation and detection
19
+
20
+ ---
21
+
22
+ ## Unicode CLDR (Common Locale Data Repository)
23
+
24
+ **Source:** Unicode Consortium
25
+ **License:** Unicode License
26
+ **URL:** https://cldr.unicode.org/
27
+
28
+ The Unicode CLDR provides key building blocks for software to support the world's languages, with the largest and most extensive standard repository of locale data available.
29
+
30
+ **License Text:** https://www.unicode.org/license.txt
31
+
32
+ **Usage in this project:**
33
+ - Currency symbol mappings
34
+ - Regional formatting conventions
35
+ - Alternative currency representations
36
+
37
+ ---
38
+
39
+ ## Real-World Test Data
40
+
41
+ **Source:** Manual collection from public e-commerce websites
42
+ **License:** Fair use for testing purposes
43
+
44
+ Test data was collected from publicly accessible price information on various e-commerce platforms across 40+ countries, including:
45
+ - Amazon (multiple regions)
46
+ - eBay
47
+ - AliExpress
48
+ - Mercado Libre
49
+ - Flipkart
50
+ - Tokopedia
51
+ - Regional retailers
52
+
53
+ **Usage in this project:**
54
+ - File: `test/integration/real-world-html.test.ts`
55
+ - Purpose: Validation of real-world price parsing accuracy
56
+ - Note: Only price format patterns are used, no proprietary data is included
57
+
58
+ ---
59
+
60
+ ## Development Dependencies
61
+
62
+ This project uses various open-source development tools under their respective licenses:
63
+ - TypeScript (Apache-2.0)
64
+ - Vitest (MIT)
65
+ - ESLint (MIT)
66
+ - Prettier (MIT)
67
+
68
+ For a complete list of development dependencies and their licenses, see `package.json` and run:
69
+ ```bash
70
+ npm list --all
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Acknowledgments
76
+
77
+ Special thanks to:
78
+ - The Unicode Consortium for maintaining CLDR data
79
+ - ISO for publishing currency standards
80
+ - The open-source community for development tools
81
+ - Contributors who provided real-world test cases
82
+
83
+ ---
84
+
85
+ ## Disclaimer
86
+
87
+ This project is provided "as is" without warranty of any kind. While we strive for accuracy, currency data and formatting conventions may change over time. Users are responsible for validating the accuracy of parsed results in their specific use cases.
88
+
89
+ ---
90
+
91
+ **Last Updated:** January 2, 2026
@@ -0,0 +1,3 @@
1
+ import type { Candidate, ParseCandidatesOptions } from "./types";
2
+ export declare function parsePriceCandidates(text: string, opts?: ParseCandidatesOptions): Candidate[];
3
+ //# sourceMappingURL=candidates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../src/candidates.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAuDjE,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,sBAAsB,GAC5B,SAAS,EAAE,CA6Db"}
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=["AED","AFN","ALL","AMD","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BHD","BIF","BMD","BND","BOB","BOV","BRL","BSD","BTN","BWP","BYN","BZD","CAD","CDF","CHE","CHF","CHW","CLF","CLP","CNY","COP","COU","CRC","CUP","CVE","CZK","DJF","DKK","DOP","DZD","EGP","ERN","ETB","EUR","FJD","FKP","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD","HKD","HNL","HTG","HUF","IDR","ILS","INR","IQD","IRR","ISK","JMD","JOD","JPY","KES","KGS","KHR","KMF","KPW","KRW","KWD","KYD","KZT","LAK","LBP","LKR","LRD","LSL","LYD","MAD","MDL","MGA","MKD","MMK","MNT","MOP","MRU","MUR","MVR","MWK","MXN","MXV","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SDG","SEK","SGD","SHP","SLE","SOS","SRD","SSP","STN","SVC","SYP","SZL","THB","TJS","TMT","TND","TOP","TRY","TTD","TWD","TZS","UAH","UGX","USD","USN","UYI","UYU","UYW","UZS","VED","VES","VND","VUV","WST","XAD","XAF","XAG","XAU","XBA","XBB","XBC","XBD","XCD","XCG","XDR","XOF","XPD","XPF","XPT","XSU","XTS","XUA","XXX","YER","ZAR","ZMW","ZWG"],B={"โ‚ฌ":"EUR","โ‚ด":"UAH","โ‚ธ":"KZT","โ‚ผ":"AZN","โ‚พ":"GEL","โ‚ช":"ILS","ึ":"AMD","เธฟ":"THB","โ‚ซ":"VND","โ‚ฑ":"PHP","โ‚ฒ":"PYG","โ‚ก":"CRC","โ‚ฎ":"MNT","โ‚ฆ":"NGN","โ‚ฉ":"KRW","โ‚บ":"TRY","โ‚น":"INR","โ‚ฝ":"RUB","เงณ":"BDT","แŸ›":"KHR","โ‚ญ":"LAK","โ‚ต":"GHS","ุฏ.ูƒ":"KWD",Rp:"IDR",RM:"MYR",KSh:"KES",Kฤ:"CZK",zล‚:"PLN",Ft:"HUF",ะปะฒ:"BGN","ะปะฒ.":"BGN",TL:"TRY",ALL:"ALL","ุฑ.ุณ.":"SAR","ุฑ.ุณ":"SAR",DH:"MAD",DA:"DZD",DT:"TND",KD:"KWD","GHโ‚ต":"GHS","so'm":"UZS","so m":"UZS",sum:"UZS",soสปm:"UZS",Q:"GTQ",RD$:"DOP","RD $":"DOP","S/":"PEN","S /":"PEN",$U:"UYU","$ U":"UYU",Bs:"BOB","Bs.":"BOB",K:"PGK",VT:"VUV",Rf:"MVR",FJD$:"FJD","FJD $":"FJD",BDS$:"BBD","BDS $":"BBD",US$:"USD","US $":"USD",CA$:"CAD","CA $":"CAD",AU$:"AUD","AU $":"AUD",A$:"AUD","A $":"AUD",NZ$:"NZD","NZ $":"NZD",S$:"SGD","S $":"SGD",HK$:"HKD","HK $":"HKD",NT$:"TWD","NT $":"TWD",EC$:"XCD","EC $":"XCD",R$:"BRL","R $":"BRL","Eยฃ":"EGP","E ยฃ":"EGP","ยฃE":"EGP","ยฃ E":"EGP","ยฃS":"SYP","ยฃ S":"SYP","Sยฃ":"SYP","S ยฃ":"SYP","JPยฅ":"JPY","JP ยฅ":"JPY","CNยฅ":"CNY","CN ยฅ":"CNY",ๅ††:"JPY"},N={$:["USD","CAD","AUD","NZD","SGD","HKD","MXN","ARS","CLP","COP","BBD","BMD","BND","BZD","FJD","GYD","KYD","LRD","NAD","SRD","TTD","XCD","BSD","JMD","SBD"],"ยฅ":["JPY","CNY"],"๏ฟฅ":["JPY","CNY"],"ยฃ":["GBP","FKP","GIP","SHP","LBP","EGP","SYP","GGP","IMP","JEP"],kr:["DKK","NOK","SEK","ISK"],Lei:["RON","MDL"],Leu:["RON","MDL"],C$:["CAD","CRC"],R:["ZAR","ZWL"],"ั€.":["BYN","RUB"],ั€:["BYN","RUB"],Fr:["CHF","XAF","XOF","XPF","DJF"],"โ‚จ":["INR","PKR","LKR","NPR","SCR"],"Rs.":["PKR","INR","LKR","NPR","SCR","MUR"],Rs:["PKR","INR","LKR","NPR","SCR","MUR"]},C=new Set(Object.keys(N));function R(n){const t={iso4217:new Set(g),uniqueSymbols:{...B},ambiguousHints:{...N},ambiguousSymbols:new Set(C)};return n?{iso4217:n.iso4217??t.iso4217,uniqueSymbols:{...t.uniqueSymbols,...n.uniqueSymbols??{}},ambiguousHints:{...t.ambiguousHints,...n.ambiguousHints??{}},ambiguousSymbols:new Set(Object.keys({...t.ambiguousHints,...n.ambiguousHints??{}}))}:t}function U(n){return n.trim().replace(/[\u00A0\u2009]/g," ").replace(/['']/g," ").replace(/\s+/g," ")}function y(n){const e=/\d[\d\s,.'"_]*/g.exec(n);return e?{token:e[0].trim(),index:e.index}:null}function b(n,t){const e=n.lastIndexOf("."),s=n.lastIndexOf(",");let i=n;if(e!==-1&&s!==-1){const r=e>s?".":",",c=r==="."?",":".";i=i.replace(new RegExp(`[${c}\\s'"_]`,"g"),"").replace(r,".")}else if(e!==-1||s!==-1){const r=e!==-1?e:s,c=n.slice(r+1).replace(/\D/g,"").length;c<=t&&c>0?i=i.replace(/[\s'"_,.](?=.*[,.])/g,"").replace(",","."):i=i.replace(/[\s'"_,.]/g,"")}else i=i.replace(/[\s'"_]/g,"");const o=parseFloat(i);return isNaN(o)?null:o}function K(n,t,e){return!!(t.replace(/\D/g,"").length>=10||/\b\d{4}[-/]\d{1,2}[-/]\d{1,2}\b/.test(n)||/\b\d{1,2}[-/]\d{1,2}[-/]\d{2,4}\b/.test(n)||/^\s*(19|20)\d{2}\s*$/.test(n)||e&&/%/.test(n)||/\d+\s*[-โ€“โ€”]\s*\d+/.test(n)||/\d+\s*[xร—]\s*\d+/i.test(n))}function M(n,t,e,s,i){const o=Math.max(0,t-i),r=Math.min(n.length,t+e+i),c=n.slice(o,t),a=n.slice(t+e,r),D=c+a,S=D.match(/\b([A-Z]{3})\b/);if(S&&s.iso4217.has(S[1]))return{status:"CONFIRMED",currency:S[1],symbol:null,hints:[]};const d=Object.keys(s.uniqueSymbols).sort((u,l)=>l.length-u.length);for(const u of d){const l=u.replace(/\s+/g,"");if(D.replace(/\s+/g,"").includes(l))return{status:"CONFIRMED",currency:s.uniqueSymbols[u],symbol:u,hints:[]}}const m=Array.from(s.ambiguousSymbols).sort((u,l)=>l.length-u.length);for(const u of m){const l=u.replace(/\s+/g,"");if(D.replace(/\s+/g,"").includes(l))return{status:"AMBIGUOUS",currency:null,symbol:u,hints:s.ambiguousHints[u]||[]}}return{status:"UNKNOWN",currency:null,symbol:null,hints:[]}}function P(n,t){const e={tables:t?.tables||R(),domain:t?.domain||"price",maxSymbolDistance:t?.maxSymbolDistance??6,ignorePercentages:t?.ignorePercentages??!0,maxFractionDigits:t?.maxFractionDigits},s=e.maxFractionDigits??(e.domain==="crypto"?8:e.domain==="fx"?4:2),i=U(n),o={matchedText:n,normalizedText:i},r=y(i);if(!r)return{status:"UNKNOWN",rawAmount:null,currency:null,symbol:null,currencyHints:[],evidence:o};if(o.amountToken=r.token,K(i,r.token,e.ignorePercentages))return{status:"UNKNOWN",rawAmount:null,currency:null,symbol:null,currencyHints:[],evidence:o};const c=b(r.token,s);if(c===null)return{status:"UNKNOWN",rawAmount:null,currency:null,symbol:null,currencyHints:[],evidence:o};const a=M(i,r.index,r.token.length,e.tables,e.maxSymbolDistance);return a.currency&&(o.isoCodeFound=a.currency),a.symbol&&(o.symbolFound=a.symbol),{status:a.status,rawAmount:c,currency:a.currency,symbol:a.symbol,currencyHints:a.hints,evidence:o}}const f=["price","cost","total","subtotal","amount","sum","pay","payment"];function T(n,t,e){let s=0;n.rawAmount!==null&&(s+=10),n.status==="CONFIRMED"?s+=50:n.status==="AMBIGUOUS"&&(s+=20),n.evidence.isoCodeFound&&(s+=30);const i=Math.max(0,e-50),o=Math.min(t.length,e+100),r=t.slice(i,o).toLowerCase();for(const c of f)if(r.includes(c)){s+=10;break}return s}function G(n,t){const e={tables:t?.tables||R(),domain:t?.domain||"price",maxSymbolDistance:t?.maxSymbolDistance??6,ignorePercentages:t?.ignorePercentages??!0,maxFractionDigits:t?.maxFractionDigits,maxCandidates:t?.maxCandidates??10},s=[],i=/\d[\d\s,.'"_]*/g;let o;for(;(o=i.exec(n))!==null;){const r=o.index,c=o.index+o[0].length,a=Math.max(0,r-e.maxSymbolDistance),D=Math.min(n.length,c+e.maxSymbolDistance),S=n.slice(a,D),d=P(S,{tables:e.tables,domain:e.domain,maxSymbolDistance:e.maxSymbolDistance,ignorePercentages:e.ignorePercentages,maxFractionDigits:e.maxFractionDigits}),m={...d,score:0,indexStart:r,indexEnd:c};m.score=T(m,n,r),d.rawAmount!==null&&s.push(m)}return s.sort((r,c)=>c.score!==r.score?c.score-r.score:r.indexStart-c.indexStart),s.slice(0,e.maxCandidates)}exports.buildCurrencyTables=R;exports.parsePriceCandidates=G;exports.parsePriceString=P;
@@ -0,0 +1,5 @@
1
+ export { parsePriceString } from "./parse";
2
+ export { parsePriceCandidates } from "./candidates";
3
+ export { buildCurrencyTables } from "./tables";
4
+ export type { CurrencyStatus, Evidence, ParseResult, Candidate, CurrencyTables, Domain, ParseOptions, ParseCandidatesOptions, } from "./types";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE/C,YAAY,EACV,cAAc,EACd,QAAQ,EACR,WAAW,EACX,SAAS,EACT,cAAc,EACd,MAAM,EACN,YAAY,EACZ,sBAAsB,GACvB,MAAM,SAAS,CAAC"}
package/dist/index.mjs ADDED
@@ -0,0 +1,538 @@
1
+ const A = [
2
+ "AED",
3
+ "AFN",
4
+ "ALL",
5
+ "AMD",
6
+ "AOA",
7
+ "ARS",
8
+ "AUD",
9
+ "AWG",
10
+ "AZN",
11
+ "BAM",
12
+ "BBD",
13
+ "BDT",
14
+ "BHD",
15
+ "BIF",
16
+ "BMD",
17
+ "BND",
18
+ "BOB",
19
+ "BOV",
20
+ "BRL",
21
+ "BSD",
22
+ "BTN",
23
+ "BWP",
24
+ "BYN",
25
+ "BZD",
26
+ "CAD",
27
+ "CDF",
28
+ "CHE",
29
+ "CHF",
30
+ "CHW",
31
+ "CLF",
32
+ "CLP",
33
+ "CNY",
34
+ "COP",
35
+ "COU",
36
+ "CRC",
37
+ "CUP",
38
+ "CVE",
39
+ "CZK",
40
+ "DJF",
41
+ "DKK",
42
+ "DOP",
43
+ "DZD",
44
+ "EGP",
45
+ "ERN",
46
+ "ETB",
47
+ "EUR",
48
+ "FJD",
49
+ "FKP",
50
+ "GBP",
51
+ "GEL",
52
+ "GHS",
53
+ "GIP",
54
+ "GMD",
55
+ "GNF",
56
+ "GTQ",
57
+ "GYD",
58
+ "HKD",
59
+ "HNL",
60
+ "HTG",
61
+ "HUF",
62
+ "IDR",
63
+ "ILS",
64
+ "INR",
65
+ "IQD",
66
+ "IRR",
67
+ "ISK",
68
+ "JMD",
69
+ "JOD",
70
+ "JPY",
71
+ "KES",
72
+ "KGS",
73
+ "KHR",
74
+ "KMF",
75
+ "KPW",
76
+ "KRW",
77
+ "KWD",
78
+ "KYD",
79
+ "KZT",
80
+ "LAK",
81
+ "LBP",
82
+ "LKR",
83
+ "LRD",
84
+ "LSL",
85
+ "LYD",
86
+ "MAD",
87
+ "MDL",
88
+ "MGA",
89
+ "MKD",
90
+ "MMK",
91
+ "MNT",
92
+ "MOP",
93
+ "MRU",
94
+ "MUR",
95
+ "MVR",
96
+ "MWK",
97
+ "MXN",
98
+ "MXV",
99
+ "MYR",
100
+ "MZN",
101
+ "NAD",
102
+ "NGN",
103
+ "NIO",
104
+ "NOK",
105
+ "NPR",
106
+ "NZD",
107
+ "OMR",
108
+ "PAB",
109
+ "PEN",
110
+ "PGK",
111
+ "PHP",
112
+ "PKR",
113
+ "PLN",
114
+ "PYG",
115
+ "QAR",
116
+ "RON",
117
+ "RSD",
118
+ "RUB",
119
+ "RWF",
120
+ "SAR",
121
+ "SBD",
122
+ "SCR",
123
+ "SDG",
124
+ "SEK",
125
+ "SGD",
126
+ "SHP",
127
+ "SLE",
128
+ "SOS",
129
+ "SRD",
130
+ "SSP",
131
+ "STN",
132
+ "SVC",
133
+ "SYP",
134
+ "SZL",
135
+ "THB",
136
+ "TJS",
137
+ "TMT",
138
+ "TND",
139
+ "TOP",
140
+ "TRY",
141
+ "TTD",
142
+ "TWD",
143
+ "TZS",
144
+ "UAH",
145
+ "UGX",
146
+ "USD",
147
+ "USN",
148
+ "UYI",
149
+ "UYU",
150
+ "UYW",
151
+ "UZS",
152
+ "VED",
153
+ "VES",
154
+ "VND",
155
+ "VUV",
156
+ "WST",
157
+ "XAD",
158
+ "XAF",
159
+ "XAG",
160
+ "XAU",
161
+ "XBA",
162
+ "XBB",
163
+ "XBC",
164
+ "XBD",
165
+ "XCD",
166
+ "XCG",
167
+ "XDR",
168
+ "XOF",
169
+ "XPD",
170
+ "XPF",
171
+ "XPT",
172
+ "XSU",
173
+ "XTS",
174
+ "XUA",
175
+ "XXX",
176
+ "YER",
177
+ "ZAR",
178
+ "ZMW",
179
+ "ZWG"
180
+ ], B = {
181
+ // Single-char (highly distinctive)
182
+ "โ‚ฌ": "EUR",
183
+ "โ‚ด": "UAH",
184
+ "โ‚ธ": "KZT",
185
+ "โ‚ผ": "AZN",
186
+ "โ‚พ": "GEL",
187
+ "โ‚ช": "ILS",
188
+ "ึ": "AMD",
189
+ "เธฟ": "THB",
190
+ "โ‚ซ": "VND",
191
+ "โ‚ฑ": "PHP",
192
+ "โ‚ฒ": "PYG",
193
+ "โ‚ก": "CRC",
194
+ "โ‚ฎ": "MNT",
195
+ "โ‚ฆ": "NGN",
196
+ "โ‚ฉ": "KRW",
197
+ "โ‚บ": "TRY",
198
+ "โ‚น": "INR",
199
+ "โ‚ฝ": "RUB",
200
+ // Extra common unique symbols (optional but practical)
201
+ "เงณ": "BDT",
202
+ // Bangladeshi taka
203
+ "แŸ›": "KHR",
204
+ // Cambodian riel
205
+ "โ‚ญ": "LAK",
206
+ // Lao kip
207
+ "โ‚ต": "GHS",
208
+ // Ghanaian cedi
209
+ // Arabic script
210
+ "ุฏ.ูƒ": "KWD",
211
+ // Kuwaiti dinar
212
+ // Letter-based (distinct in practice)
213
+ Rp: "IDR",
214
+ RM: "MYR",
215
+ KSh: "KES",
216
+ Kฤ: "CZK",
217
+ zล‚: "PLN",
218
+ Ft: "HUF",
219
+ ะปะฒ: "BGN",
220
+ "ะปะฒ.": "BGN",
221
+ TL: "TRY",
222
+ ALL: "ALL",
223
+ "ุฑ.ุณ.": "SAR",
224
+ "ุฑ.ุณ": "SAR",
225
+ DH: "MAD",
226
+ DA: "DZD",
227
+ DT: "TND",
228
+ KD: "KWD",
229
+ "GHโ‚ต": "GHS",
230
+ "so'm": "UZS",
231
+ "so m": "UZS",
232
+ // Normalized version (apostrophe becomes space)
233
+ sum: "UZS",
234
+ soสปm: "UZS",
235
+ // Alternative apostrophe
236
+ Q: "GTQ",
237
+ RD$: "DOP",
238
+ "RD $": "DOP",
239
+ "S/": "PEN",
240
+ "S /": "PEN",
241
+ $U: "UYU",
242
+ "$ U": "UYU",
243
+ Bs: "BOB",
244
+ "Bs.": "BOB",
245
+ K: "PGK",
246
+ VT: "VUV",
247
+ Rf: "MVR",
248
+ FJD$: "FJD",
249
+ "FJD $": "FJD",
250
+ BDS$: "BBD",
251
+ "BDS $": "BBD",
252
+ // Disambiguated dollar forms (treat as unique)
253
+ US$: "USD",
254
+ "US $": "USD",
255
+ CA$: "CAD",
256
+ "CA $": "CAD",
257
+ AU$: "AUD",
258
+ "AU $": "AUD",
259
+ A$: "AUD",
260
+ "A $": "AUD",
261
+ NZ$: "NZD",
262
+ "NZ $": "NZD",
263
+ S$: "SGD",
264
+ "S $": "SGD",
265
+ HK$: "HKD",
266
+ "HK $": "HKD",
267
+ NT$: "TWD",
268
+ "NT $": "TWD",
269
+ EC$: "XCD",
270
+ "EC $": "XCD",
271
+ R$: "BRL",
272
+ "R $": "BRL",
273
+ // Disambiguated pound forms (treat as unique)
274
+ "Eยฃ": "EGP",
275
+ "E ยฃ": "EGP",
276
+ "ยฃE": "EGP",
277
+ "ยฃ E": "EGP",
278
+ "ยฃS": "SYP",
279
+ "ยฃ S": "SYP",
280
+ "Sยฃ": "SYP",
281
+ "S ยฃ": "SYP",
282
+ // Disambiguated yen/yuan forms (treat as unique)
283
+ "JPยฅ": "JPY",
284
+ "JP ยฅ": "JPY",
285
+ "CNยฅ": "CNY",
286
+ "CN ยฅ": "CNY",
287
+ // CJK characters
288
+ ๅ††: "JPY"
289
+ // Japanese yen
290
+ }, N = {
291
+ // Bare "$" is extremely ambiguous; keep a practical set of common "dollar-sign" currencies.
292
+ $: [
293
+ "USD",
294
+ "CAD",
295
+ "AUD",
296
+ "NZD",
297
+ "SGD",
298
+ "HKD",
299
+ "MXN",
300
+ "ARS",
301
+ "CLP",
302
+ "COP",
303
+ "BBD",
304
+ "BMD",
305
+ "BND",
306
+ "BZD",
307
+ "FJD",
308
+ "GYD",
309
+ "KYD",
310
+ "LRD",
311
+ "NAD",
312
+ "SRD",
313
+ "TTD",
314
+ "XCD",
315
+ "BSD",
316
+ "JMD",
317
+ "SBD"
318
+ ],
319
+ // Yen/Yuan
320
+ "ยฅ": ["JPY", "CNY"],
321
+ "๏ฟฅ": ["JPY", "CNY"],
322
+ // Pound sign used across multiple "pound" currencies
323
+ "ยฃ": ["GBP", "FKP", "GIP", "SHP", "LBP", "EGP", "SYP", "GGP", "IMP", "JEP"],
324
+ // Krona/Krone
325
+ kr: ["DKK", "NOK", "SEK", "ISK"],
326
+ // Lei used by Romania and Moldova
327
+ Lei: ["RON", "MDL"],
328
+ Leu: ["RON", "MDL"],
329
+ // "C$" sometimes appears for Canada and Costa Rica in the wild
330
+ C$: ["CAD", "CRC"],
331
+ // "R" is commonly Rand (but R$ already mapped to BRL as unique)
332
+ R: ["ZAR", "ZWL"],
333
+ // Cyrillic "ั€." or "ั€" for rubles (Belarus/Russia)
334
+ "ั€.": ["BYN", "RUB"],
335
+ ั€: ["BYN", "RUB"],
336
+ // Franc/Rupee family โ€” only if you decide to support them (they are noisy, but real).
337
+ // Note: These can cause false positives, consider enabling with a strictness flag
338
+ Fr: ["CHF", "XAF", "XOF", "XPF", "DJF"],
339
+ "โ‚จ": ["INR", "PKR", "LKR", "NPR", "SCR"],
340
+ "Rs.": ["PKR", "INR", "LKR", "NPR", "SCR", "MUR"],
341
+ Rs: ["PKR", "INR", "LKR", "NPR", "SCR", "MUR"]
342
+ }, U = new Set(Object.keys(N));
343
+ function d(n) {
344
+ const t = {
345
+ iso4217: new Set(A),
346
+ uniqueSymbols: { ...B },
347
+ ambiguousHints: { ...N },
348
+ ambiguousSymbols: new Set(U)
349
+ };
350
+ return n ? {
351
+ iso4217: n.iso4217 ?? t.iso4217,
352
+ uniqueSymbols: { ...t.uniqueSymbols, ...n.uniqueSymbols ?? {} },
353
+ ambiguousHints: { ...t.ambiguousHints, ...n.ambiguousHints ?? {} },
354
+ ambiguousSymbols: new Set(
355
+ Object.keys({
356
+ ...t.ambiguousHints,
357
+ ...n.ambiguousHints ?? {}
358
+ })
359
+ )
360
+ } : t;
361
+ }
362
+ function g(n) {
363
+ return n.trim().replace(/[\u00A0\u2009]/g, " ").replace(/['']/g, " ").replace(/\s+/g, " ");
364
+ }
365
+ function C(n) {
366
+ const e = /\d[\d\s,.'"_]*/g.exec(n);
367
+ return e ? {
368
+ token: e[0].trim(),
369
+ index: e.index
370
+ } : null;
371
+ }
372
+ function y(n, t) {
373
+ const e = n.lastIndexOf("."), s = n.lastIndexOf(",");
374
+ let i = n;
375
+ if (e !== -1 && s !== -1) {
376
+ const r = e > s ? "." : ",", c = r === "." ? "," : ".";
377
+ i = i.replace(new RegExp(`[${c}\\s'"_]`, "g"), "").replace(r, ".");
378
+ } else if (e !== -1 || s !== -1) {
379
+ const r = e !== -1 ? e : s, c = n.slice(r + 1).replace(/\D/g, "").length;
380
+ c <= t && c > 0 ? i = i.replace(/[\s'"_,.](?=.*[,.])/g, "").replace(",", ".") : i = i.replace(/[\s'"_,.]/g, "");
381
+ } else
382
+ i = i.replace(/[\s'"_]/g, "");
383
+ const o = parseFloat(i);
384
+ return isNaN(o) ? null : o;
385
+ }
386
+ function b(n, t, e) {
387
+ return !!(t.replace(/\D/g, "").length >= 10 || /\b\d{4}[-/]\d{1,2}[-/]\d{1,2}\b/.test(n) || /\b\d{1,2}[-/]\d{1,2}[-/]\d{2,4}\b/.test(n) || /^\s*(19|20)\d{2}\s*$/.test(n) || e && /%/.test(n) || /\d+\s*[-โ€“โ€”]\s*\d+/.test(n) || /\d+\s*[xร—]\s*\d+/i.test(n));
388
+ }
389
+ function K(n, t, e, s, i) {
390
+ const o = Math.max(0, t - i), r = Math.min(n.length, t + e + i), c = n.slice(o, t), a = n.slice(t + e, r), D = c + a, S = D.match(/\b([A-Z]{3})\b/);
391
+ if (S && s.iso4217.has(S[1]))
392
+ return {
393
+ status: "CONFIRMED",
394
+ currency: S[1],
395
+ symbol: null,
396
+ hints: []
397
+ };
398
+ const R = Object.keys(s.uniqueSymbols).sort(
399
+ (u, l) => l.length - u.length
400
+ );
401
+ for (const u of R) {
402
+ const l = u.replace(/\s+/g, "");
403
+ if (D.replace(/\s+/g, "").includes(l))
404
+ return {
405
+ status: "CONFIRMED",
406
+ currency: s.uniqueSymbols[u],
407
+ symbol: u,
408
+ hints: []
409
+ };
410
+ }
411
+ const m = Array.from(s.ambiguousSymbols).sort(
412
+ (u, l) => l.length - u.length
413
+ );
414
+ for (const u of m) {
415
+ const l = u.replace(/\s+/g, "");
416
+ if (D.replace(/\s+/g, "").includes(l))
417
+ return {
418
+ status: "AMBIGUOUS",
419
+ currency: null,
420
+ symbol: u,
421
+ hints: s.ambiguousHints[u] || []
422
+ };
423
+ }
424
+ return {
425
+ status: "UNKNOWN",
426
+ currency: null,
427
+ symbol: null,
428
+ hints: []
429
+ };
430
+ }
431
+ function M(n, t) {
432
+ const e = {
433
+ tables: t?.tables || d(),
434
+ domain: t?.domain || "price",
435
+ maxSymbolDistance: t?.maxSymbolDistance ?? 6,
436
+ ignorePercentages: t?.ignorePercentages ?? !0,
437
+ maxFractionDigits: t?.maxFractionDigits
438
+ }, s = e.maxFractionDigits ?? (e.domain === "crypto" ? 8 : e.domain === "fx" ? 4 : 2), i = g(n), o = {
439
+ matchedText: n,
440
+ normalizedText: i
441
+ }, r = C(i);
442
+ if (!r)
443
+ return {
444
+ status: "UNKNOWN",
445
+ rawAmount: null,
446
+ currency: null,
447
+ symbol: null,
448
+ currencyHints: [],
449
+ evidence: o
450
+ };
451
+ if (o.amountToken = r.token, b(i, r.token, e.ignorePercentages))
452
+ return {
453
+ status: "UNKNOWN",
454
+ rawAmount: null,
455
+ currency: null,
456
+ symbol: null,
457
+ currencyHints: [],
458
+ evidence: o
459
+ };
460
+ const c = y(r.token, s);
461
+ if (c === null)
462
+ return {
463
+ status: "UNKNOWN",
464
+ rawAmount: null,
465
+ currency: null,
466
+ symbol: null,
467
+ currencyHints: [],
468
+ evidence: o
469
+ };
470
+ const a = K(
471
+ i,
472
+ r.index,
473
+ r.token.length,
474
+ e.tables,
475
+ e.maxSymbolDistance
476
+ );
477
+ return a.currency && (o.isoCodeFound = a.currency), a.symbol && (o.symbolFound = a.symbol), {
478
+ status: a.status,
479
+ rawAmount: c,
480
+ currency: a.currency,
481
+ symbol: a.symbol,
482
+ currencyHints: a.hints,
483
+ evidence: o
484
+ };
485
+ }
486
+ const f = [
487
+ "price",
488
+ "cost",
489
+ "total",
490
+ "subtotal",
491
+ "amount",
492
+ "sum",
493
+ "pay",
494
+ "payment"
495
+ ];
496
+ function G(n, t, e) {
497
+ let s = 0;
498
+ n.rawAmount !== null && (s += 10), n.status === "CONFIRMED" ? s += 50 : n.status === "AMBIGUOUS" && (s += 20), n.evidence.isoCodeFound && (s += 30);
499
+ const i = Math.max(0, e - 50), o = Math.min(t.length, e + 100), r = t.slice(i, o).toLowerCase();
500
+ for (const c of f)
501
+ if (r.includes(c)) {
502
+ s += 10;
503
+ break;
504
+ }
505
+ return s;
506
+ }
507
+ function T(n, t) {
508
+ const e = {
509
+ tables: t?.tables || d(),
510
+ domain: t?.domain || "price",
511
+ maxSymbolDistance: t?.maxSymbolDistance ?? 6,
512
+ ignorePercentages: t?.ignorePercentages ?? !0,
513
+ maxFractionDigits: t?.maxFractionDigits,
514
+ maxCandidates: t?.maxCandidates ?? 10
515
+ }, s = [], i = /\d[\d\s,.'"_]*/g;
516
+ let o;
517
+ for (; (o = i.exec(n)) !== null; ) {
518
+ const r = o.index, c = o.index + o[0].length, a = Math.max(0, r - e.maxSymbolDistance), D = Math.min(n.length, c + e.maxSymbolDistance), S = n.slice(a, D), R = M(S, {
519
+ tables: e.tables,
520
+ domain: e.domain,
521
+ maxSymbolDistance: e.maxSymbolDistance,
522
+ ignorePercentages: e.ignorePercentages,
523
+ maxFractionDigits: e.maxFractionDigits
524
+ }), m = {
525
+ ...R,
526
+ score: 0,
527
+ indexStart: r,
528
+ indexEnd: c
529
+ };
530
+ m.score = G(m, n, r), R.rawAmount !== null && s.push(m);
531
+ }
532
+ return s.sort((r, c) => c.score !== r.score ? c.score - r.score : r.indexStart - c.indexStart), s.slice(0, e.maxCandidates);
533
+ }
534
+ export {
535
+ d as buildCurrencyTables,
536
+ T as parsePriceCandidates,
537
+ M as parsePriceString
538
+ };
@@ -0,0 +1,3 @@
1
+ import type { ParseResult, ParseOptions } from "./types";
2
+ export declare function parsePriceString(input: string, opts?: ParseOptions): ParseResult;
3
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EAIb,MAAM,SAAS,CAAC;AA+KjB,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,YAAY,GAClB,WAAW,CA0Fb"}
@@ -0,0 +1,4 @@
1
+ export declare const UNIQUE_SYMBOLS: Record<string, string>;
2
+ export declare const AMBIGUOUS_HINTS: Record<string, string[]>;
3
+ export declare const AMBIGUOUS_SYMBOLS: Set<string>;
4
+ //# sourceMappingURL=currency-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currency-data.d.ts","sourceRoot":"","sources":["../../src/tables/currency-data.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6GjD,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CA6DpD,CAAC;AAGF,eAAO,MAAM,iBAAiB,aAAwC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CurrencyTables } from "./types";
2
+ export declare function buildCurrencyTables(custom?: Partial<CurrencyTables>): CurrencyTables;
3
+ //# sourceMappingURL=tables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../src/tables.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAQ9C,wBAAgB,mBAAmB,CACjC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAC/B,cAAc,CAsBhB"}
@@ -0,0 +1,39 @@
1
+ export type CurrencyStatus = "CONFIRMED" | "AMBIGUOUS" | "UNKNOWN";
2
+ export type Evidence = {
3
+ matchedText: string;
4
+ normalizedText: string;
5
+ amountToken?: string;
6
+ isoCodeFound?: string;
7
+ symbolFound?: string;
8
+ };
9
+ export type ParseResult = {
10
+ status: CurrencyStatus;
11
+ rawAmount: number | null;
12
+ currency: string | null;
13
+ symbol: string | null;
14
+ currencyHints: string[];
15
+ evidence: Evidence;
16
+ };
17
+ export type Candidate = ParseResult & {
18
+ score: number;
19
+ indexStart: number;
20
+ indexEnd: number;
21
+ };
22
+ export type CurrencyTables = {
23
+ iso4217: Set<string>;
24
+ uniqueSymbols: Record<string, string>;
25
+ ambiguousHints: Record<string, string[]>;
26
+ ambiguousSymbols: Set<string>;
27
+ };
28
+ export type Domain = "price" | "fx" | "crypto";
29
+ export type ParseOptions = {
30
+ tables?: CurrencyTables;
31
+ domain?: Domain;
32
+ maxFractionDigits?: number;
33
+ maxSymbolDistance?: number;
34
+ ignorePercentages?: boolean;
35
+ };
36
+ export type ParseCandidatesOptions = ParseOptions & {
37
+ maxCandidates?: number;
38
+ };
39
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,CAAC;AAEnE,MAAM,MAAM,QAAQ,GAAG;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACzC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,QAAQ,CAAC;AAE/C,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,YAAY,GAAG;IAClD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "strict-money-parse",
3
+ "version": "1.0.0",
4
+ "description": "Strict TypeScript library for parsing monetary values from strings with evidence-based currency detection",
5
+ "author": {
6
+ "name": "Yurii Dejurin",
7
+ "url": "https://github.com/dejurin"
8
+ },
9
+ "license": "MIT",
10
+ "homepage": "https://moneyconvert.net/",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/MoneyConverter/strict-money-parse.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/MoneyConverter/strict-money-parse/issues"
17
+ },
18
+ "keywords": [
19
+ "money",
20
+ "currency",
21
+ "parser",
22
+ "price",
23
+ "iso4217",
24
+ "typescript",
25
+ "money-parser",
26
+ "currency-detection",
27
+ "price-parser",
28
+ "forex",
29
+ "exchange-rate",
30
+ "financial",
31
+ "payment",
32
+ "e-commerce"
33
+ ],
34
+ "type": "module",
35
+ "main": "./dist/index.cjs",
36
+ "module": "./dist/index.mjs",
37
+ "types": "./dist/index.d.ts",
38
+ "exports": {
39
+ ".": {
40
+ "types": "./dist/index.d.ts",
41
+ "import": "./dist/index.mjs",
42
+ "require": "./dist/index.cjs"
43
+ }
44
+ },
45
+ "files": [
46
+ "dist",
47
+ "README.md",
48
+ "LICENSE",
49
+ "THIRD_PARTY_NOTICES.md"
50
+ ],
51
+ "engines": {
52
+ "node": ">=18.0.0"
53
+ },
54
+ "scripts": {
55
+ "build": "vite build && tsc -p tsconfig.types.json",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest",
58
+ "test:coverage": "vitest run --coverage",
59
+ "lint": "eslint src scripts test --max-warnings=0",
60
+ "format": "prettier --write \"src/**/*.{ts,js}\" \"scripts/**/*.{ts,js}\" \"test/**/*.{ts,js}\"",
61
+ "update-iso4217": "tsx scripts/update-iso4217.ts",
62
+ "check-licenses": "tsx scripts/check-licenses.ts",
63
+ "prepublishOnly": "npm run build && npm run check-licenses && npm test"
64
+ },
65
+ "devDependencies": {
66
+ "@types/node": "^25.0.3",
67
+ "@typescript-eslint/eslint-plugin": "^8.51.0",
68
+ "@typescript-eslint/parser": "^8.51.0",
69
+ "@vitest/coverage-v8": "^4.0.16",
70
+ "eslint": "^9.39.2",
71
+ "prettier": "^3.7.4",
72
+ "tsx": "^4.21.0",
73
+ "typescript": "^5.9.3",
74
+ "vite": "^7.3.0",
75
+ "vitest": "^4.0.16"
76
+ }
77
+ }