diff --git a/DATA_REQUIREMENTS.md b/DATA_REQUIREMENTS.md new file mode 100644 index 0000000..9746d7e --- /dev/null +++ b/DATA_REQUIREMENTS.md @@ -0,0 +1,55 @@ +# Country Data Requirements +Guide for adding a new country to the static Region Identifier dataset. Each supported country needs three JSON files plus a small code change. + +## 1) Country config – `country/ISO3.json` +- Keys: + - `zipCodeFormat`: `"numeric"` or `"alpha"`. + - `zipCodeLength`: integer, required for numeric formats to pad/compare values (USA=5, AUS=4, DEU=5, etc.). Omit for alpha formats (CAN/GBR/NLD). +- Example: +```json +{ "zipCodeFormat": "numeric", "zipCodeLength": 5 } +``` + +## 2) Region names – `regionNames/ISO3.json` +- Plain object mapping ISO 3166-2 region codes (same codes used in `regions/*.json`) to display names in English. +- Example (`regionNames/AUS.json`): +```json +{ + "AU-NSW": "New South Wales", + "AU-VIC": "Victoria" +} +``` + +## 3) Region mappings – `regions/ISO3.json` +Array of objects that map postal codes to ISO 3166-2 region codes. Formats already used in the repo: +- **Numeric intervals** (inclusive): objects with `low`, `high`, `region`. Values can be numbers or numeric strings if leading zeros matter. Example (`regions/AUS.json`): +```json +{ "region": "AU-NSW", "low": 1000, "high": 1999 } +``` +- **Explicit codes**: objects with `low`, `region`, no `high`. Every postal code (or prefix) must be listed. Use strings to preserve zeros. Examples: + - Belgium lists every 4-digit code (`regions/BEL.json`). + - Spain lists 5-digit codes as strings (`regions/ESP.json`). + - Mexico lists 2-digit prefixes (`regions/MEX.json`). + - CAN/GBR use alpha prefixes (e.g., `"low": "X0A"` or `"low": "AB"`). +- **Discrete lists**: objects with `region` and `list` (array of codes). Numeric countries store numbers; matching uses `zipCodeLength` to pad leading zeros before comparison. Examples: USA (`list` of 5-digit numbers), RUS (per-region lists). + +Additional format notes: +- Files can mix formats if needed. Order matters because the lookup stops at the first match. +- Intervals and lists are treated as inclusive ranges; for alpha codes only exact equality is used. +- Keep codes as strings when leading zeros are significant. + +## 4) Code wiring +- Add the ISO3 code to `availableCountries` in `lib/region.js`; otherwise the static data is ignored and Google is used. +- If the country needs custom postal-code normalization, extend `validateZipCode` (see existing cases for GBR, CAN, NLD, MEX). + +## 5) Testing +- Add test cases to `test/tests.js` under `countriesPostalCodes`: include the country ISO/name, a representative zip, expected region code, and set `usingGoogle: false`. +- Run `npm test` to execute Mocha tests. +- Optional: verify pretty-name lookups via `getNameFromCountryAndRegion` using the `regionNames` file. + +## 6) Data quality checklist +- Region codes must be valid ISO 3166-2 for the country. +- `regionNames` should be English and cover every region code present in `regions/ISO3.json`. +- Postal-code coverage should include territories and edge prefixes (e.g., US territories, Canadian northern prefixes). +- Prefer ascending ordering of `regions` entries to keep matching predictable. +- Avoid empty mappings; placeholders (e.g., empty lists) will yield null regions and fall back to Google. diff --git a/README.md b/README.md index b8c236a..cc03d24 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Utility module that provides an easy way to identify the region of the country d - MEX - NLD - RUS +- SRB - SWE - USA diff --git a/country/SRB.json b/country/SRB.json new file mode 100644 index 0000000..797c859 --- /dev/null +++ b/country/SRB.json @@ -0,0 +1,4 @@ +{ + "zipCodeFormat": "numeric", + "zipCodeLength": 5 +} diff --git a/lib/region.js b/lib/region.js index 1940c00..6f9599f 100644 --- a/lib/region.js +++ b/lib/region.js @@ -18,6 +18,7 @@ const availableCountries = new Set([ 'MEX', 'NLD', 'RUS', + 'SRB', 'SWE', 'USA', 'AUS', diff --git a/regionNames/SRB.json b/regionNames/SRB.json new file mode 100644 index 0000000..732ca2c --- /dev/null +++ b/regionNames/SRB.json @@ -0,0 +1,27 @@ +{ + "RS-00": "Belgrade", + "RS-01": "North Bačka", + "RS-02": "Central Banat", + "RS-03": "North Banat", + "RS-04": "South Banat", + "RS-05": "West Bačka", + "RS-06": "South Bačka", + "RS-07": "Srem", + "RS-08": "Mačva", + "RS-09": "Kolubara", + "RS-10": "Podunavlje", + "RS-11": "Braničevo", + "RS-12": "Šumadija", + "RS-13": "Pomoravlje", + "RS-14": "Bor", + "RS-15": "Zaječar", + "RS-16": "Zlatibor", + "RS-17": "Moravica", + "RS-18": "Raška", + "RS-19": "Rasina", + "RS-20": "Nišava", + "RS-21": "Toplica", + "RS-22": "Pirot", + "RS-23": "Jablanica", + "RS-24": "Pčinja" +} diff --git a/regions/SRB.json b/regions/SRB.json new file mode 100644 index 0000000..eb8bd6c --- /dev/null +++ b/regions/SRB.json @@ -0,0 +1,245 @@ +[ + { + "region": "RS-00", + "low": 11000, + "high": 11299 + }, + { + "region": "RS-00", + "list": [ + 11306, + 11307, + 11308, + 11309, + 11351 + ] + }, + { + "region": "RS-10", + "low": 11300, + "high": 11305 + }, + { + "region": "RS-10", + "low": 11310, + "high": 11325 + }, + { + "region": "RS-10", + "low": 11328, + "high": 11329 + }, + { + "region": "RS-10", + "list": [ + 11420, + 11423, + 11425, + 11431, + 11432 + ] + }, + { + "region": "RS-00", + "low": 11400, + "high": 11419 + }, + { + "region": "RS-00", + "low": 11426, + "high": 11427 + }, + { + "region": "RS-00", + "list": [ + 11430, + 11433 + ] + }, + { + "region": "RS-00", + "low": 11450, + "high": 11462 + }, + { + "region": "RS-00", + "low": 11500, + "high": 11599 + }, + { + "region": "RS-02", + "list": [ + 11467 + ] + }, + { + "region": "RS-11", + "low": 12000, + "high": 12399 + }, + { + "region": "RS-09", + "low": 14000, + "high": 14299 + }, + { + "region": "RS-08", + "low": 15000, + "high": 15399 + }, + { + "region": "RS-23", + "low": 16000, + "high": 16299 + }, + { + "region": "RS-24", + "low": 17500, + "high": 17599 + }, + { + "region": "RS-15", + "low": 18230, + "high": 18237 + }, + { + "region": "RS-20", + "low": 18000, + "high": 18229 + }, + { + "region": "RS-20", + "low": 18238, + "high": 18269 + }, + { + "region": "RS-22", + "low": 18300, + "high": 18359 + }, + { + "region": "RS-20", + "low": 18360, + "high": 18369 + }, + { + "region": "RS-21", + "low": 18400, + "high": 18499 + }, + { + "region": "RS-15", + "low": 19000, + "high": 19099 + }, + { + "region": "RS-15", + "low": 19200, + "high": 19209 + }, + { + "region": "RS-15", + "low": 19214, + "high": 19214 + }, + { + "region": "RS-15", + "low": 19227, + "high": 19228 + }, + { + "region": "RS-14", + "low": 19210, + "high": 19229 + }, + { + "region": "RS-15", + "low": 19233, + "high": 19235 + }, + { + "region": "RS-14", + "low": 19250, + "high": 19259 + }, + { + "region": "RS-14", + "low": 19300, + "high": 19335 + }, + { + "region": "RS-15", + "low": 19340, + "high": 19378 + }, + { + "region": "RS-06", + "low": 21000, + "high": 21499 + }, + { + "region": "RS-07", + "low": 22000, + "high": 22499 + }, + { + "region": "RS-02", + "low": 23100, + "high": 23299 + }, + { + "region": "RS-03", + "low": 23300, + "high": 23399 + }, + { + "region": "RS-01", + "low": 24000, + "high": 24399 + }, + { + "region": "RS-03", + "low": 24400, + "high": 24499 + }, + { + "region": "RS-05", + "low": 25000, + "high": 25299 + }, + { + "region": "RS-04", + "low": 26000, + "high": 26399 + }, + { + "region": "RS-16", + "low": 31000, + "high": 31399 + }, + { + "region": "RS-17", + "low": 32000, + "high": 32399 + }, + { + "region": "RS-12", + "low": 34000, + "high": 34399 + }, + { + "region": "RS-13", + "low": 35000, + "high": 35299 + }, + { + "region": "RS-18", + "low": 36000, + "high": 36399 + }, + { + "region": "RS-19", + "low": 37000, + "high": 37299 + } +] \ No newline at end of file diff --git a/test/tests.js b/test/tests.js index 007dd31..02572f2 100644 --- a/test/tests.js +++ b/test/tests.js @@ -206,6 +206,27 @@ const countriesPostalCodes = { result: 'MX-CMX', usingGoogle: false, }], + 'Serbia': [{ + name: 'SRB', + zip: '11000', + result: 'RS-00', + usingGoogle: false, + }, { + name: 'SRB', + zip: '11320', + result: 'RS-10', + usingGoogle: false, + }, { + name: 'SRB', + zip: '18230', + result: 'RS-15', + usingGoogle: false, + }, { + name: 'SRB', + zip: '24430', + result: 'RS-03', + usingGoogle: false, + }], 'United States': [{ name: 'USA', zip: '972022239',