Skip to content

feat(currencies): add ISO 4217 currency support (opt-in) - #166

Merged
dmythro merged 1 commit into
mainfrom
feat/iso-4217-currencies
Jun 14, 2026
Merged

feat(currencies): add ISO 4217 currency support (opt-in)#166
dmythro merged 1 commit into
mainfrom
feat/iso-4217-currencies

Conversation

@dmythro

@dmythro dmythro commented Jun 14, 2026

Copy link
Copy Markdown
Member

Summary

Adds full ISO 4217 currency support as an opt-in countries-list/currencies subpath, so the default bundle is unaffected.

Each entry is { name, native, symbol, symbolNative, numeric, decimals } (+ optional withdrawn):

import { currencies, getCurrency, getCurrencyByNumeric } from 'countries-list/currencies'

currencies.UAH              // { name: 'Ukrainian Hryvnia', native: 'українська гривня', symbol: '₴', symbolNative: '₴', numeric: '980', decimals: 2 }
getCurrency('JPY')          // ICurrencyData { code: 'JPY', native: '日本円', …, decimals: 0 }

// Numeric (ISO 4217) lookup — accepts string | number, normalised to a zero-padded 3-digit key
getCurrencyByNumeric('840') // USD   (canonical ISO form)
getCurrencyByNumeric(840)   // USD   (number works too)
getCurrencyByNumeric(8)     // ALL   (8 → '008')
  • name / native — English and home-locale names (e.g. Japanese Yen / 日本円).
  • symbol / symbolNative — UI glyph and the glyph used in the currency's home locale.
  • numeric is stored as a zero-padded 3-digit string ('008', '048') because ISO 4217 numeric codes have significant leading zeros a JS number can't preserve. getCurrencyByNumeric therefore accepts string | number and normalises with String(n).padStart(3, '0').

Why opt-in / bundle impact

Currency const maps don't reliably tree-shake, so a subpath keeps the main entry flat. Verified: 0 currency bytes in the cjs / mjs / iife index entries (main bundle unchanged).

Artifact Size
mjs/currencies.js (opt-in) ~23 KB (~6 KB gzipped)
currencies.all.min.json (181) ~23 KB
currencies.min.json (in-use, 160) ~20 KB
minimal/currencies.symbol / .numeric ~2 KB each

Data (181 codes)

  • Source: official SIX ISO 4217 list (Pblshd 2026-01-01) for the active set, numeric codes and minor units; Unicode CLDR via Intl for the English + native name, symbol (narrow) and symbolNative. ISO 4217 itself defines no symbols or localized names, hence CLDR. The native name for a multi-country currency uses the primary country's locale (e.g. EUReuro).
  • Reproducible generator: packages/scripts/generateCurrencies.ts (bun run generate:currencies), re-run on ISO updates.
  • Covers 178 active codes + 3 withdrawn codes still referenced by country data (ANG, SLL, USS), flagged withdrawn: true. getCurrencyByNumeric resolves shared numerics to the active code (e.g. 532XCG, not the withdrawn ANG).
  • Where CLDR has no usable glyph, symbol / symbolNative fall back to the ISO code (e.g. KWD); blank/zero-width CLDR values are treated as missing.

Also in this PR

  • ICurrency / ICurrencyData / TCurrencyCode types; getCurrency() + getCurrencyByNumeric() utils.
  • ICountry.currency tightened to TCurrencyCode[] (was string[]) — country currency codes are now validated against the table at type-check time. ⚠️ Minor type-level breaking change: consumers doing country.currency.includes(someDynamicString) would need a cast.
  • Fixed check-types to actually type-check the countries package — it was a no-op (root tsconfig uses project references + files: [], which tsc --noEmit ignores), so CI was catching zero type errors in the main package.
  • SQL currencies table; currencies.d.ts subpath typings; PHP currencies() / currenciesAll() loaders; README; keywords.
  • Tests incl. an integrity check (every country currency exists in the table; names/symbols are non-blank).

Country-data modernization → #167

3 country currency codes are stale vs current ISO 4217 (ANGXCG, SLLSLE, drop USS). That's a country-data change with consumer impact, so it's a separate stacked PR (#167) rather than bundled here.

Notes

  • Generated dist/ is not committed in this PR — it's rebuilt at release (see AGENTS.md).
  • Version bump left for the release flow (chore(release)); a minor or major is warranted given the ICountry.currency type change.
  • bun run ci passes (lint + real check-types + build + tests).

Copilot AI review requested due to automatic review settings June 14, 2026 14:21
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds full ISO 4217 currency support to the countries-list package. New types (ICurrency, ICurrencyData, TCurrencyCode, TCurrencies) are introduced in types.ts, with ICountry.currency updated to use TCurrencyCode[]. A generated data/currencies.ts file maps ~180 currency codes to name, native, symbol, symbolNative, numeric code, decimals, and an optional withdrawn flag. Two lookup functions (getCurrency, getCurrencyByNumeric) are implemented with numeric-index precedence logic and re-exported via an opt-in currencies subpath, with the build configuration updated to produce a separate CJS/ESM bundle for it. A generateCurrencies.ts script fetches and formats currency data from the SIX ISO 4217 XML list, using Intl.DisplayNames for names and Intl.NumberFormat with CLDR for symbols. Script infrastructure (constants, data exports, utilities) and downstream tasks (SQL generation, typings generation, JSON minification) are extended for currencies. Comprehensive tests and README documentation are added.

Poem

🐇 A rabbit counts coins from each land,
With symbols and numerics close at hand,
From SIX we fetch codes, both active and old,
In UAH, EUR, and USD bold.
Now getCurrencyByNumeric pads with care —
ISO 4217 data, finally there! 🪙

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: adding ISO 4217 currency support as an opt-in feature.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description is comprehensive and addresses most template requirements, though it omits the specific template structure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/iso-4217-currencies

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds opt-in ISO 4217 currency support to countries-list via a dedicated countries-list/currencies export so the default entry points remain unchanged in size, while providing richer currency metadata (name, symbols, numeric code, decimals) plus lookup helpers and generated artifacts.

Changes:

  • Introduces a generated currencies dataset and new currency types (ICurrency, ICurrencyData, TCurrencyCode) plus getCurrency() / getCurrencyByNumeric().
  • Adds build/script support to generate typings, SQL, and minimal JSON subsets for currencies (including “in-use” vs “all” outputs).
  • Updates distribution exports (JS/TS/PHP/SQL) and documentation to describe the new opt-in subpath.

Reviewed changes

Copilot reviewed 16 out of 27 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
README.md Documents the new opt-in currencies subpath and dataset details.
packages/test-js/getCurrency.test.ts Adds tests for currency lookups and dataset integrity.
packages/scripts/utils.ts Adds script helper to compute “currencies in use”.
packages/scripts/tasks/minifyJsonData.ts Emits currencies JSON plus minimal symbol/numeric maps.
packages/scripts/tasks/generateTypings.ts Generates currencies.d.ts subpath typings and currency code unions.
packages/scripts/tasks/generateSql.ts Adds SQL generation for a currencies table and inserts.
packages/scripts/package.json Adds generate:currencies script entry.
packages/scripts/generateCurrencies.ts New generator to build the currencies dataset from SIX + Intl.
packages/scripts/data.ts Exposes currencies + computed currencies-in-use for build tasks.
packages/scripts/constants.ts Adds CURRENCIES constant for script outputs.
packages/countries/tsup.config.ts Builds a separate opt-in src/currencies.ts entry (CJS/ESM only).
packages/countries/src/types.ts Adds currency types and currency-related record types.
packages/countries/src/getCurrency.ts Implements getCurrency and numeric-code lookup.
packages/countries/src/data/currencies.ts Adds generated ISO 4217 currency dataset.
packages/countries/src/currencies.ts New opt-in entry that re-exports currencies + lookup helpers.
dist/package.json Adds ./currencies export mapping and updates metadata/keywords.
dist/mjs/currencies.js Adds built ESM artifact for the currencies subpath.
dist/minimal/currencies.symbol.min.json Adds minimal code→symbol map output.
dist/minimal/currencies.numeric.min.json Adds minimal code→numeric map output.
dist/index.php Adds PHP loaders for currencies (in-use and all).
dist/index.d.ts Adds emitted currency types and TCurrencyCode union.
dist/data.sql Adds currencies table DDL and insert statements.
dist/currencies.min.json Adds minified “in-use” currencies JSON output.
dist/currencies.d.ts Adds emitted typings for the countries-list/currencies subpath.
dist/currencies.all.min.json Adds minified “all currencies” JSON output.
dist/cjs/currencies.js Adds built CJS artifact for the currencies subpath.
composer.json Updates description/keywords to mention ISO 4217 currencies.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/countries/src/data/currencies.ts Outdated
Comment thread packages/scripts/generateCurrencies.ts
Comment thread packages/test-js/getCurrency.test.ts
Comment thread packages/scripts/utils.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/countries/src/data/currencies.ts`:
- Around line 265-268: The symbolNative property for the Cape Verdean Escudo
(CVE) currency entry contains an invisible character that renders as blank in
the UI, degrading user experience despite passing tests. Replace the invisible
character in the symbolNative field with a visible fallback value such as the
ISO code (CVE) or the symbol property value to ensure proper display when the
native currency glyph is unavailable or empty.

In `@packages/scripts/utils.ts`:
- Around line 81-95: The code at line 94 silently creates empty objects when a
currency code referenced in the data does not exist in the currencies object,
which can corrupt the output file instead of catching data inconsistencies
early. In the forEach loop that builds currenciesInUse, add a validation check
before the Object.assign call to verify that currencies[code] exists. If the
currency code is not found in the currencies object, throw an error with a
descriptive message that includes the missing currency code so that dataset
drift is surfaced immediately rather than producing incomplete objects in the
final currencies.min.json output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c8de1a23-e67a-41a7-91a0-d9ca60446604

📥 Commits

Reviewing files that changed from the base of the PR and between 594a26d and bc21025.

⛔ Files ignored due to path filters (11)
  • dist/cjs/currencies.js is excluded by !**/dist/**
  • dist/currencies.all.min.json is excluded by !**/dist/**
  • dist/currencies.d.ts is excluded by !**/dist/**
  • dist/currencies.min.json is excluded by !**/dist/**
  • dist/data.sql is excluded by !**/dist/**
  • dist/index.d.ts is excluded by !**/dist/**
  • dist/index.php is excluded by !**/dist/**
  • dist/minimal/currencies.numeric.min.json is excluded by !**/dist/**
  • dist/minimal/currencies.symbol.min.json is excluded by !**/dist/**
  • dist/mjs/currencies.js is excluded by !**/dist/**
  • dist/package.json is excluded by !**/dist/**
📒 Files selected for processing (16)
  • README.md
  • composer.json
  • packages/countries/src/currencies.ts
  • packages/countries/src/data/currencies.ts
  • packages/countries/src/getCurrency.ts
  • packages/countries/src/types.ts
  • packages/countries/tsup.config.ts
  • packages/scripts/constants.ts
  • packages/scripts/data.ts
  • packages/scripts/generateCurrencies.ts
  • packages/scripts/package.json
  • packages/scripts/tasks/generateSql.ts
  • packages/scripts/tasks/generateTypings.ts
  • packages/scripts/tasks/minifyJsonData.ts
  • packages/scripts/utils.ts
  • packages/test-js/getCurrency.test.ts

Comment thread packages/countries/src/data/currencies.ts
Comment thread packages/scripts/utils.ts
dmythro added a commit that referenced this pull request Jun 14, 2026
CLDR can return a visually-empty narrow symbol (e.g. CVE native is U+200B),
which rendered blank in UIs and slipped past the integrity test:

- symbolOf() now falls back to the ISO code when the value has no visible
  (non-whitespace, non-format) code point
- the integrity test requires a visible code point instead of length > 0
- getCurrenciesInUse() throws if a country references a currency missing
  from the table, instead of silently emitting an empty object

Addresses review feedback on #166.
@dmythro
dmythro requested a review from Copilot June 14, 2026 14:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 27 changed files in this pull request and generated no new comments.

@dmythro
dmythro force-pushed the feat/iso-4217-currencies branch from eab0c08 to aeec6f2 Compare June 14, 2026 14:57

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/scripts/generateCurrencies.ts`:
- Line 15: Fix the typo in the URL string at line 15 by correcting "currrency"
(with three consecutive r's) to "currency" (with one r). This typo in the SIX
Group data center URL will cause the fetch operation to fail. Simply correct the
spelling in the URL string to restore functionality.
- Around line 28-35: The local ICurrency interface definition in
generateCurrencies.ts duplicates the canonical ICurrency type exported from
packages/countries/src/types.ts, creating risk of type drift. Remove the local
ICurrency interface definition and instead import ICurrency directly from
packages/countries/src/types.ts at the top of the generateCurrencies.ts file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 465e42f3-48ff-40db-9433-e0ea9546b85c

📥 Commits

Reviewing files that changed from the base of the PR and between eab0c08 and aeec6f2.

⛔ Files ignored due to path filters (2)
  • dist/index.php is excluded by !**/dist/**
  • dist/package.json is excluded by !**/dist/**
📒 Files selected for processing (17)
  • AGENTS.md
  • README.md
  • composer.json
  • packages/countries/src/currencies.ts
  • packages/countries/src/data/currencies.ts
  • packages/countries/src/getCurrency.ts
  • packages/countries/src/types.ts
  • packages/countries/tsup.config.ts
  • packages/scripts/constants.ts
  • packages/scripts/data.ts
  • packages/scripts/generateCurrencies.ts
  • packages/scripts/package.json
  • packages/scripts/tasks/generateSql.ts
  • packages/scripts/tasks/generateTypings.ts
  • packages/scripts/tasks/minifyJsonData.ts
  • packages/scripts/utils.ts
  • packages/test-js/getCurrency.test.ts
✅ Files skipped from review due to trivial changes (4)
  • AGENTS.md
  • README.md
  • packages/scripts/constants.ts
  • composer.json
🚧 Files skipped from review as they are similar to previous changes (12)
  • packages/scripts/package.json
  • packages/scripts/utils.ts
  • packages/countries/src/currencies.ts
  • packages/countries/tsup.config.ts
  • packages/countries/src/data/currencies.ts
  • packages/scripts/tasks/generateSql.ts
  • packages/scripts/data.ts
  • packages/countries/src/getCurrency.ts
  • packages/test-js/getCurrency.test.ts
  • packages/scripts/tasks/minifyJsonData.ts
  • packages/countries/src/types.ts
  • packages/scripts/tasks/generateTypings.ts

Comment thread packages/scripts/generateCurrencies.ts
Comment thread packages/scripts/generateCurrencies.ts Outdated
@dmythro
dmythro force-pushed the feat/iso-4217-currencies branch 2 times, most recently from 12139de to 96a4d29 Compare June 14, 2026 15:26

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/scripts/generateCurrencies.ts`:
- Around line 209-220: The Bun.write() call that writes the currencies.ts file
is executed before validating the completeness of the currency data. Move the
Bun.write() statement to after the missing currency codes check, and add a throw
statement that fails the script when missing.length > 0 to prevent incomplete
generated artifacts from being written to disk.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 774840c9-76d2-468c-8502-a554ecca7619

📥 Commits

Reviewing files that changed from the base of the PR and between 12139de and 96a4d29.

⛔ Files ignored due to path filters (2)
  • dist/index.php is excluded by !**/dist/**
  • dist/package.json is excluded by !**/dist/**
📒 Files selected for processing (19)
  • .gitignore
  • AGENTS.md
  • README.md
  • composer.json
  • package.json
  • packages/countries/src/currencies.ts
  • packages/countries/src/data/currencies.ts
  • packages/countries/src/getCurrency.ts
  • packages/countries/src/types.ts
  • packages/countries/tsup.config.ts
  • packages/scripts/constants.ts
  • packages/scripts/data.ts
  • packages/scripts/generateCurrencies.ts
  • packages/scripts/package.json
  • packages/scripts/tasks/generateSql.ts
  • packages/scripts/tasks/generateTypings.ts
  • packages/scripts/tasks/minifyJsonData.ts
  • packages/scripts/utils.ts
  • packages/test-js/getCurrency.test.ts
✅ Files skipped from review due to trivial changes (6)
  • packages/scripts/constants.ts
  • composer.json
  • packages/scripts/data.ts
  • AGENTS.md
  • .gitignore
  • README.md
🚧 Files skipped from review as they are similar to previous changes (11)
  • packages/scripts/package.json
  • packages/countries/src/currencies.ts
  • packages/countries/tsup.config.ts
  • packages/countries/src/getCurrency.ts
  • packages/scripts/utils.ts
  • packages/test-js/getCurrency.test.ts
  • packages/scripts/tasks/generateTypings.ts
  • packages/scripts/tasks/generateSql.ts
  • packages/countries/src/types.ts
  • package.json
  • packages/scripts/tasks/minifyJsonData.ts

Comment thread packages/scripts/generateCurrencies.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 21 changed files in this pull request and generated 2 comments.

Comment thread packages/scripts/tasks/generateSql.ts
Comment thread packages/scripts/tasks/minifyJsonData.ts

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 21 changed files in this pull request and generated 1 comment.

Comment thread packages/countries/src/getCurrency.ts Outdated
Opt-in `countries-list/currencies` subpath with full ISO 4217 data
(English + native name, UI symbol, native symbol, numeric code and
minor-unit decimals) for 181 codes — the active list plus withdrawn codes
still referenced by country data (flagged `withdrawn`).

- `currencies` map, `getCurrency()` and `getCurrencyByNumeric()` utils
- `ICurrency` / `ICurrencyData` / `TCurrencyCode` types
- `ICountry.currency` is now `TCurrencyCode[]` (validated against the table)
- reproducible generator (SIX ISO 4217 list + Unicode CLDR), with a
  visible-symbol fallback so blank CLDR symbols use the ISO code
- SQL table, PHP loaders, README, keywords
- fix `check-types` so CI actually type-checks the countries package

Data is opt-in: the main bundle is unchanged. Generated dist is built at
release, not committed here (see AGENTS.md).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 21 changed files in this pull request and generated no new comments.

@dmythro
dmythro merged commit d13f57f into main Jun 14, 2026
4 checks passed
@dmythro
dmythro deleted the feat/iso-4217-currencies branch June 14, 2026 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants