kennzeichen 0.1.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.
@@ -0,0 +1,910 @@
1
+ // src/core/locations.ts
2
+ var LOCATION = [
3
+ "A",
4
+ "AA",
5
+ "AB",
6
+ "ABG",
7
+ "ABI",
8
+ "AC",
9
+ "AE",
10
+ "AH",
11
+ "AIB",
12
+ "AIC",
13
+ "AK",
14
+ "ALF",
15
+ "ALZ",
16
+ "AM",
17
+ "AN",
18
+ "ANA",
19
+ "ANG",
20
+ "ANK",
21
+ "A\xD6",
22
+ "AP",
23
+ "APD",
24
+ "ARN",
25
+ "ART",
26
+ "AS",
27
+ "ASL",
28
+ "ASZ",
29
+ "AT",
30
+ "AU",
31
+ "AUR",
32
+ "AW",
33
+ "AZ",
34
+ "AZE",
35
+ "B",
36
+ "BA",
37
+ "BAD",
38
+ "BAR",
39
+ "BB",
40
+ "BBG",
41
+ "BBL",
42
+ "BC",
43
+ "BCH",
44
+ "BD",
45
+ "BE",
46
+ "BED",
47
+ "BER",
48
+ "BF",
49
+ "BGD",
50
+ "BGL",
51
+ "BH",
52
+ "BI",
53
+ "BID",
54
+ "BIN",
55
+ "BIR",
56
+ "BIT",
57
+ "BIW",
58
+ "BK",
59
+ "BKS",
60
+ "BL",
61
+ "BLB",
62
+ "BLK",
63
+ "BM",
64
+ "BN",
65
+ "BNA",
66
+ "BO",
67
+ "B\xD6",
68
+ "BOG",
69
+ "BOH",
70
+ "BOR",
71
+ "BOT",
72
+ "BP",
73
+ "BRA",
74
+ "BRB",
75
+ "BRG",
76
+ "BRK",
77
+ "BRL",
78
+ "BRV",
79
+ "BS",
80
+ "BSB",
81
+ "BSK",
82
+ "BT",
83
+ "BTF",
84
+ "B\xDCD",
85
+ "BUL",
86
+ "B\xDCR",
87
+ "B\xDCS",
88
+ "B\xDCZ",
89
+ "BW",
90
+ "BWL",
91
+ "BYL",
92
+ "BZ",
93
+ "C",
94
+ "CA",
95
+ "CAS",
96
+ "CB",
97
+ "CE",
98
+ "CHA",
99
+ "CLP",
100
+ "CLZ",
101
+ "CO",
102
+ "COC",
103
+ "COE",
104
+ "CR",
105
+ "CUX",
106
+ "CW",
107
+ "D",
108
+ "DA",
109
+ "DAH",
110
+ "DAN",
111
+ "DAU",
112
+ "DBR",
113
+ "DD",
114
+ "DE",
115
+ "DEG",
116
+ "DEL",
117
+ "DGF",
118
+ "DH",
119
+ "DI",
120
+ "DIL",
121
+ "DIN",
122
+ "DIZ",
123
+ "DKB",
124
+ "DL",
125
+ "DLG",
126
+ "DM",
127
+ "DN",
128
+ "DO",
129
+ "DON",
130
+ "DU",
131
+ "DUD",
132
+ "D\xDCW",
133
+ "DW",
134
+ "DZ",
135
+ "E",
136
+ "EA",
137
+ "EB",
138
+ "EBE",
139
+ "EBN",
140
+ "EBS",
141
+ "ECK",
142
+ "ED",
143
+ "EE",
144
+ "EF",
145
+ "EG",
146
+ "EH",
147
+ "EI",
148
+ "EIC",
149
+ "EIL",
150
+ "EIN",
151
+ "EIS",
152
+ "EL",
153
+ "EM",
154
+ "EMD",
155
+ "EMS",
156
+ "EN",
157
+ "ER",
158
+ "ERB",
159
+ "ERH",
160
+ "ERK",
161
+ "ERZ",
162
+ "ES",
163
+ "ESB",
164
+ "ESW",
165
+ "EU",
166
+ "EW",
167
+ "F",
168
+ "FB",
169
+ "FD",
170
+ "FDB",
171
+ "FDS",
172
+ "FEU",
173
+ "FF",
174
+ "FFB",
175
+ "FG",
176
+ "FI",
177
+ "FKB",
178
+ "FL",
179
+ "FL\xD6",
180
+ "FN",
181
+ "FO",
182
+ "FOR",
183
+ "FR",
184
+ "FRG",
185
+ "FRI",
186
+ "FRW",
187
+ "FS",
188
+ "FT",
189
+ "FTL",
190
+ "F\xDC",
191
+ "F\xDCS",
192
+ "FW",
193
+ "FZ",
194
+ "G",
195
+ "GA",
196
+ "GAN",
197
+ "GAP",
198
+ "GC",
199
+ "GD",
200
+ "GDB",
201
+ "GE",
202
+ "GEL",
203
+ "GEO",
204
+ "GER",
205
+ "GF",
206
+ "GG",
207
+ "GHA",
208
+ "GHC",
209
+ "GI",
210
+ "GK",
211
+ "GL",
212
+ "GLA",
213
+ "GM",
214
+ "GMN",
215
+ "GN",
216
+ "GNT",
217
+ "G\xD6",
218
+ "GOA",
219
+ "GOH",
220
+ "GP",
221
+ "GR",
222
+ "GRA",
223
+ "GRH",
224
+ "GRI",
225
+ "GRM",
226
+ "GRZ",
227
+ "GS",
228
+ "GT",
229
+ "GTH",
230
+ "G\xDC",
231
+ "GUB",
232
+ "GUN",
233
+ "GV",
234
+ "GVM",
235
+ "GW",
236
+ "GZ",
237
+ "H",
238
+ "HA",
239
+ "HAB",
240
+ "HAL",
241
+ "HAM",
242
+ "HAS",
243
+ "HB",
244
+ "HBN",
245
+ "HBS",
246
+ "HC",
247
+ "HCH",
248
+ "HD",
249
+ "HDH",
250
+ "HDL",
251
+ "HE",
252
+ "HEB",
253
+ "HEF",
254
+ "HEI",
255
+ "HEL",
256
+ "HER",
257
+ "HET",
258
+ "HF",
259
+ "HG",
260
+ "HGN",
261
+ "HGW",
262
+ "HH",
263
+ "HHM",
264
+ "HI",
265
+ "HIG",
266
+ "HIP",
267
+ "HK",
268
+ "HL",
269
+ "HM",
270
+ "HM\xDC",
271
+ "HN",
272
+ "HO",
273
+ "HOG",
274
+ "HOH",
275
+ "HOL",
276
+ "HOM",
277
+ "HOR",
278
+ "H\xD6S",
279
+ "HOT",
280
+ "HP",
281
+ "HR",
282
+ "HRO",
283
+ "HS",
284
+ "HSK",
285
+ "HST",
286
+ "HU",
287
+ "HV",
288
+ "HVL",
289
+ "HWI",
290
+ "HX",
291
+ "HY",
292
+ "HZ",
293
+ "IGB",
294
+ "IK",
295
+ "IL",
296
+ "ILL",
297
+ "IN",
298
+ "IZ",
299
+ "J",
300
+ "JE",
301
+ "JL",
302
+ "J\xDCL",
303
+ "K",
304
+ "KA",
305
+ "KB",
306
+ "KC",
307
+ "KE",
308
+ "KEH",
309
+ "KEL",
310
+ "KEM",
311
+ "KF",
312
+ "KG",
313
+ "KH",
314
+ "KI",
315
+ "KIB",
316
+ "KK",
317
+ "KL",
318
+ "KLE",
319
+ "KLZ",
320
+ "KM",
321
+ "KN",
322
+ "KO",
323
+ "K\xD6N",
324
+ "K\xD6T",
325
+ "K\xD6Z",
326
+ "KR",
327
+ "KRU",
328
+ "KS",
329
+ "KT",
330
+ "KU",
331
+ "K\xDCN",
332
+ "KUS",
333
+ "KW",
334
+ "KY",
335
+ "KYF",
336
+ "L",
337
+ "LA",
338
+ "LAN",
339
+ "LAU",
340
+ "LB",
341
+ "LBS",
342
+ "LBZ",
343
+ "LC",
344
+ "LD",
345
+ "LDK",
346
+ "LDS",
347
+ "LEO",
348
+ "LER",
349
+ "LEV",
350
+ "LF",
351
+ "LG",
352
+ "LH",
353
+ "LI",
354
+ "LIB",
355
+ "LIF",
356
+ "LIP",
357
+ "LL",
358
+ "LM",
359
+ "LN",
360
+ "L\xD6",
361
+ "L\xD6B",
362
+ "LOS",
363
+ "LP",
364
+ "LR",
365
+ "LRO",
366
+ "LSA",
367
+ "LSN",
368
+ "LSZ",
369
+ "LU",
370
+ "L\xDCN",
371
+ "LUP",
372
+ "LWL",
373
+ "M",
374
+ "MA",
375
+ "MAB",
376
+ "MAI",
377
+ "MAK",
378
+ "MAL",
379
+ "MB",
380
+ "MC",
381
+ "MD",
382
+ "ME",
383
+ "MED",
384
+ "MEG",
385
+ "MEI",
386
+ "MEK",
387
+ "MEL",
388
+ "MER",
389
+ "MET",
390
+ "MG",
391
+ "MGH",
392
+ "MGN",
393
+ "MH",
394
+ "MHL",
395
+ "MI",
396
+ "MIL",
397
+ "MK",
398
+ "MKK",
399
+ "ML",
400
+ "MM",
401
+ "MN",
402
+ "MO",
403
+ "MOD",
404
+ "MOL",
405
+ "MON",
406
+ "MOS",
407
+ "MQ",
408
+ "MR",
409
+ "MS",
410
+ "MSE",
411
+ "MSH",
412
+ "MSP",
413
+ "MST",
414
+ "MTK",
415
+ "MTL",
416
+ "MUC",
417
+ "M\xDC",
418
+ "M\xDCB",
419
+ "M\xDCL",
420
+ "M\xDCR",
421
+ "MVL",
422
+ "MW",
423
+ "MY",
424
+ "MYK",
425
+ "MZ",
426
+ "MZG",
427
+ "N",
428
+ "NAB",
429
+ "NAI",
430
+ "NAU",
431
+ "NB",
432
+ "ND",
433
+ "NDH",
434
+ "NE",
435
+ "NEA",
436
+ "NEB",
437
+ "NEC",
438
+ "NEN",
439
+ "NES",
440
+ "NEU",
441
+ "NEW",
442
+ "NF",
443
+ "NH",
444
+ "NI",
445
+ "NK",
446
+ "NL",
447
+ "NM",
448
+ "NMB",
449
+ "NMS",
450
+ "N\xD6",
451
+ "NOH",
452
+ "NOL",
453
+ "NOM",
454
+ "NOR",
455
+ "NP",
456
+ "NR",
457
+ "NRW",
458
+ "NT",
459
+ "NU",
460
+ "NVP",
461
+ "NW",
462
+ "NWM",
463
+ "NY",
464
+ "NZ",
465
+ "OA",
466
+ "OAL",
467
+ "OB",
468
+ "OBB",
469
+ "OBG",
470
+ "OC",
471
+ "OCH",
472
+ "OD",
473
+ "OE",
474
+ "OF",
475
+ "OG",
476
+ "OH",
477
+ "OHA",
478
+ "\xD6HR",
479
+ "OHV",
480
+ "OHZ",
481
+ "OK",
482
+ "OL",
483
+ "OP",
484
+ "OPR",
485
+ "OS",
486
+ "OSL",
487
+ "OTW",
488
+ "OVI",
489
+ "OVL",
490
+ "OVP",
491
+ "OZ",
492
+ "P",
493
+ "PA",
494
+ "PAF",
495
+ "PAN",
496
+ "PAR",
497
+ "PB",
498
+ "PCH",
499
+ "PE",
500
+ "PEG",
501
+ "PF",
502
+ "PI",
503
+ "PIR",
504
+ "PL",
505
+ "PL\xD6",
506
+ "PM",
507
+ "PN",
508
+ "PR",
509
+ "PR\xDC",
510
+ "PS",
511
+ "PW",
512
+ "PZ",
513
+ "QFT",
514
+ "QLB",
515
+ "R",
516
+ "RA",
517
+ "RC",
518
+ "RD",
519
+ "RDG",
520
+ "RE",
521
+ "REG",
522
+ "REH",
523
+ "REI",
524
+ "RG",
525
+ "RH",
526
+ "RI",
527
+ "RID",
528
+ "RIE",
529
+ "RL",
530
+ "RM",
531
+ "RN",
532
+ "RO",
533
+ "ROD",
534
+ "ROF",
535
+ "ROK",
536
+ "ROL",
537
+ "ROS",
538
+ "ROT",
539
+ "ROW",
540
+ "RP",
541
+ "RPL",
542
+ "RS",
543
+ "RSL",
544
+ "RT",
545
+ "RU",
546
+ "R\xDCD",
547
+ "R\xDCG",
548
+ "RV",
549
+ "RW",
550
+ "RZ",
551
+ "S",
552
+ "SAB",
553
+ "SAD",
554
+ "SAL",
555
+ "SAN",
556
+ "SAW",
557
+ "S\xC4K",
558
+ "SB",
559
+ "SBG",
560
+ "SBK",
561
+ "SC",
562
+ "SCZ",
563
+ "SDH",
564
+ "SDL",
565
+ "SDT",
566
+ "SE",
567
+ "SEB",
568
+ "SEE",
569
+ "SEF",
570
+ "SEL",
571
+ "SFB",
572
+ "SFT",
573
+ "SG",
574
+ "SGH",
575
+ "SH",
576
+ "SHA",
577
+ "SHG",
578
+ "SHK",
579
+ "SHL",
580
+ "SI",
581
+ "SIG",
582
+ "SIH",
583
+ "SIM",
584
+ "SK",
585
+ "SL",
586
+ "SLE",
587
+ "SLF",
588
+ "SLG",
589
+ "SLK",
590
+ "SLN",
591
+ "SLS",
592
+ "SL\xDC",
593
+ "SLZ",
594
+ "SM",
595
+ "SM\xDC",
596
+ "SN",
597
+ "SO",
598
+ "SOB",
599
+ "SOG",
600
+ "SOK",
601
+ "S\xD6M",
602
+ "SON",
603
+ "SP",
604
+ "SPB",
605
+ "SPN",
606
+ "SR",
607
+ "SRB",
608
+ "SRO",
609
+ "ST",
610
+ "STA",
611
+ "STB",
612
+ "STD",
613
+ "STE",
614
+ "STL",
615
+ "STO",
616
+ "SU",
617
+ "SUL",
618
+ "S\xDCW",
619
+ "SW",
620
+ "SWA",
621
+ "SY",
622
+ "SZ",
623
+ "SZB",
624
+ "TBB",
625
+ "TDO",
626
+ "TE",
627
+ "TET",
628
+ "TF",
629
+ "TG",
630
+ "THL",
631
+ "THW",
632
+ "TIR",
633
+ "TO",
634
+ "T\xD6L",
635
+ "TP",
636
+ "TR",
637
+ "TS",
638
+ "TT",
639
+ "T\xDC",
640
+ "TUT",
641
+ "UE",
642
+ "UEM",
643
+ "UFF",
644
+ "UH",
645
+ "UL",
646
+ "UM",
647
+ "UN",
648
+ "USI",
649
+ "\xDCB",
650
+ "V",
651
+ "VAI",
652
+ "VB",
653
+ "VEC",
654
+ "VER",
655
+ "VG",
656
+ "VIB",
657
+ "VIE",
658
+ "VIT",
659
+ "VK",
660
+ "VOH",
661
+ "VR",
662
+ "VS",
663
+ "W",
664
+ "WA",
665
+ "WAF",
666
+ "WAK",
667
+ "WAN",
668
+ "WAR",
669
+ "WAT",
670
+ "WB",
671
+ "WBS",
672
+ "WDA",
673
+ "WE",
674
+ "WEL",
675
+ "WEN",
676
+ "WER",
677
+ "WES",
678
+ "WF",
679
+ "WG",
680
+ "WHV",
681
+ "WI",
682
+ "WIL",
683
+ "WIN",
684
+ "WIS",
685
+ "WIT",
686
+ "WIV",
687
+ "WIZ",
688
+ "WK",
689
+ "WL",
690
+ "WLG",
691
+ "WM",
692
+ "WMS",
693
+ "WN",
694
+ "WND",
695
+ "WO",
696
+ "WOB",
697
+ "WOH",
698
+ "WOL",
699
+ "WOR",
700
+ "WOS",
701
+ "WR",
702
+ "WRN",
703
+ "WS",
704
+ "WSF",
705
+ "WST",
706
+ "WSW",
707
+ "WT",
708
+ "WTL",
709
+ "WTM",
710
+ "W\xDC",
711
+ "WUG",
712
+ "W\xDCM",
713
+ "WUN",
714
+ "WUR",
715
+ "WW",
716
+ "WZ",
717
+ "WZL",
718
+ "X",
719
+ "Y",
720
+ "Z",
721
+ "ZE",
722
+ "ZEL",
723
+ "ZI",
724
+ "ZIG",
725
+ "ZP",
726
+ "ZR",
727
+ "ZW",
728
+ "ZZ"
729
+ ];
730
+ var LOCATION_SET = new Set(LOCATION);
731
+
732
+ // src/core/parse.ts
733
+ var PART2_PATTERN = /^[A-Z]{1,2}$/;
734
+ var PART3_PATTERN = /^[1-9][0-9]{0,3}[EH]?$/;
735
+ function parseLicensePlate(input) {
736
+ const normalized = input.trim().toUpperCase().replace(/\s+/g, " ");
737
+ if (!normalized) {
738
+ return { type: "partial", plate: {} };
739
+ }
740
+ if (normalized.includes("-")) {
741
+ const hyphenIndex = normalized.indexOf("-");
742
+ const locationPart = normalized.slice(0, hyphenIndex);
743
+ const rest = normalized.slice(hyphenIndex + 1).trim();
744
+ if (!LOCATION_SET.has(locationPart)) {
745
+ return { type: "invalid" };
746
+ }
747
+ return parseRestWithLocation(locationPart, rest);
748
+ }
749
+ const spaceMatch = normalized.match(/^([A-ZÄÖÜ]{1,3})\s+(.*)$/);
750
+ if (spaceMatch) {
751
+ const [, locationPart, rest] = spaceMatch;
752
+ if (locationPart && rest && LOCATION_SET.has(locationPart)) {
753
+ return parseRestWithLocation(locationPart, rest);
754
+ }
755
+ }
756
+ const candidates = [];
757
+ for (let i = 1; i <= Math.min(3, normalized.length); i++) {
758
+ const possibleLocation = normalized.slice(0, i);
759
+ const rest = normalized.slice(i);
760
+ if (!LOCATION_SET.has(possibleLocation)) continue;
761
+ if (!rest) {
762
+ continue;
763
+ }
764
+ const restResult = parseRestParts(rest);
765
+ if (restResult) {
766
+ candidates.push({
767
+ part1: possibleLocation,
768
+ part2: restResult.part2,
769
+ part3: restResult.part3
770
+ });
771
+ }
772
+ }
773
+ if (candidates.length === 1 && candidates[0]) {
774
+ return { type: "unambiguous", plate: candidates[0] };
775
+ }
776
+ if (candidates.length > 1) {
777
+ return { type: "ambiguous", options: candidates };
778
+ }
779
+ const partialCandidates = [];
780
+ for (let i = Math.min(3, normalized.length); i >= 1; i--) {
781
+ const possibleLocation = normalized.slice(0, i);
782
+ const rest = normalized.slice(i);
783
+ if (!LOCATION_SET.has(possibleLocation)) continue;
784
+ if (!rest) {
785
+ partialCandidates.push({ part1: possibleLocation });
786
+ } else if (/^[A-Z]{1,2}$/.test(rest)) {
787
+ partialCandidates.push({ part1: possibleLocation, part2: rest });
788
+ }
789
+ }
790
+ const partialWithPart2 = partialCandidates.filter((c) => c.part2);
791
+ if (partialWithPart2.length > 1) {
792
+ return {
793
+ type: "ambiguous",
794
+ options: partialWithPart2.map((c) => ({
795
+ part1: c.part1,
796
+ part2: c.part2,
797
+ part3: ""
798
+ }))
799
+ };
800
+ }
801
+ if (partialCandidates.length > 0 && partialCandidates[0]) {
802
+ return { type: "partial", plate: partialCandidates[0] };
803
+ }
804
+ for (let i = normalized.length; i >= 1; i--) {
805
+ const prefix = normalized.slice(0, i);
806
+ const hasMatchingLocation = LOCATION.some((loc) => loc.startsWith(prefix));
807
+ if (hasMatchingLocation) {
808
+ return { type: "partial", plate: {} };
809
+ }
810
+ }
811
+ return { type: "invalid" };
812
+ }
813
+ function parseRestWithLocation(location, rest) {
814
+ if (!rest) {
815
+ return { type: "partial", plate: { part1: location } };
816
+ }
817
+ const result = parseRestParts(rest);
818
+ if (result) {
819
+ return {
820
+ type: "unambiguous",
821
+ plate: { part1: location, part2: result.part2, part3: result.part3 }
822
+ };
823
+ }
824
+ if (/^[A-Z]{1,2}$/.test(rest)) {
825
+ return { type: "partial", plate: { part1: location, part2: rest } };
826
+ }
827
+ const partialMatch = rest.match(/^([A-Z]{1,2})\s?([1-9][0-9]{0,3}[EH]?)$/);
828
+ if (partialMatch) {
829
+ const [, part2, part3] = partialMatch;
830
+ if (part2 && part3 && PART2_PATTERN.test(part2) && PART3_PATTERN.test(part3)) {
831
+ return { type: "unambiguous", plate: { part1: location, part2, part3 } };
832
+ }
833
+ if (part2 && part3) {
834
+ return { type: "partial", plate: { part1: location, part2, part3 } };
835
+ }
836
+ }
837
+ return { type: "invalid" };
838
+ }
839
+ function parseRestParts(rest) {
840
+ const withSpace = rest.match(/^([A-Z]{1,2})\s+([1-9][0-9]{0,3}[EH]?)$/);
841
+ if (withSpace) {
842
+ const [, part2, part3] = withSpace;
843
+ if (part2 && part3 && PART2_PATTERN.test(part2) && PART3_PATTERN.test(part3)) {
844
+ return { part2, part3 };
845
+ }
846
+ }
847
+ const withoutSpace = rest.match(/^([A-Z]{1,2})([1-9][0-9]{0,3}[EH]?)$/);
848
+ if (withoutSpace) {
849
+ const [, part2, part3] = withoutSpace;
850
+ if (part2 && part3 && PART2_PATTERN.test(part2) && PART3_PATTERN.test(part3)) {
851
+ return { part2, part3 };
852
+ }
853
+ }
854
+ return null;
855
+ }
856
+
857
+ // src/core/format.ts
858
+ function formatParsedPlate(plate) {
859
+ const { part1, part2, part3 } = plate;
860
+ if (!part1) return "";
861
+ if (!part2) return part1;
862
+ if (!part3) return `${part1}-${part2}`;
863
+ return `${part1}-${part2} ${part3}`;
864
+ }
865
+ function formatPlateNo(input) {
866
+ try {
867
+ const sanitizedInput = input.trim().replace(/\s+/g, " ");
868
+ const parts = sanitizedInput.split("-");
869
+ if (parts.length !== 2) return input;
870
+ const [_location, _rest] = parts;
871
+ if (!_location || !_rest) return input;
872
+ const location = _location.trim().toUpperCase();
873
+ const rest = _rest.trim();
874
+ const match = rest.match(/^([A-Z]+)\s?(\d{1,4})\s?([A-Z]?)$/i);
875
+ if (!match) return input;
876
+ const [, letters, numbers, lastPart] = match;
877
+ if (!letters || !numbers) return input;
878
+ return `${location}-${letters.toUpperCase()} ${numbers}${lastPart ? lastPart.toUpperCase() : ""}`;
879
+ } catch {
880
+ return input;
881
+ }
882
+ }
883
+
884
+ // src/core/validate.ts
885
+ function sanitizeLicensePlate(plate) {
886
+ return plate.replace(/[-\s]/g, "");
887
+ }
888
+ function cleanPlateNo(input) {
889
+ return input.replace(/[\s-]/g, "");
890
+ }
891
+ function isValidLicensePlate(input) {
892
+ return parseLicensePlate(input).type === "unambiguous";
893
+ }
894
+ function isValidLicensePlateFormat(input) {
895
+ const trimmed = input.trim();
896
+ if (trimmed === "") return true;
897
+ return /^[A-ZÄÖÜ]{1,3}-[A-Z]{1,2} [1-9][0-9]{0,3}[EH]?$/i.test(trimmed);
898
+ }
899
+
900
+ export {
901
+ LOCATION,
902
+ LOCATION_SET,
903
+ parseLicensePlate,
904
+ formatParsedPlate,
905
+ formatPlateNo,
906
+ sanitizeLicensePlate,
907
+ cleanPlateNo,
908
+ isValidLicensePlate,
909
+ isValidLicensePlateFormat
910
+ };