postcode-format-validator 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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "postcode-format-validator",
3
- "version": "1.0.0",
4
- "description": "Validate postcodes/postal codes for 100+ countries worldwide based on official format definitions",
3
+ "version": "1.0.1",
4
+ "description": "Validate postcodes/postal codes for 170+ countries worldwide based on official format definitions",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.mjs",
7
7
  "types": "src/index.d.ts",
package/src/formats.js CHANGED
@@ -33,6 +33,183 @@ function formatToRegex(fmt) {
33
33
  return new RegExp(pattern);
34
34
  }
35
35
 
36
+ /**
37
+ * Human-readable country/region names keyed by ISO code.
38
+ */
39
+ const COUNTRY_NAMES = {
40
+ AD: 'Andorra',
41
+ AF: 'Afghanistan',
42
+ AI: 'Anguilla',
43
+ AL: 'Albania',
44
+ AM: 'Armenia',
45
+ AR: 'Argentina',
46
+ AS: 'American Samoa',
47
+ AT: 'Austria',
48
+ AU: 'Australia',
49
+ AX: 'Åland Islands',
50
+ AZ: 'Azerbaijan',
51
+ BA: 'Bosnia and Herzegovina',
52
+ BB: 'Barbados',
53
+ BD: 'Bangladesh',
54
+ BE: 'Belgium',
55
+ BG: 'Bulgaria',
56
+ BH: 'Bahrain',
57
+ BM: 'Bermuda',
58
+ BN: 'Brunei',
59
+ BR: 'Brazil',
60
+ BT: 'Bhutan',
61
+ BY: 'Belarus',
62
+ CA: 'Canada',
63
+ CC: 'Cocos (Keeling) Islands',
64
+ CH: 'Switzerland',
65
+ CL: 'Chile',
66
+ CN: 'China',
67
+ CO: 'Colombia',
68
+ CR: 'Costa Rica',
69
+ CU: 'Cuba',
70
+ CV: 'Cape Verde',
71
+ CX: 'Christmas Island',
72
+ CY: 'Cyprus',
73
+ CZ: 'Czech Republic',
74
+ DE: 'Germany',
75
+ DK: 'Denmark',
76
+ DO: 'Dominican Republic',
77
+ DZ: 'Algeria',
78
+ EC: 'Ecuador',
79
+ EE: 'Estonia',
80
+ EG: 'Egypt',
81
+ ES: 'Spain',
82
+ ET: 'Ethiopia',
83
+ FI: 'Finland',
84
+ FK: 'Falkland Islands',
85
+ FM: 'Micronesia',
86
+ FO: 'Faroe Islands',
87
+ FR: 'France',
88
+ GB: 'United Kingdom',
89
+ GE: 'Georgia',
90
+ GF: 'French Guyana',
91
+ GG: 'Guernsey',
92
+ GI: 'Gibraltar',
93
+ GL: 'Greenland',
94
+ GN: 'Guinea',
95
+ GP: 'Guadeloupe',
96
+ GR: 'Greece',
97
+ GS: 'South Georgia and the South Sandwich Islands',
98
+ GT: 'Guatemala',
99
+ GU: 'Guam',
100
+ GW: 'Guinea-Bissau',
101
+ HN: 'Honduras',
102
+ HR: 'Croatia',
103
+ HT: 'Haiti',
104
+ HU: 'Hungary',
105
+ IC: 'Canary Islands',
106
+ ID: 'Indonesia',
107
+ IL: 'Israel',
108
+ IM: 'Isle of Man',
109
+ IN: 'India',
110
+ IO: 'British Indian Ocean Territory',
111
+ IQ: 'Iraq',
112
+ IR: 'Iran',
113
+ IS: 'Iceland',
114
+ IT: 'Italy',
115
+ JE: 'Jersey',
116
+ JO: 'Jordan',
117
+ JP: 'Japan',
118
+ KE: 'Kenya',
119
+ KG: 'Kyrgyzstan',
120
+ KH: 'Cambodia',
121
+ KR: 'South Korea',
122
+ KV: 'Kosovo',
123
+ KW: 'Kuwait',
124
+ KY: 'Cayman Islands',
125
+ KZ: 'Kazakhstan',
126
+ LA: 'Laos',
127
+ LB: 'Lebanon',
128
+ LI: 'Liechtenstein',
129
+ LK: 'Sri Lanka',
130
+ LR: 'Liberia',
131
+ LS: 'Lesotho',
132
+ LT: 'Lithuania',
133
+ LU: 'Luxembourg',
134
+ LV: 'Latvia',
135
+ MA: 'Morocco',
136
+ MC: 'Monaco',
137
+ MD: 'Moldova',
138
+ ME: 'Montenegro',
139
+ MG: 'Madagascar',
140
+ MH: 'Marshall Islands',
141
+ MK: 'North Macedonia',
142
+ MM: 'Myanmar',
143
+ MN: 'Mongolia',
144
+ MP: 'Northern Mariana Islands',
145
+ MQ: 'Martinique',
146
+ MS: 'Montserrat',
147
+ MT: 'Malta',
148
+ MV: 'Maldives',
149
+ MX: 'Mexico',
150
+ MY: 'Malaysia',
151
+ NC: 'New Caledonia',
152
+ NE: 'Niger',
153
+ NF: 'Norfolk Island',
154
+ NG: 'Nigeria',
155
+ NI: 'Nicaragua',
156
+ NL: 'Netherlands',
157
+ NO: 'Norway',
158
+ NP: 'Nepal',
159
+ NZ: 'New Zealand',
160
+ OM: 'Oman',
161
+ PA: 'Panama',
162
+ PE: 'Peru',
163
+ PG: 'Papua New Guinea',
164
+ PH: 'Philippines',
165
+ PK: 'Pakistan',
166
+ PL: 'Poland',
167
+ PM: 'Saint Pierre and Miquelon',
168
+ PN: 'Pitcairn Islands',
169
+ PR: 'Puerto Rico',
170
+ PS: 'Palestine',
171
+ PT: 'Portugal',
172
+ PW: 'Palau',
173
+ PY: 'Paraguay',
174
+ RE: 'Réunion',
175
+ RO: 'Romania',
176
+ RS: 'Serbia',
177
+ RU: 'Russia',
178
+ SA: 'Saudi Arabia',
179
+ SD: 'Sudan',
180
+ SE: 'Sweden',
181
+ SG: 'Singapore',
182
+ SH: 'Saint Helena',
183
+ SI: 'Slovenia',
184
+ SK: 'Slovakia',
185
+ SM: 'San Marino',
186
+ SN: 'Senegal',
187
+ SV: 'El Salvador',
188
+ SZ: 'Eswatini',
189
+ TC: 'Turks and Caicos Islands',
190
+ TH: 'Thailand',
191
+ TJ: 'Tajikistan',
192
+ TM: 'Turkmenistan',
193
+ TN: 'Tunisia',
194
+ TR: 'Turkey',
195
+ TT: 'Trinidad and Tobago',
196
+ TW: 'Taiwan',
197
+ TZ: 'Tanzania',
198
+ UA: 'Ukraine',
199
+ US: 'United States',
200
+ UY: 'Uruguay',
201
+ UZ: 'Uzbekistan',
202
+ VA: 'Vatican City',
203
+ VE: 'Venezuela',
204
+ VI: 'US Virgin Islands',
205
+ VN: 'Vietnam',
206
+ WF: 'Wallis and Futuna',
207
+ XY: 'St. Barthélemy',
208
+ YT: 'Mayotte',
209
+ ZA: 'South Africa',
210
+ ZM: 'Zambia',
211
+ };
212
+
36
213
  /**
37
214
  * Raw format data derived from postcode_formats.csv.
38
215
  * Key = ISO country/region code (upper-case).
@@ -43,6 +220,15 @@ const POSTCODE_FORMATS = {
43
220
  { format: '99999', significantFigures: 5 },
44
221
  { format: 'AA999', significantFigures: 5 },
45
222
  ],
223
+ AF: [
224
+ { format: '9999', significantFigures: 4 },
225
+ ],
226
+ AI: [
227
+ { format: 'AA-9999', significantFigures: 4 },
228
+ ],
229
+ AL: [
230
+ { format: '9999', significantFigures: 4 },
231
+ ],
46
232
  AM: [
47
233
  { format: '9999', significantFigures: 4 },
48
234
  ],
@@ -58,6 +244,9 @@ const POSTCODE_FORMATS = {
58
244
  AU: [
59
245
  { format: '9999', significantFigures: 4 },
60
246
  ],
247
+ AX: [
248
+ { format: '99999', significantFigures: 5 },
249
+ ],
61
250
  AZ: [
62
251
  { format: '999999', significantFigures: 6 },
63
252
  { format: '9999', significantFigures: 4 },
@@ -65,6 +254,9 @@ const POSTCODE_FORMATS = {
65
254
  BA: [
66
255
  { format: '99999', significantFigures: 5 },
67
256
  ],
257
+ BB: [
258
+ { format: 'AA99999', significantFigures: 7 },
259
+ ],
68
260
  BD: [
69
261
  { format: '9999', significantFigures: 4 },
70
262
  ],
@@ -74,6 +266,14 @@ const POSTCODE_FORMATS = {
74
266
  BG: [
75
267
  { format: '9999', significantFigures: 4 },
76
268
  ],
269
+ BH: [
270
+ { format: '999', significantFigures: 3 },
271
+ { format: '9999', significantFigures: 4 },
272
+ ],
273
+ BM: [
274
+ { format: 'AA 99', significantFigures: 4 },
275
+ { format: 'AA99', significantFigures: 4 },
276
+ ],
77
277
  BN: [
78
278
  { format: 'AA9999', significantFigures: 6 },
79
279
  ],
@@ -82,6 +282,9 @@ const POSTCODE_FORMATS = {
82
282
  { format: '99999-999', significantFigures: 5 },
83
283
  { format: '99999999', significantFigures: 5 },
84
284
  ],
285
+ BT: [
286
+ { format: '99999', significantFigures: 5 },
287
+ ],
85
288
  BY: [
86
289
  { format: '999999', significantFigures: 6 },
87
290
  ],
@@ -89,18 +292,33 @@ const POSTCODE_FORMATS = {
89
292
  { format: 'A9A 9A', significantFigures: 6 },
90
293
  { format: 'A9A 9A9', significantFigures: 6 },
91
294
  ],
295
+ CC: [
296
+ { format: '9999', significantFigures: 4 },
297
+ ],
92
298
  CH: [
93
299
  { format: '9999', significantFigures: 4 },
94
300
  ],
301
+ CL: [
302
+ { format: '9999999', significantFigures: 7 },
303
+ ],
95
304
  CN: [
96
305
  { format: '999999', significantFigures: 6 },
97
306
  ],
98
307
  CO: [
99
308
  { format: '999999', significantFigures: 6 },
100
309
  ],
310
+ CR: [
311
+ { format: '99999', significantFigures: 5 },
312
+ ],
101
313
  CU: [
102
314
  { format: '99999', significantFigures: 5 },
103
315
  ],
316
+ CV: [
317
+ { format: '9999', significantFigures: 4 },
318
+ ],
319
+ CX: [
320
+ { format: '9999', significantFigures: 4 },
321
+ ],
104
322
  CY: [
105
323
  { format: '9999', significantFigures: 4 },
106
324
  ],
@@ -113,6 +331,9 @@ const POSTCODE_FORMATS = {
113
331
  DK: [
114
332
  { format: '9999', significantFigures: 4 },
115
333
  ],
334
+ DO: [
335
+ { format: '99999', significantFigures: 5 },
336
+ ],
116
337
  DZ: [
117
338
  { format: '99999', significantFigures: 5 },
118
339
  ],
@@ -122,12 +343,21 @@ const POSTCODE_FORMATS = {
122
343
  EE: [
123
344
  { format: '99999', significantFigures: 5 },
124
345
  ],
346
+ EG: [
347
+ { format: '99999', significantFigures: 5 },
348
+ ],
125
349
  ES: [
126
350
  { format: '99999', significantFigures: 5 },
127
351
  ],
352
+ ET: [
353
+ { format: '9999', significantFigures: 4 },
354
+ ],
128
355
  FI: [
129
356
  { format: '99999', significantFigures: 5 },
130
357
  ],
358
+ FK: [
359
+ { format: 'AAAA 9AA', significantFigures: 8 },
360
+ ],
131
361
  FM: [
132
362
  { format: '99999', significantFigures: 5 },
133
363
  ],
@@ -155,22 +385,43 @@ const POSTCODE_FORMATS = {
155
385
  { format: 'AA99 9AA', significantFigures: 4 },
156
386
  { format: 'AA9 9AA', significantFigures: 3 },
157
387
  ],
388
+ GI: [
389
+ { format: 'AA99 9AA', significantFigures: 6 },
390
+ ],
158
391
  GL: [
159
392
  { format: '9999', significantFigures: 4 },
160
393
  ],
394
+ GN: [
395
+ { format: '999', significantFigures: 3 },
396
+ ],
161
397
  GP: [
162
398
  { format: '99999', significantFigures: 5 },
163
399
  ],
164
400
  GR: [
165
401
  { format: '999 99', significantFigures: 6 },
166
402
  ],
403
+ GS: [
404
+ { format: 'AAAA 9AA', significantFigures: 8 },
405
+ ],
406
+ GT: [
407
+ { format: '99999', significantFigures: 5 },
408
+ ],
167
409
  GU: [
168
410
  { format: '99999', significantFigures: 5 },
169
411
  { format: '99999-9999', significantFigures: 5 },
170
412
  ],
413
+ GW: [
414
+ { format: '9999', significantFigures: 4 },
415
+ ],
416
+ HN: [
417
+ { format: '99999', significantFigures: 5 },
418
+ ],
171
419
  HR: [
172
420
  { format: '99999', significantFigures: 5 },
173
421
  ],
422
+ HT: [
423
+ { format: '9999', significantFigures: 4 },
424
+ ],
174
425
  HU: [
175
426
  { format: '9999', significantFigures: 4 },
176
427
  ],
@@ -183,9 +434,23 @@ const POSTCODE_FORMATS = {
183
434
  IL: [
184
435
  { format: '9999999', significantFigures: 7 },
185
436
  ],
437
+ IM: [
438
+ { format: 'AA9 9AA', significantFigures: 5 },
439
+ { format: 'AA99 9AA', significantFigures: 6 },
440
+ ],
186
441
  IN: [
187
442
  { format: '999999', significantFigures: 6 },
188
443
  ],
444
+ IO: [
445
+ { format: 'AAAA 9AA', significantFigures: 8 },
446
+ ],
447
+ IQ: [
448
+ { format: '99999', significantFigures: 5 },
449
+ ],
450
+ IR: [
451
+ { format: '9999999999', significantFigures: 10 },
452
+ { format: '99999-99999', significantFigures: 10 },
453
+ ],
189
454
  IS: [
190
455
  { format: '999', significantFigures: 3 },
191
456
  ],
@@ -195,9 +460,15 @@ const POSTCODE_FORMATS = {
195
460
  JE: [
196
461
  { format: 'AA9 9AA', significantFigures: 3 },
197
462
  ],
463
+ JO: [
464
+ { format: '99999', significantFigures: 5 },
465
+ ],
198
466
  JP: [
199
467
  { format: '999-9999', significantFigures: 8 },
200
468
  ],
469
+ KE: [
470
+ { format: '99999', significantFigures: 5 },
471
+ ],
201
472
  KG: [
202
473
  { format: '999999', significantFigures: 6 },
203
474
  ],
@@ -210,12 +481,34 @@ const POSTCODE_FORMATS = {
210
481
  KV: [
211
482
  { format: '99999', significantFigures: 5 },
212
483
  ],
484
+ KW: [
485
+ { format: '99999', significantFigures: 5 },
486
+ ],
487
+ KY: [
488
+ { format: 'AA9-9999', significantFigures: 5 },
489
+ ],
213
490
  KZ: [
214
491
  { format: '999999', significantFigures: 6 },
215
492
  ],
493
+ LA: [
494
+ { format: '99999', significantFigures: 5 },
495
+ ],
496
+ LB: [
497
+ { format: '9999 9999', significantFigures: 8 },
498
+ { format: '9999', significantFigures: 4 },
499
+ ],
216
500
  LI: [
217
501
  { format: '9999', significantFigures: 4 },
218
502
  ],
503
+ LK: [
504
+ { format: '99999', significantFigures: 5 },
505
+ ],
506
+ LR: [
507
+ { format: '9999', significantFigures: 4 },
508
+ ],
509
+ LS: [
510
+ { format: '999', significantFigures: 3 },
511
+ ],
219
512
  LT: [
220
513
  { format: '99999', significantFigures: 5 },
221
514
  ],
@@ -246,6 +539,9 @@ const POSTCODE_FORMATS = {
246
539
  MK: [
247
540
  { format: '9999', significantFigures: 4 },
248
541
  ],
542
+ MM: [
543
+ { format: '99999', significantFigures: 5 },
544
+ ],
249
545
  MN: [
250
546
  { format: '999999', significantFigures: 6 },
251
547
  { format: '99999', significantFigures: 5 },
@@ -256,6 +552,12 @@ const POSTCODE_FORMATS = {
256
552
  MQ: [
257
553
  { format: '99999', significantFigures: 5 },
258
554
  ],
555
+ MS: [
556
+ { format: 'AAA9999', significantFigures: 7 },
557
+ ],
558
+ MT: [
559
+ { format: 'AAA 9999', significantFigures: 7 },
560
+ ],
259
561
  MV: [
260
562
  { format: '99999', significantFigures: 5 },
261
563
  { format: '9999', significantFigures: 4 },
@@ -269,6 +571,18 @@ const POSTCODE_FORMATS = {
269
571
  NC: [
270
572
  { format: '99999', significantFigures: 5 },
271
573
  ],
574
+ NE: [
575
+ { format: '9999', significantFigures: 4 },
576
+ ],
577
+ NF: [
578
+ { format: '9999', significantFigures: 4 },
579
+ ],
580
+ NG: [
581
+ { format: '999999', significantFigures: 6 },
582
+ ],
583
+ NI: [
584
+ { format: '99999', significantFigures: 5 },
585
+ ],
272
586
  NL: [
273
587
  { format: '9999', significantFigures: 4 },
274
588
  { format: '9999 AA', significantFigures: 4 },
@@ -276,9 +590,21 @@ const POSTCODE_FORMATS = {
276
590
  NO: [
277
591
  { format: '9999', significantFigures: 4 },
278
592
  ],
593
+ NP: [
594
+ { format: '99999', significantFigures: 5 },
595
+ ],
279
596
  NZ: [
280
597
  { format: '9999', significantFigures: 4 },
281
598
  ],
599
+ OM: [
600
+ { format: '999', significantFigures: 3 },
601
+ ],
602
+ PA: [
603
+ { format: '9999', significantFigures: 4 },
604
+ ],
605
+ PE: [
606
+ { format: '99999', significantFigures: 5 },
607
+ ],
282
608
  PG: [
283
609
  { format: '999', significantFigures: 3 },
284
610
  ],
@@ -291,15 +617,27 @@ const POSTCODE_FORMATS = {
291
617
  PL: [
292
618
  { format: '99-999', significantFigures: 6 },
293
619
  ],
620
+ PM: [
621
+ { format: '99999', significantFigures: 5 },
622
+ ],
623
+ PN: [
624
+ { format: 'AAAA 9AA', significantFigures: 8 },
625
+ ],
294
626
  PR: [
295
627
  { format: '99999', significantFigures: 5 },
296
628
  ],
629
+ PS: [
630
+ { format: '999', significantFigures: 3 },
631
+ ],
297
632
  PT: [
298
633
  { format: '9999-999', significantFigures: 8 },
299
634
  ],
300
635
  PW: [
301
636
  { format: '99999', significantFigures: 5 },
302
637
  ],
638
+ PY: [
639
+ { format: '9999', significantFigures: 4 },
640
+ ],
303
641
  RE: [
304
642
  { format: '99999', significantFigures: 5 },
305
643
  ],
@@ -312,6 +650,13 @@ const POSTCODE_FORMATS = {
312
650
  RU: [
313
651
  { format: '999999', significantFigures: 6 },
314
652
  ],
653
+ SA: [
654
+ { format: '99999', significantFigures: 5 },
655
+ { format: '99999-9999', significantFigures: 5 },
656
+ ],
657
+ SD: [
658
+ { format: '99999', significantFigures: 5 },
659
+ ],
315
660
  SE: [
316
661
  { format: '999 99', significantFigures: 6 },
317
662
  ],
@@ -330,22 +675,43 @@ const POSTCODE_FORMATS = {
330
675
  SM: [
331
676
  { format: '99999', significantFigures: 5 },
332
677
  ],
678
+ SN: [
679
+ { format: '99999', significantFigures: 5 },
680
+ ],
681
+ SV: [
682
+ { format: '9999', significantFigures: 4 },
683
+ ],
333
684
  SZ: [
334
685
  { format: 'A999', significantFigures: 4 },
335
686
  ],
687
+ TC: [
688
+ { format: 'AAAA 9AA', significantFigures: 8 },
689
+ ],
336
690
  TH: [
337
691
  { format: '99999', significantFigures: 5 },
338
692
  ],
693
+ TJ: [
694
+ { format: '999999', significantFigures: 6 },
695
+ ],
696
+ TM: [
697
+ { format: '999999', significantFigures: 6 },
698
+ ],
339
699
  TN: [
340
700
  { format: '9999', significantFigures: 4 },
341
701
  ],
342
702
  TR: [
343
703
  { format: '99999', significantFigures: 5 },
344
704
  ],
705
+ TT: [
706
+ { format: '999999', significantFigures: 6 },
707
+ ],
345
708
  TW: [
346
709
  { format: '999', significantFigures: 3 },
347
710
  { format: '99999', significantFigures: 5 },
348
711
  ],
712
+ TZ: [
713
+ { format: '99999', significantFigures: 5 },
714
+ ],
349
715
  UA: [
350
716
  { format: '99999', significantFigures: 5 },
351
717
  ],
@@ -353,12 +719,27 @@ const POSTCODE_FORMATS = {
353
719
  { format: '99999', significantFigures: 5 },
354
720
  { format: '99999-9999', significantFigures: 5 },
355
721
  ],
722
+ UY: [
723
+ { format: '99999', significantFigures: 5 },
724
+ ],
356
725
  UZ: [
357
726
  { format: '999999', significantFigures: 6 },
358
727
  ],
728
+ VA: [
729
+ { format: '99999', significantFigures: 5 },
730
+ ],
731
+ VE: [
732
+ { format: '9999', significantFigures: 4 },
733
+ ],
359
734
  VI: [
360
735
  { format: '99999', significantFigures: 5 },
361
736
  ],
737
+ VN: [
738
+ { format: '999999', significantFigures: 6 },
739
+ ],
740
+ WF: [
741
+ { format: '99999', significantFigures: 5 },
742
+ ],
362
743
  XY: [
363
744
  { format: '99999', significantFigures: 5 },
364
745
  ],
@@ -368,6 +749,9 @@ const POSTCODE_FORMATS = {
368
749
  ZA: [
369
750
  { format: '9999', significantFigures: 4 },
370
751
  ],
752
+ ZM: [
753
+ { format: '99999', significantFigures: 5 },
754
+ ],
371
755
  };
372
756
 
373
757
  // Pre-compile regex patterns for each format entry
@@ -377,4 +761,4 @@ for (const code of Object.keys(POSTCODE_FORMATS)) {
377
761
  }
378
762
  }
379
763
 
380
- module.exports = { POSTCODE_FORMATS, formatToRegex };
764
+ module.exports = { POSTCODE_FORMATS, COUNTRY_NAMES, formatToRegex };
package/src/index.d.ts CHANGED
@@ -7,6 +7,29 @@ export interface PostcodeFormat {
7
7
  significantFigures: number;
8
8
  }
9
9
 
10
+ export interface ValidationResult {
11
+ /** Whether the postcode is valid. */
12
+ valid: boolean;
13
+ /** The postcode value that was tested (trimmed). */
14
+ postcode: string;
15
+ /** The normalised (upper-case) country code. */
16
+ countryCode: string;
17
+ /** Human-readable country name, or null if unknown. */
18
+ countryName: string | null;
19
+ /** The format pattern that matched (e.g. '99999'), or null if invalid. */
20
+ matchedFormat: string | null;
21
+ /** Significant figures of the matched format, or null if invalid. */
22
+ significantFigures: number | null;
23
+ /** All accepted format strings for the country, or null if country unknown. */
24
+ acceptedFormats: string[] | null;
25
+ /** Number of accepted formats (0 if country unknown). */
26
+ totalFormats: number;
27
+ /** Whether leading/trailing whitespace was trimmed from input. */
28
+ inputTrimmed: boolean;
29
+ /** Error code: null if valid, otherwise 'INVALID_INPUT' | 'UNKNOWN_COUNTRY' | 'INVALID_FORMAT'. */
30
+ error: 'INVALID_INPUT' | 'UNKNOWN_COUNTRY' | 'INVALID_FORMAT' | null;
31
+ }
32
+
10
33
  /**
11
34
  * Validate a postcode against the known formats for a given country.
12
35
  *
@@ -16,6 +39,16 @@ export interface PostcodeFormat {
16
39
  */
17
40
  export declare function validatePostcode(countryCode: string, postcode: string): boolean;
18
41
 
42
+ /**
43
+ * Validate a postcode and return a detailed result object with country name,
44
+ * matched format, accepted formats, error codes, and more.
45
+ *
46
+ * @param countryCode ISO 3166-1 alpha-2 country/region code (case-insensitive).
47
+ * @param postcode The postcode / postal code to validate.
48
+ * @returns Detailed validation result.
49
+ */
50
+ export declare function validatePostcodeDetailed(countryCode: string, postcode: string): ValidationResult;
51
+
19
52
  /**
20
53
  * Get the accepted postcode format(s) for a country.
21
54
  *
@@ -24,6 +57,14 @@ export declare function validatePostcode(countryCode: string, postcode: string):
24
57
  */
25
58
  export declare function getFormats(countryCode: string): PostcodeFormat[] | null;
26
59
 
60
+ /**
61
+ * Get the country/region name for a given code.
62
+ *
63
+ * @param countryCode ISO country/region code (case-insensitive).
64
+ * @returns Country name, or null if not found.
65
+ */
66
+ export declare function getCountryName(countryCode: string): string | null;
67
+
27
68
  /**
28
69
  * List all supported country codes.
29
70
  *
@@ -33,3 +74,6 @@ export declare function getSupportedCountries(): string[];
33
74
 
34
75
  /** Raw format data keyed by country code. */
35
76
  export declare const POSTCODE_FORMATS: Record<string, PostcodeFormat[]>;
77
+
78
+ /** Country/region names keyed by ISO code. */
79
+ export declare const COUNTRY_NAMES: Record<string, string>;
package/src/index.js CHANGED
@@ -1,21 +1,43 @@
1
1
  /**
2
2
  * postcode-validator
3
3
  *
4
- * Validate postcodes / postal codes for 100+ countries based on their
4
+ * Validate postcodes / postal codes for 170+ countries based on their
5
5
  * official format definitions.
6
6
  *
7
7
  * Usage:
8
- * const { validatePostcode, getFormats, getSupportedCountries } = require('postcode-validator');
8
+ * const { validatePostcode, validatePostcodeDetailed, getFormats, getSupportedCountries } = require('postcode-validator');
9
9
  *
10
10
  * validatePostcode('US', '10001'); // true
11
11
  * validatePostcode('US', '1000'); // false
12
- * validatePostcode('GB', 'SW1A 1AA'); // true
13
- * validatePostcode('CA', 'K1A 0B1'); // true
12
+ *
13
+ * validatePostcodeDetailed('US', '10001');
14
+ * // → { valid: true, postcode: '10001', countryCode: 'US', countryName: 'United States',
15
+ * // matchedFormat: '99999', significantFigures: 5, acceptedFormats: ['99999','99999-9999'],
16
+ * // totalFormats: 2, inputTrimmed: false, error: null }
17
+ *
18
+ * validatePostcodeDetailed('US', '1000');
19
+ * // → { valid: false, postcode: '1000', countryCode: 'US', countryName: 'United States',
20
+ * // matchedFormat: null, significantFigures: null, acceptedFormats: ['99999','99999-9999'],
21
+ * // totalFormats: 2, inputTrimmed: false, error: 'INVALID_FORMAT' }
14
22
  */
15
23
 
16
24
  'use strict';
17
25
 
18
- const { POSTCODE_FORMATS, formatToRegex } = require('./formats');
26
+ const { POSTCODE_FORMATS, COUNTRY_NAMES, formatToRegex } = require('./formats');
27
+
28
+ /**
29
+ * @typedef {Object} ValidationResult
30
+ * @property {boolean} valid Whether the postcode is valid.
31
+ * @property {string} postcode The postcode value that was tested (trimmed).
32
+ * @property {string} countryCode The normalised (upper-case) country code.
33
+ * @property {string|null} countryName Human-readable country name, or null if unknown.
34
+ * @property {string|null} matchedFormat The format pattern that matched (e.g. '99999'), or null.
35
+ * @property {number|null} significantFigures Significant figures of the matched format, or null.
36
+ * @property {string[]|null} acceptedFormats All accepted format strings for the country, or null.
37
+ * @property {number} totalFormats Number of accepted formats (0 if country unknown).
38
+ * @property {boolean} inputTrimmed Whether leading/trailing whitespace was trimmed.
39
+ * @property {string|null} error Error code: null | 'INVALID_INPUT' | 'UNKNOWN_COUNTRY' | 'INVALID_FORMAT'.
40
+ */
19
41
 
20
42
  /**
21
43
  * Validate a postcode against the known formats for a given country.
@@ -41,6 +63,87 @@ function validatePostcode(countryCode, postcode) {
41
63
  return formats.some((entry) => entry.regex.test(trimmed));
42
64
  }
43
65
 
66
+ /**
67
+ * Validate a postcode and return a detailed result object.
68
+ *
69
+ * @param {string} countryCode ISO 3166-1 alpha-2 country/region code (case-insensitive).
70
+ * @param {string} postcode The postcode / postal code to validate.
71
+ * @returns {ValidationResult} Detailed validation result.
72
+ */
73
+ function validatePostcodeDetailed(countryCode, postcode) {
74
+ // ── Handle invalid inputs ────────────────────────────────────
75
+ if (typeof countryCode !== 'string' || typeof postcode !== 'string') {
76
+ return {
77
+ valid: false,
78
+ postcode: typeof postcode === 'string' ? postcode : String(postcode ?? ''),
79
+ countryCode: typeof countryCode === 'string' ? countryCode.trim().toUpperCase() : String(countryCode ?? ''),
80
+ countryName: null,
81
+ matchedFormat: null,
82
+ significantFigures: null,
83
+ acceptedFormats: null,
84
+ totalFormats: 0,
85
+ inputTrimmed: false,
86
+ error: 'INVALID_INPUT',
87
+ };
88
+ }
89
+
90
+ const code = countryCode.trim().toUpperCase();
91
+ const trimmed = postcode.trim();
92
+ const inputTrimmed = trimmed !== postcode;
93
+ const countryName = COUNTRY_NAMES[code] || null;
94
+
95
+ // ── Unknown country ──────────────────────────────────────────
96
+ const formats = POSTCODE_FORMATS[code];
97
+ if (!formats) {
98
+ return {
99
+ valid: false,
100
+ postcode: trimmed,
101
+ countryCode: code,
102
+ countryName,
103
+ matchedFormat: null,
104
+ significantFigures: null,
105
+ acceptedFormats: null,
106
+ totalFormats: 0,
107
+ inputTrimmed,
108
+ error: 'UNKNOWN_COUNTRY',
109
+ };
110
+ }
111
+
112
+ const acceptedFormats = formats.map((f) => f.format);
113
+
114
+ // ── Try each format ──────────────────────────────────────────
115
+ for (const entry of formats) {
116
+ if (entry.regex.test(trimmed)) {
117
+ return {
118
+ valid: true,
119
+ postcode: trimmed,
120
+ countryCode: code,
121
+ countryName,
122
+ matchedFormat: entry.format,
123
+ significantFigures: entry.significantFigures,
124
+ acceptedFormats,
125
+ totalFormats: formats.length,
126
+ inputTrimmed,
127
+ error: null,
128
+ };
129
+ }
130
+ }
131
+
132
+ // ── No format matched ────────────────────────────────────────
133
+ return {
134
+ valid: false,
135
+ postcode: trimmed,
136
+ countryCode: code,
137
+ countryName,
138
+ matchedFormat: null,
139
+ significantFigures: null,
140
+ acceptedFormats,
141
+ totalFormats: formats.length,
142
+ inputTrimmed,
143
+ error: 'INVALID_FORMAT',
144
+ };
145
+ }
146
+
44
147
  /**
45
148
  * Get the accepted postcode format(s) for a country.
46
149
  *
@@ -54,6 +157,18 @@ function getFormats(countryCode) {
54
157
  return POSTCODE_FORMATS[code] || null;
55
158
  }
56
159
 
160
+ /**
161
+ * Get the country/region name for a given code.
162
+ *
163
+ * @param {string} countryCode ISO country/region code (case-insensitive).
164
+ * @returns {string|null} Country name, or null if not found.
165
+ */
166
+ function getCountryName(countryCode) {
167
+ if (typeof countryCode !== 'string') return null;
168
+ const code = countryCode.trim().toUpperCase();
169
+ return COUNTRY_NAMES[code] || null;
170
+ }
171
+
57
172
  /**
58
173
  * List all supported country codes.
59
174
  *
@@ -65,7 +180,10 @@ function getSupportedCountries() {
65
180
 
66
181
  module.exports = {
67
182
  validatePostcode,
183
+ validatePostcodeDetailed,
68
184
  getFormats,
185
+ getCountryName,
69
186
  getSupportedCountries,
70
187
  POSTCODE_FORMATS,
188
+ COUNTRY_NAMES,
71
189
  };
package/src/index.mjs CHANGED
@@ -1,6 +1,9 @@
1
1
  import mod from './index.js';
2
2
  export const validatePostcode = mod.validatePostcode;
3
+ export const validatePostcodeDetailed = mod.validatePostcodeDetailed;
3
4
  export const getFormats = mod.getFormats;
5
+ export const getCountryName = mod.getCountryName;
4
6
  export const getSupportedCountries = mod.getSupportedCountries;
5
7
  export const POSTCODE_FORMATS = mod.POSTCODE_FORMATS;
8
+ export const COUNTRY_NAMES = mod.COUNTRY_NAMES;
6
9
  export default mod;