@budiauktioner/buildi-primitives 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.
Files changed (107) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/LICENSE +21 -0
  3. package/README.md +253 -0
  4. package/THIRD_PARTY_NOTICES.md +52 -0
  5. package/dist/banking/index.cjs +6491 -0
  6. package/dist/banking/index.cjs.map +1 -0
  7. package/dist/banking/index.d.cts +58 -0
  8. package/dist/banking/index.d.ts +58 -0
  9. package/dist/banking/index.js +6464 -0
  10. package/dist/banking/index.js.map +1 -0
  11. package/dist/contact/index.cjs +6678 -0
  12. package/dist/contact/index.cjs.map +1 -0
  13. package/dist/contact/index.d.cts +709 -0
  14. package/dist/contact/index.d.ts +709 -0
  15. package/dist/contact/index.js +6586 -0
  16. package/dist/contact/index.js.map +1 -0
  17. package/dist/country-BhD51LDL.d.cts +433 -0
  18. package/dist/country-p0n0EVQ9.d.ts +433 -0
  19. package/dist/finance/index.cjs +3592 -0
  20. package/dist/finance/index.cjs.map +1 -0
  21. package/dist/finance/index.d.cts +83 -0
  22. package/dist/finance/index.d.ts +83 -0
  23. package/dist/finance/index.js +3584 -0
  24. package/dist/finance/index.js.map +1 -0
  25. package/dist/geography/index.cjs +4227 -0
  26. package/dist/geography/index.cjs.map +1 -0
  27. package/dist/geography/index.d.cts +34 -0
  28. package/dist/geography/index.d.ts +34 -0
  29. package/dist/geography/index.js +4202 -0
  30. package/dist/geography/index.js.map +1 -0
  31. package/dist/index.cjs +14087 -0
  32. package/dist/index.cjs.map +1 -0
  33. package/dist/index.d.cts +75 -0
  34. package/dist/index.d.ts +75 -0
  35. package/dist/index.js +13868 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/isin-EeVPpNWu.d.ts +39 -0
  38. package/dist/isin-ZlQLBVm8.d.cts +39 -0
  39. package/dist/organization/index.cjs +2376 -0
  40. package/dist/organization/index.cjs.map +1 -0
  41. package/dist/organization/index.d.cts +117 -0
  42. package/dist/organization/index.d.ts +117 -0
  43. package/dist/organization/index.js +2346 -0
  44. package/dist/organization/index.js.map +1 -0
  45. package/dist/person/index.cjs +1144 -0
  46. package/dist/person/index.cjs.map +1 -0
  47. package/dist/person/index.d.cts +60 -0
  48. package/dist/person/index.d.ts +60 -0
  49. package/dist/person/index.js +1125 -0
  50. package/dist/person/index.js.map +1 -0
  51. package/dist/person-full-name-Cmc9Ynuc.d.cts +82 -0
  52. package/dist/person-full-name-D6Hbsab6.d.ts +82 -0
  53. package/dist/phone-number-C24--ggy.d.ts +139 -0
  54. package/dist/phone-number-DZ-YxCQQ.d.cts +139 -0
  55. package/dist/property/index.cjs +487 -0
  56. package/dist/property/index.cjs.map +1 -0
  57. package/dist/property/index.d.cts +56 -0
  58. package/dist/property/index.d.ts +56 -0
  59. package/dist/property/index.js +480 -0
  60. package/dist/property/index.js.map +1 -0
  61. package/dist/sample-data/index.cjs +12310 -0
  62. package/dist/sample-data/index.cjs.map +1 -0
  63. package/dist/sample-data/index.d.cts +260 -0
  64. package/dist/sample-data/index.d.ts +260 -0
  65. package/dist/sample-data/index.js +12302 -0
  66. package/dist/sample-data/index.js.map +1 -0
  67. package/dist/swedish-address-DNC3ftRF.d.cts +297 -0
  68. package/dist/swedish-address-GMzjqgxb.d.ts +297 -0
  69. package/dist/swedish-bank-account-holder-name-BFJ8h1aO.d.cts +45 -0
  70. package/dist/swedish-bank-account-holder-name-CAAru07F.d.ts +45 -0
  71. package/dist/swedish-municipality-DlUS7g7h.d.cts +87 -0
  72. package/dist/swedish-municipality-nDRHYRAd.d.ts +87 -0
  73. package/dist/swedish-organization-name-D7NvERxA.d.cts +33 -0
  74. package/dist/swedish-organization-name-rR0Q836C.d.ts +33 -0
  75. package/dist/swedish-organization-number-Bcj7V_lh.d.cts +130 -0
  76. package/dist/swedish-organization-number-DM8dpXwR.d.ts +130 -0
  77. package/dist/swedish-organization-type-CZOdETwG.d.cts +29 -0
  78. package/dist/swedish-organization-type-CZOdETwG.d.ts +29 -0
  79. package/dist/swedish-personal-identity-number-BiIg4io3.d.ts +149 -0
  80. package/dist/swedish-personal-identity-number-Cp9Coz55.d.cts +149 -0
  81. package/dist/swedish-property-designation-BM-gdd9x.d.ts +46 -0
  82. package/dist/swedish-property-designation-BaHXufqV.d.cts +46 -0
  83. package/dist/swedish-sni-code-Ccsswpni.d.ts +53 -0
  84. package/dist/swedish-sni-code-CuJFyM6l.d.cts +53 -0
  85. package/dist/swedish-swish-number-CL6Gx_h3.d.cts +397 -0
  86. package/dist/swedish-swish-number-DDG3mNDg.d.ts +397 -0
  87. package/dist/text-candidate-qg2bD9PY.d.cts +110 -0
  88. package/dist/text-candidate-qg2bD9PY.d.ts +110 -0
  89. package/dist/text-scanning/index.cjs +10414 -0
  90. package/dist/text-scanning/index.cjs.map +1 -0
  91. package/dist/text-scanning/index.d.cts +153 -0
  92. package/dist/text-scanning/index.d.ts +153 -0
  93. package/dist/text-scanning/index.js +10406 -0
  94. package/dist/text-scanning/index.js.map +1 -0
  95. package/dist/validation/index.cjs +83 -0
  96. package/dist/validation/index.cjs.map +1 -0
  97. package/dist/validation/index.d.cts +63 -0
  98. package/dist/validation/index.d.ts +63 -0
  99. package/dist/validation/index.js +79 -0
  100. package/dist/validation/index.js.map +1 -0
  101. package/dist/web/index.cjs +3994 -0
  102. package/dist/web/index.cjs.map +1 -0
  103. package/dist/web/index.d.cts +203 -0
  104. package/dist/web/index.d.ts +203 -0
  105. package/dist/web/index.js +3987 -0
  106. package/dist/web/index.js.map +1 -0
  107. package/package.json +211 -0
@@ -0,0 +1,1144 @@
1
+ 'use strict';
2
+
3
+ // src/primitives-defaults.ts
4
+ var DEFAULT_CULTURE = "sv-SE";
5
+ var DEFAULT_UI_CULTURE = "sv-SE";
6
+ var state = {
7
+ culture: DEFAULT_CULTURE,
8
+ uiCulture: DEFAULT_UI_CULTURE};
9
+ var PrimitivesDefaults = {
10
+ /**
11
+ * BCP-47 locale tag used for casing and number formatting.
12
+ * Defaults to `'sv-SE'`.
13
+ */
14
+ get culture() {
15
+ return state.culture;
16
+ },
17
+ set culture(value) {
18
+ state.culture = value;
19
+ },
20
+ /**
21
+ * `true` when {@link uiCulture} is Swedish (`sv` or `sv-*`).
22
+ * Types use this to select between localized and English display names.
23
+ */
24
+ get useLocalizedDisplayNames() {
25
+ const lang = state.uiCulture.toLowerCase().split("-")[0];
26
+ return lang === "sv";
27
+ }};
28
+
29
+ // src/internal/input-sanitization.ts
30
+ var FORMAT_OR_NOT_ASSIGNED = /[\p{Cf}\p{Cn}]/u;
31
+ var SPACE_SEPARATOR = /[\p{Zs}\p{Zl}\p{Zp}]/u;
32
+ var CONTROL = /\p{Cc}/u;
33
+ function sanitizeInput(input) {
34
+ let out = "";
35
+ for (const c of input) {
36
+ if (c === "\u2018" || c === "\u2019" || c === "\u201A" || c === "\u201B") {
37
+ out += "'";
38
+ continue;
39
+ }
40
+ if (c === "\u201C" || c === "\u201D" || c === "\u201E" || c === "\u201F" || c === "\xAB" || c === "\xBB") {
41
+ out += '"';
42
+ continue;
43
+ }
44
+ if (FORMAT_OR_NOT_ASSIGNED.test(c)) {
45
+ continue;
46
+ }
47
+ if (CONTROL.test(c)) {
48
+ if (c === " " || c === "\n" || c === "\r") out += " ";
49
+ continue;
50
+ }
51
+ if (SPACE_SEPARATOR.test(c)) {
52
+ out += " ";
53
+ continue;
54
+ }
55
+ out += c;
56
+ }
57
+ return out;
58
+ }
59
+ var WHITESPACE_RUN = /\s+/g;
60
+ function collapseWhitespace(input) {
61
+ if (input == null) return "";
62
+ return sanitizeInput(input).trim().replace(WHITESPACE_RUN, " ");
63
+ }
64
+
65
+ // src/person/person-name-normalization.ts
66
+ var SINGLE_PART_PATTERN = /^(?:[\p{L}\p{M}]+|['\p{L}\p{M}]{2,}|[\p{Lo}])(?:['\p{Zs}-][\p{L}\p{M}]+)*$/u;
67
+ var HONORIFICS = [
68
+ "fr\xF6ken",
69
+ "froken",
70
+ "froeken",
71
+ "prof",
72
+ "miss",
73
+ "mrs",
74
+ "mr",
75
+ "ms",
76
+ "dr",
77
+ "herr",
78
+ "fru"
79
+ ];
80
+ function collapseWhitespace2(input) {
81
+ let result = collapseWhitespace(input);
82
+ result = result.replace(/\s*-\s*/g, "-");
83
+ const parts = result.split(" ").map((p) => p.replace(/^\.+|\.+$/g, "")).filter((p) => p.length > 0);
84
+ result = parts.join(" ");
85
+ return stripLeadingHonorific(result);
86
+ }
87
+ function stripLeadingHonorific(input) {
88
+ const lower = input.toLowerCase();
89
+ for (const h of HONORIFICS) {
90
+ if (input.length <= h.length) continue;
91
+ if (!lower.startsWith(h)) continue;
92
+ if (input[h.length] !== " ") continue;
93
+ return input.slice(h.length + 1);
94
+ }
95
+ return input;
96
+ }
97
+ function normalizeCasing(input) {
98
+ const letters = [...input].filter((c) => /\p{L}/u.test(c));
99
+ if (letters.length === 0) return input;
100
+ const culture = PrimitivesDefaults.culture;
101
+ const allLower = letters.every((c) => c === c.toLocaleLowerCase(culture));
102
+ const allUpper = letters.every((c) => c === c.toLocaleUpperCase(culture));
103
+ return allLower || allUpper ? capitalizeEachWord(input) : input;
104
+ }
105
+ function validateNamePart(value) {
106
+ if (value == null || value.trim() === "") return false;
107
+ if (/[\p{Cc}]/u.test(value)) return false;
108
+ if (/[\p{Cn}]/u.test(value)) return false;
109
+ return SINGLE_PART_PATTERN.test(value);
110
+ }
111
+ function validateGivenNames(value) {
112
+ if (value == null || value.trim() === "") return false;
113
+ const parts = value.split(" ").filter((p) => p !== "");
114
+ return parts.length > 0 && parts.every(validateNamePart);
115
+ }
116
+ function capitalizeEachWord(input) {
117
+ return input.split(" ").filter(Boolean).map(capitalizeHyphenated).join(" ");
118
+ }
119
+ function capitalizeHyphenated(word) {
120
+ return word.split("-").map(capitalizeWord).join("-");
121
+ }
122
+ function capitalizeWord(word) {
123
+ if (!word) return word;
124
+ const culture = PrimitivesDefaults.culture;
125
+ const lowered = word.toLocaleLowerCase(culture);
126
+ for (let i = 0; i < lowered.length; i++) {
127
+ if (/\p{L}/u.test(lowered[i])) {
128
+ return lowered.slice(0, i) + lowered[i].toLocaleUpperCase(culture) + lowered.slice(i + 1);
129
+ }
130
+ }
131
+ return lowered;
132
+ }
133
+
134
+ // src/person/person-given-name.ts
135
+ var MAX_INPUT_LENGTH = 200;
136
+ var PersonGivenName = class _PersonGivenName {
137
+ static typeInfo = Object.freeze({
138
+ englishName: "Given Name",
139
+ localizedName: "F\xF6rnamn",
140
+ emoji: "\u270F\uFE0F",
141
+ sources: Object.freeze([
142
+ "https://skatteverket.se/privat/folkbokforing/namn.4.18e1b10334ebe8bc80004083.html",
143
+ "https://www.riksdagen.se/sv/dokument-och-lagar/dokument/svensk-forfattningssamling/lag-20161013-om-personnamn_sfs-2016-1013/"
144
+ ])
145
+ });
146
+ value;
147
+ names;
148
+ preferredName;
149
+ constructor(value, names, preferredName) {
150
+ this.value = value;
151
+ this.names = Object.freeze([...names]);
152
+ this.preferredName = preferredName;
153
+ }
154
+ static tryParse(input, options) {
155
+ const collapsed = collapseWhitespace2(input);
156
+ if (collapsed.length === 0 || collapsed.length > MAX_INPUT_LENGTH) return null;
157
+ const normalized = normalizeCasing(collapsed);
158
+ if (!validateGivenNames(normalized)) return null;
159
+ const names = normalized.split(" ").filter((p) => p !== "");
160
+ let preferred = null;
161
+ const preferredInput = options?.preferredName ?? null;
162
+ if (preferredInput != null && preferredInput.trim() !== "") {
163
+ const np = normalizeCasing(collapseWhitespace2(preferredInput));
164
+ const found = names.find((n) => n.toLowerCase() === np.toLowerCase()) ?? null;
165
+ if (found === null) return null;
166
+ preferred = found;
167
+ }
168
+ return new _PersonGivenName(normalized, names, preferred);
169
+ }
170
+ static parse(input, options) {
171
+ const r = _PersonGivenName.tryParse(input, options);
172
+ if (r === null) throw new Error("Invalid given name(s).");
173
+ return r;
174
+ }
175
+ static isValid(input) {
176
+ return _PersonGivenName.tryParse(input) !== null;
177
+ }
178
+ static format(input, options) {
179
+ const r = _PersonGivenName.tryParse(input);
180
+ if (r) return r.value;
181
+ if (options?.fallbackToTrimmedInputWhenInvalid && input != null && input.trim() !== "") {
182
+ return input.trim();
183
+ }
184
+ return null;
185
+ }
186
+ static normalize(input, options) {
187
+ return _PersonGivenName.format(input, options);
188
+ }
189
+ static isNormalized(input) {
190
+ return input != null && _PersonGivenName.normalize(input) === input;
191
+ }
192
+ withPreferredName(preferredName) {
193
+ const found = this.names.find((n) => n.toLowerCase() === preferredName.toLowerCase()) ?? null;
194
+ if (found === null) {
195
+ throw new Error("Preferred name must be one of the given names.");
196
+ }
197
+ return new _PersonGivenName(this.value, this.names, found);
198
+ }
199
+ toNormalizedString() {
200
+ return this.value;
201
+ }
202
+ toString() {
203
+ return this.value;
204
+ }
205
+ equals(other) {
206
+ return other != null && this.value === other.value;
207
+ }
208
+ compareTo(other) {
209
+ if (other == null) return 1;
210
+ return this.value < other.value ? -1 : this.value > other.value ? 1 : 0;
211
+ }
212
+ };
213
+
214
+ // src/person/person-family-name.ts
215
+ var MAX_INPUT_LENGTH2 = 200;
216
+ var PersonFamilyName = class _PersonFamilyName {
217
+ static typeInfo = Object.freeze({
218
+ englishName: "Family Name",
219
+ localizedName: "Efternamn",
220
+ emoji: "\u{1F4DB}",
221
+ sources: Object.freeze([
222
+ "https://skatteverket.se/privat/folkbokforing/namn.4.18e1b10334ebe8bc80004083.html",
223
+ "https://www.riksdagen.se/sv/dokument-och-lagar/dokument/svensk-forfattningssamling/lag-20161013-om-personnamn_sfs-2016-1013/"
224
+ ])
225
+ });
226
+ value;
227
+ constructor(value) {
228
+ this.value = value;
229
+ }
230
+ static tryParse(input) {
231
+ const collapsed = collapseWhitespace2(input);
232
+ if (collapsed.length === 0 || collapsed.length > MAX_INPUT_LENGTH2) return null;
233
+ const normalized = normalizeCasing(collapsed);
234
+ if (!validateNamePart(normalized)) return null;
235
+ return new _PersonFamilyName(normalized);
236
+ }
237
+ static parse(input) {
238
+ const r = _PersonFamilyName.tryParse(input);
239
+ if (r === null) throw new Error("Invalid family name.");
240
+ return r;
241
+ }
242
+ static isValid(input) {
243
+ return _PersonFamilyName.tryParse(input) !== null;
244
+ }
245
+ static format(input, options) {
246
+ const r = _PersonFamilyName.tryParse(input);
247
+ if (r) return r.value;
248
+ if (options?.fallbackToTrimmedInputWhenInvalid && input != null && input.trim() !== "") {
249
+ return input.trim();
250
+ }
251
+ return null;
252
+ }
253
+ static normalize(input, options) {
254
+ return _PersonFamilyName.format(input, options);
255
+ }
256
+ static isNormalized(input) {
257
+ return input != null && _PersonFamilyName.normalize(input) === input;
258
+ }
259
+ toNormalizedString() {
260
+ return this.value;
261
+ }
262
+ toString() {
263
+ return this.value;
264
+ }
265
+ equals(other) {
266
+ return other != null && this.value === other.value;
267
+ }
268
+ compareTo(other) {
269
+ if (other == null) return 1;
270
+ return this.value < other.value ? -1 : this.value > other.value ? 1 : 0;
271
+ }
272
+ };
273
+
274
+ // src/person/person-full-name.ts
275
+ var MAX_INPUT_LENGTH3 = 500;
276
+ var PersonFullName = class _PersonFullName {
277
+ static typeInfo = Object.freeze({
278
+ englishName: "Full Name",
279
+ localizedName: "Fullst\xE4ndigt namn",
280
+ emoji: "\u{1F4C7}",
281
+ sources: Object.freeze([
282
+ "https://skatteverket.se/privat/folkbokforing/namn.4.18e1b10334ebe8bc80004083.html",
283
+ "https://www.riksdagen.se/sv/dokument-och-lagar/dokument/svensk-forfattningssamling/lag-20161013-om-personnamn_sfs-2016-1013/"
284
+ ])
285
+ });
286
+ givenName;
287
+ familyName;
288
+ value;
289
+ get preferredName() {
290
+ return this.givenName.preferredName;
291
+ }
292
+ constructor(given, family, value) {
293
+ this.givenName = given;
294
+ this.familyName = family;
295
+ this.value = value;
296
+ }
297
+ static create(givenName, familyName) {
298
+ return new _PersonFullName(givenName, familyName, `${givenName.value} ${familyName.value}`);
299
+ }
300
+ static tryParse(input, options) {
301
+ const collapsed = collapseWhitespace2(input);
302
+ if (collapsed.length === 0 || collapsed.length > MAX_INPUT_LENGTH3) return null;
303
+ const tokens = collapsed.split(" ").filter((t) => t !== "");
304
+ if (tokens.length < 2) return null;
305
+ const givenPart = tokens.slice(0, tokens.length - 1).join(" ");
306
+ const given = PersonGivenName.tryParse(givenPart, options);
307
+ if (given === null) return null;
308
+ const family = PersonFamilyName.tryParse(tokens[tokens.length - 1]);
309
+ if (family === null) return null;
310
+ return new _PersonFullName(given, family, `${given.value} ${family.value}`);
311
+ }
312
+ static parse(input, options) {
313
+ const r = _PersonFullName.tryParse(input, options);
314
+ if (r === null) {
315
+ throw new Error("Invalid full name. Must contain at least given name(s) and a family name.");
316
+ }
317
+ return r;
318
+ }
319
+ static isValid(input) {
320
+ return _PersonFullName.tryParse(input) !== null;
321
+ }
322
+ static format(input, options) {
323
+ const r = _PersonFullName.tryParse(input);
324
+ if (r) return r.value;
325
+ if (options?.fallbackToTrimmedInputWhenInvalid && input != null && input.trim() !== "") {
326
+ return input.trim();
327
+ }
328
+ return null;
329
+ }
330
+ static normalize(input, options) {
331
+ return _PersonFullName.format(input, options);
332
+ }
333
+ static isNormalized(input) {
334
+ return input != null && _PersonFullName.normalize(input) === input;
335
+ }
336
+ withPreferredName(preferredName) {
337
+ const given = this.givenName.withPreferredName(preferredName);
338
+ return new _PersonFullName(given, this.familyName, this.value);
339
+ }
340
+ toNormalizedString() {
341
+ return this.value;
342
+ }
343
+ toString() {
344
+ return this.value;
345
+ }
346
+ equals(other) {
347
+ return other != null && this.value === other.value;
348
+ }
349
+ compareTo(other) {
350
+ if (other == null) return 1;
351
+ return this.value < other.value ? -1 : this.value > other.value ? 1 : 0;
352
+ }
353
+ };
354
+
355
+ // src/internal/clock.ts
356
+ var systemClock = {
357
+ now: () => /* @__PURE__ */ new Date()
358
+ };
359
+
360
+ // src/person/person-age.ts
361
+ var MAX_YEARS = 200;
362
+ var DAYS_PER_YEAR = 365;
363
+ var DAYS_PER_MONTH = 30;
364
+ var MAX_TOTAL_DAYS = MAX_YEARS * DAYS_PER_YEAR;
365
+ var YEARS_PATTERN = /^\s*(\d+(?:[.,]\d+)?)\s*(?:år|years?)?\s*$/iu;
366
+ var MONTHS_PATTERN = /^\s*(\d+)\s+(?:månader?|månad|months?)\s*$/iu;
367
+ var DAYS_PATTERN = /^\s*(\d+)\s+(?:dagar?|dag|days?)\s*$/iu;
368
+ var PersonAge = class _PersonAge {
369
+ static typeInfo = Object.freeze({
370
+ englishName: "Age",
371
+ localizedName: "\xC5lder",
372
+ emoji: "\u{1F382}",
373
+ sources: Object.freeze([
374
+ "https://www.riksdagen.se/sv/dokument-och-lagar/dokument/svensk-forfattningssamling/foraldrabalk-1949381_sfs-1949-381/",
375
+ "https://www.riksdagen.se/sv/dokument-och-lagar/dokument/svensk-forfattningssamling/brottsbalk-1962700_sfs-1962-700/"
376
+ ])
377
+ });
378
+ years;
379
+ totalMonths;
380
+ totalDays;
381
+ get isOfSwedishLegalAge() {
382
+ return this.years >= 18;
383
+ }
384
+ get isSwedishCriminallyResponsible() {
385
+ return this.years >= 15;
386
+ }
387
+ get isOfSwedishRetirementAge() {
388
+ return this.years >= 65;
389
+ }
390
+ constructor(years, totalMonths, totalDays) {
391
+ this.years = years;
392
+ this.totalMonths = totalMonths;
393
+ this.totalDays = totalDays;
394
+ }
395
+ static tryParse(input) {
396
+ if (input == null || input.trim() === "") return null;
397
+ const sanitized = input.trim();
398
+ if (sanitized.length > 50) return null;
399
+ let m = DAYS_PATTERN.exec(sanitized);
400
+ if (m) {
401
+ const d = parseInt(m[1], 10);
402
+ return tryFromDays(d);
403
+ }
404
+ m = MONTHS_PATTERN.exec(sanitized);
405
+ if (m) {
406
+ const months = parseInt(m[1], 10);
407
+ return tryFromMonths(months);
408
+ }
409
+ m = YEARS_PATTERN.exec(sanitized);
410
+ if (m) {
411
+ const value = parseFloat(m[1].replace(",", "."));
412
+ if (!Number.isFinite(value) || value < 0) return null;
413
+ const intYears = Math.trunc(value);
414
+ if (value === intYears) return tryFromYears(intYears);
415
+ return tryFromDays(Math.trunc(value * DAYS_PER_YEAR));
416
+ }
417
+ return null;
418
+ }
419
+ static parse(input) {
420
+ const r = _PersonAge.tryParse(input);
421
+ if (r === null) throw new Error("Invalid person age.");
422
+ return r;
423
+ }
424
+ static isValid(input) {
425
+ return _PersonAge.tryParse(input) !== null;
426
+ }
427
+ static fromYears(years) {
428
+ if (years < 0 || years > MAX_YEARS || !Number.isInteger(years)) {
429
+ throw new RangeError(`Years must be between 0 and ${MAX_YEARS}.`);
430
+ }
431
+ return new _PersonAge(years, years * 12, years * DAYS_PER_YEAR);
432
+ }
433
+ static fromMonths(months) {
434
+ if (months < 0 || months > MAX_YEARS * 12 || !Number.isInteger(months)) {
435
+ throw new RangeError(`Months must be between 0 and ${MAX_YEARS * 12}.`);
436
+ }
437
+ return new _PersonAge(Math.trunc(months / 12), months, months * DAYS_PER_MONTH);
438
+ }
439
+ static fromDays(days) {
440
+ if (days < 0 || days > MAX_TOTAL_DAYS || !Number.isInteger(days)) {
441
+ throw new RangeError(`Days must be between 0 and ${MAX_TOTAL_DAYS}.`);
442
+ }
443
+ return new _PersonAge(Math.trunc(days / DAYS_PER_YEAR), Math.trunc(days / DAYS_PER_MONTH), days);
444
+ }
445
+ /**
446
+ * Build a {@link PersonAge} from a birth date and an optional reference date.
447
+ * `birthDate` and `referenceDate` are interpreted as UTC midnights of the date
448
+ * portion of the supplied {@link Date} values.
449
+ */
450
+ static fromBirthDate(birthDate, options) {
451
+ const ref = options?.referenceDate ?? options?.clock?.now() ?? systemClock.now();
452
+ const birth = new Date(
453
+ Date.UTC(birthDate.getUTCFullYear(), birthDate.getUTCMonth(), birthDate.getUTCDate())
454
+ );
455
+ const today = new Date(Date.UTC(ref.getUTCFullYear(), ref.getUTCMonth(), ref.getUTCDate()));
456
+ if (birth > today)
457
+ throw new RangeError("Birth date cannot be in the future relative to the reference date.");
458
+ const totalDays = Math.floor((today.getTime() - birth.getTime()) / 864e5);
459
+ let years = today.getUTCFullYear() - birth.getUTCFullYear();
460
+ if (today.getUTCMonth() < birth.getUTCMonth() || today.getUTCMonth() === birth.getUTCMonth() && today.getUTCDate() < birth.getUTCDate()) {
461
+ years--;
462
+ }
463
+ let monthDate = new Date(
464
+ Date.UTC(birth.getUTCFullYear() + years, birth.getUTCMonth(), birth.getUTCDate())
465
+ );
466
+ let months = 0;
467
+ while (true) {
468
+ const next = new Date(monthDate);
469
+ next.setUTCMonth(next.getUTCMonth() + 1);
470
+ if (next > today) break;
471
+ monthDate = next;
472
+ months++;
473
+ }
474
+ return new _PersonAge(years, years * 12 + months, totalDays);
475
+ }
476
+ static format(input, options) {
477
+ const r = _PersonAge.tryParse(input);
478
+ if (r) return r.toString();
479
+ if (options?.fallbackToTrimmedInputWhenInvalid && input != null && input.trim() !== "") {
480
+ return input.trim();
481
+ }
482
+ return null;
483
+ }
484
+ static normalize(input, options) {
485
+ const r = _PersonAge.tryParse(input);
486
+ if (r) return r.toNormalizedString();
487
+ if (options?.fallbackToTrimmedInputWhenInvalid && input != null) {
488
+ const t = input.trim();
489
+ return t.length > 0 ? t : null;
490
+ }
491
+ return null;
492
+ }
493
+ static isNormalized(input) {
494
+ return input != null && _PersonAge.normalize(input) === input;
495
+ }
496
+ toNormalizedString() {
497
+ return String(this.years);
498
+ }
499
+ toString() {
500
+ return this.years >= 1 ? `${this.years} \xE5r` : `${this.totalMonths} m\xE5nader`;
501
+ }
502
+ equals(other) {
503
+ return other != null && this.totalDays === other.totalDays;
504
+ }
505
+ compareTo(other) {
506
+ if (other == null) return 1;
507
+ return this.totalDays - other.totalDays;
508
+ }
509
+ };
510
+ function tryFromYears(years) {
511
+ if (years < 0 || years > MAX_YEARS) return null;
512
+ return PersonAge.fromYears(years);
513
+ }
514
+ function tryFromMonths(months) {
515
+ if (months < 0 || months > MAX_YEARS * 12) return null;
516
+ if (months * DAYS_PER_MONTH > MAX_TOTAL_DAYS) return null;
517
+ return PersonAge.fromMonths(months);
518
+ }
519
+ function tryFromDays(days) {
520
+ if (days < 0 || days > MAX_TOTAL_DAYS) return null;
521
+ return PersonAge.fromDays(days);
522
+ }
523
+
524
+ // src/person/person-masking.ts
525
+ var MaskedNamePart = "***";
526
+ function maskGivenName(value, options) {
527
+ if (options?.useInitials) return value.names.map(toInitial).join(" ");
528
+ return value.names.map(() => MaskedNamePart).join(" ");
529
+ }
530
+ function maskFamilyName(value, options) {
531
+ if (options?.useInitials) return toInitial(value.value);
532
+ return MaskedNamePart;
533
+ }
534
+ function maskFullName(value, options) {
535
+ const family = maskFamilyName(value.familyName, options);
536
+ if (options?.showGivenName) return `${value.givenName.value} ${family}`;
537
+ return `${maskGivenName(value.givenName, options)} ${family}`;
538
+ }
539
+ function maskPersonAge(value) {
540
+ if (value.years >= 1) return `${"*".repeat(String(value.years).length)} \xE5r`;
541
+ return `${"*".repeat(String(value.totalMonths).length)} m\xE5nader`;
542
+ }
543
+ function toInitial(value) {
544
+ return `${value[0]}.`;
545
+ }
546
+
547
+ // src/text-scanning/text-candidate-category.ts
548
+ var TextCandidateCategory = {
549
+ PersonalIdentifier: "PersonalIdentifier"};
550
+
551
+ // src/text-scanning/text-candidate.ts
552
+ var TextCandidate = class {
553
+ /** Zero-based start position in the scanned text. */
554
+ startIndex;
555
+ /** Number of characters in the original matched span. */
556
+ length;
557
+ /** The raw substring from the input text that was matched. */
558
+ originalText;
559
+ /**
560
+ * Short type name, e.g. `EmailAddress` or `SwedishPersonalIdentityNumber`.
561
+ */
562
+ typeName;
563
+ /** Broad category of the matched type. */
564
+ category;
565
+ /** Machine-comparable canonical form of the matched value. */
566
+ normalizedForm;
567
+ /** Human-readable display form of the matched value. */
568
+ formattedForm;
569
+ /**
570
+ * Display form with sensitive content masked (e.g. `990807-****`).
571
+ * Produced by the type's `toMaskedString()` helper.
572
+ */
573
+ maskedForm;
574
+ /** Heuristic confidence level. */
575
+ confidence;
576
+ /** The successfully parsed instance of the matched type. */
577
+ value;
578
+ constructor(opts) {
579
+ this.startIndex = opts.startIndex;
580
+ this.length = opts.length;
581
+ this.originalText = opts.originalText;
582
+ this.typeName = opts.typeName;
583
+ this.category = opts.category;
584
+ this.normalizedForm = opts.normalizedForm;
585
+ this.formattedForm = opts.formattedForm;
586
+ this.maskedForm = opts.maskedForm;
587
+ this.confidence = opts.confidence;
588
+ this.value = opts.value;
589
+ }
590
+ /** Exclusive end position (`startIndex + length`). */
591
+ get endIndex() {
592
+ return this.startIndex + this.length;
593
+ }
594
+ /** Returns `true` if this candidate's span overlaps with `other`. */
595
+ overlaps(other) {
596
+ return this.startIndex < other.endIndex && other.startIndex < this.endIndex;
597
+ }
598
+ /** Returns `true` if this candidate's span fully contains `other`. */
599
+ contains(other) {
600
+ return this.startIndex <= other.startIndex && this.endIndex >= other.endIndex;
601
+ }
602
+ };
603
+
604
+ // src/text-scanning/text-match-confidence.ts
605
+ var TextMatchConfidence = {
606
+ /**
607
+ * Strong match with checksum or format-specific validation (e.g. a personal
608
+ * identity number with a valid Luhn check digit and plausible date, or an
609
+ * IBAN with valid MOD-97).
610
+ */
611
+ High: 2
612
+ };
613
+
614
+ // src/validation/validation-error-reason.ts
615
+ var ValidationErrorReason = {
616
+ // --- Common ---
617
+ InputIsEmpty: "InputIsEmpty",
618
+ InputTooLong: "InputTooLong",
619
+ InvalidFormat: "InvalidFormat"};
620
+
621
+ // src/validation/validation-issue.ts
622
+ var ValidationIssue = class {
623
+ reason;
624
+ englishDescription;
625
+ localizedDescription;
626
+ constructor(reason, englishDescription, localizedDescription) {
627
+ this.reason = reason;
628
+ this.englishDescription = englishDescription;
629
+ this.localizedDescription = localizedDescription;
630
+ }
631
+ /**
632
+ * Returns {@link localizedDescription} when
633
+ * {@link PrimitivesDefaults.useLocalizedDisplayNames} is `true`, otherwise
634
+ * {@link englishDescription}.
635
+ */
636
+ get description() {
637
+ return PrimitivesDefaults.useLocalizedDisplayNames ? this.localizedDescription : this.englishDescription;
638
+ }
639
+ };
640
+
641
+ // src/validation/validation-result.ts
642
+ var ValidationResult = class {
643
+ rawInput;
644
+ isValid;
645
+ issues;
646
+ /** @internal — use `validResult` / `invalidResult` factories. */
647
+ constructor(rawInput, isValid, issues) {
648
+ this.rawInput = rawInput ?? null;
649
+ this.isValid = isValid;
650
+ this.issues = Object.freeze([...issues]);
651
+ }
652
+ };
653
+ function validResult(rawInput) {
654
+ return new ValidationResult(rawInput, true, []);
655
+ }
656
+ function invalidResult(rawInput, reasonOrIssues, englishDescription, localizedDescription) {
657
+ if (typeof reasonOrIssues === "string") {
658
+ if (englishDescription === void 0 || localizedDescription === void 0) {
659
+ throw new Error("invalidResult requires both english and localized descriptions");
660
+ }
661
+ return new ValidationResult(rawInput, false, [
662
+ new ValidationIssue(reasonOrIssues, englishDescription, localizedDescription)
663
+ ]);
664
+ }
665
+ return new ValidationResult(rawInput, false, reasonOrIssues);
666
+ }
667
+
668
+ // src/internal/luhn.ts
669
+ function luhnIsValid(digits) {
670
+ if (!digits) return false;
671
+ let sum = 0;
672
+ const len = digits.length;
673
+ for (let i = 0; i < len; i++) {
674
+ const code = digits.charCodeAt(i);
675
+ if (code < 48 || code > 57) return false;
676
+ let d = code - 48;
677
+ if ((len - i) % 2 === 0) {
678
+ d *= 2;
679
+ if (d > 9) d -= 9;
680
+ }
681
+ sum += d;
682
+ }
683
+ return sum % 10 === 0;
684
+ }
685
+
686
+ // src/person/personnummer-parser.ts
687
+ var defaultClock = systemClock;
688
+ var TWELVE = /^(\d{4})(\d{2})(\d{2})(\d{3})(\d)$/;
689
+ var TEN = /^(\d{2})(\d{2})(\d{2})(\d{3})(\d)$/;
690
+ var TEN_WITH_SEP = /^(\d{2})(\d{2})(\d{2})([-+])(\d{3})(\d)$/;
691
+ var TWELVE_WITH_SEP = /^(\d{4})(\d{2})(\d{2})([-+])(\d{3})(\d)$/;
692
+ function parsePin(input, clock = defaultClock) {
693
+ if (!input) return null;
694
+ const cleaned = input.trim();
695
+ if (cleaned.length === 0) return null;
696
+ let year, month, day;
697
+ let individual, check;
698
+ let hadPlus = false;
699
+ let isTwelve = false;
700
+ let m = TWELVE.exec(cleaned);
701
+ if (m) {
702
+ year = +m[1];
703
+ month = +m[2];
704
+ day = +m[3];
705
+ individual = m[4];
706
+ check = m[5];
707
+ isTwelve = true;
708
+ } else if (m = TEN.exec(cleaned)) {
709
+ const yy = +m[1];
710
+ year = inferCenturyForTenDigit(yy, false, clock);
711
+ month = +m[2];
712
+ day = +m[3];
713
+ individual = m[4];
714
+ check = m[5];
715
+ } else if (m = TEN_WITH_SEP.exec(cleaned)) {
716
+ const yy = +m[1];
717
+ hadPlus = m[4] === "+";
718
+ year = inferCenturyForTenDigit(yy, hadPlus, clock);
719
+ month = +m[2];
720
+ day = +m[3];
721
+ individual = m[5];
722
+ check = m[6];
723
+ } else if (m = TWELVE_WITH_SEP.exec(cleaned)) {
724
+ year = +m[1];
725
+ month = +m[2];
726
+ day = +m[3];
727
+ individual = m[5];
728
+ check = m[6];
729
+ if (m[4] === "+") return null;
730
+ } else {
731
+ return null;
732
+ }
733
+ if (month < 1 || month > 12) return null;
734
+ const isCoordination = day >= 60 && day <= 91;
735
+ let realDay;
736
+ let kind;
737
+ if (isCoordination) {
738
+ kind = "coordination";
739
+ realDay = day === 60 ? 0 : day - 60;
740
+ if (realDay !== 0 && !isValidDay(year, month, realDay)) return null;
741
+ } else {
742
+ kind = "personal";
743
+ if (!isValidDay(year, month, day)) return null;
744
+ realDay = day;
745
+ }
746
+ const luhnInput = String(year % 100).padStart(2, "0") + String(month).padStart(2, "0") + String(day).padStart(2, "0") + individual + check;
747
+ if (!luhnIsValid(luhnInput)) return null;
748
+ if (isTwelve && (year < 1800 || year > 2200)) return null;
749
+ return {
750
+ kind,
751
+ year,
752
+ month,
753
+ realDay,
754
+ individual,
755
+ checkDigit: check,
756
+ hadPlusSeparator: hadPlus
757
+ };
758
+ }
759
+ function isValidDay(year, month, day) {
760
+ if (day < 1) return false;
761
+ const dim = daysInMonth(year, month);
762
+ return day <= dim;
763
+ }
764
+ function daysInMonth(year, month) {
765
+ if (month === 2) {
766
+ const leap = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
767
+ return leap ? 29 : 28;
768
+ }
769
+ if ([4, 6, 9, 11].includes(month)) return 30;
770
+ return 31;
771
+ }
772
+ function inferCenturyForTenDigit(yy, plusSeparator, clock) {
773
+ const now = clock.now();
774
+ const currentYear = now.getUTCFullYear();
775
+ const currentCentury = Math.floor(currentYear / 100);
776
+ const candidate = currentCentury * 100 + yy;
777
+ let year = candidate;
778
+ if (year > currentYear) year -= 100;
779
+ if (plusSeparator) year -= 100;
780
+ return year;
781
+ }
782
+ function pinTo12Digit(p) {
783
+ const day = p.kind === "coordination" ? p.realDay === 0 ? 60 : p.realDay + 60 : p.realDay;
784
+ return String(p.year).padStart(4, "0") + String(p.month).padStart(2, "0") + String(day).padStart(2, "0") + p.individual + p.checkDigit;
785
+ }
786
+ function pinTo10Digit(p, clock = defaultClock) {
787
+ const day = p.kind === "coordination" ? p.realDay === 0 ? 60 : p.realDay + 60 : p.realDay;
788
+ const yy = String(p.year % 100).padStart(2, "0");
789
+ const sep = ageInYears(p, clock) >= 100 ? "+" : "-";
790
+ return yy + String(p.month).padStart(2, "0") + String(day).padStart(2, "0") + sep + p.individual + p.checkDigit;
791
+ }
792
+ function ageInYears(p, clock) {
793
+ if (p.kind === "coordination" && p.realDay === 0) return 0;
794
+ const now = clock.now();
795
+ const day = p.kind === "coordination" ? p.realDay : p.realDay;
796
+ const birth = new Date(Date.UTC(p.year, p.month - 1, day || 1));
797
+ const ms = now.getTime() - birth.getTime();
798
+ return Math.floor(ms / (365.25 * 24 * 3600 * 1e3));
799
+ }
800
+ function pinGender(p) {
801
+ const d = parseInt(p.individual.charAt(p.individual.length - 1), 10);
802
+ return d % 2 === 0 ? "female" : "male";
803
+ }
804
+ function pinDateOfBirth(p) {
805
+ if (p.kind === "coordination" && p.realDay === 0) return null;
806
+ return new Date(Date.UTC(p.year, p.month - 1, p.realDay));
807
+ }
808
+ function pinAgeInYears(p, clock = defaultClock) {
809
+ if (p.kind === "coordination" && p.realDay === 0) return null;
810
+ return ageInYears(p, clock);
811
+ }
812
+
813
+ // src/person/swedish-personal-identity-number.ts
814
+ var MAX_INPUT_LENGTH4 = 20;
815
+ var SCAN_PATTERN = /(?<!\d)(\d{6,8})([-+])(\d{4})(?!\d)/g;
816
+ var SwedishPersonalIdentityNumber = class _SwedishPersonalIdentityNumber {
817
+ static typeInfo = Object.freeze({
818
+ englishName: "Personal Identity Number",
819
+ localizedName: "Personnummer",
820
+ emoji: "\u{1FAAA}",
821
+ sources: Object.freeze([
822
+ "https://skatteverket.se/privat/folkbokforing/personnummer.4.3810a01c150939e893f18c29.html",
823
+ "https://sv.wikipedia.org/wiki/Personnummer_i_Sverige",
824
+ "https://en.wikipedia.org/wiki/Luhn_algorithm"
825
+ ])
826
+ });
827
+ _pin;
828
+ _clock;
829
+ constructor(pin, clock) {
830
+ this._pin = pin;
831
+ this._clock = clock;
832
+ }
833
+ get formatted() {
834
+ return pinTo10Digit(this._pin, this._clock);
835
+ }
836
+ get value() {
837
+ return pinTo12Digit(this._pin);
838
+ }
839
+ get dateOfBirthHint() {
840
+ const d = pinDateOfBirth(this._pin);
841
+ if (d === null) throw new Error("Date of birth is unknown.");
842
+ return d;
843
+ }
844
+ get ageHint() {
845
+ const a = pinAgeInYears(this._pin, this._clock);
846
+ if (a === null) throw new Error("Age is unknown.");
847
+ return a;
848
+ }
849
+ get genderHint() {
850
+ return pinGender(this._pin);
851
+ }
852
+ static tryParse(input, options) {
853
+ if (input == null || input.trim() === "") return null;
854
+ const sanitized = sanitizeInput(input).trim();
855
+ if (sanitized.length === 0 || sanitized.length > MAX_INPUT_LENGTH4) return null;
856
+ const clock = options?.clock ?? systemClock;
857
+ const pin = parsePin(sanitized, clock);
858
+ if (pin === null) return null;
859
+ if (pin.kind !== "personal") return null;
860
+ return new _SwedishPersonalIdentityNumber(pin, clock);
861
+ }
862
+ static parse(input, options) {
863
+ const r = _SwedishPersonalIdentityNumber.tryParse(input, options);
864
+ if (r === null) throw new Error("Invalid Swedish personal identity number.");
865
+ return r;
866
+ }
867
+ static isValid(input) {
868
+ return _SwedishPersonalIdentityNumber.tryParse(input) !== null;
869
+ }
870
+ static format(input, options) {
871
+ const r = _SwedishPersonalIdentityNumber.tryParse(input, options);
872
+ if (r) return r.formatted;
873
+ if (options?.fallbackToTrimmedInputWhenInvalid && input != null && input.trim() !== "") {
874
+ return input.trim();
875
+ }
876
+ return null;
877
+ }
878
+ static normalize(input, options) {
879
+ const r = _SwedishPersonalIdentityNumber.tryParse(input, options);
880
+ if (r) return r.value;
881
+ if (options?.fallbackToTrimmedInputWhenInvalid && input != null) {
882
+ const t = input.trim();
883
+ return t.length > 0 ? t : null;
884
+ }
885
+ return null;
886
+ }
887
+ static isNormalized(input) {
888
+ return input != null && _SwedishPersonalIdentityNumber.normalize(input) === input;
889
+ }
890
+ static validate(input) {
891
+ if (input == null || input.trim() === "") {
892
+ return invalidResult(
893
+ input,
894
+ ValidationErrorReason.InputIsEmpty,
895
+ "Input is empty or whitespace.",
896
+ "V\xE4rdet \xE4r tomt."
897
+ );
898
+ }
899
+ const sanitized = sanitizeInput(input).trim();
900
+ if (sanitized.length > MAX_INPUT_LENGTH4) {
901
+ return invalidResult(
902
+ input,
903
+ ValidationErrorReason.InputTooLong,
904
+ "Input contains too many characters.",
905
+ "V\xE4rdet inneh\xE5ller f\xF6r m\xE5nga tecken."
906
+ );
907
+ }
908
+ const pin = parsePin(sanitized);
909
+ if (pin === null || pin.kind !== "personal") {
910
+ return invalidResult(
911
+ input,
912
+ ValidationErrorReason.InvalidFormat,
913
+ "Invalid personal identity number format.",
914
+ "Ogiltigt format f\xF6r personnummer."
915
+ );
916
+ }
917
+ return validResult(input);
918
+ }
919
+ toNormalizedString() {
920
+ return this.value;
921
+ }
922
+ toString() {
923
+ return this.formatted;
924
+ }
925
+ to10DigitString() {
926
+ return this.formatted;
927
+ }
928
+ to12DigitString() {
929
+ return this.value;
930
+ }
931
+ static findCandidatesInText(text) {
932
+ if (!text) return [];
933
+ const out = [];
934
+ SCAN_PATTERN.lastIndex = 0;
935
+ let m;
936
+ while ((m = SCAN_PATTERN.exec(text)) !== null) {
937
+ const pin = _SwedishPersonalIdentityNumber.tryParse(m[0]);
938
+ if (!pin) continue;
939
+ out.push(
940
+ new TextCandidate({
941
+ startIndex: m.index,
942
+ length: m[0].length,
943
+ originalText: m[0],
944
+ typeName: "SwedishPersonalIdentityNumber",
945
+ category: TextCandidateCategory.PersonalIdentifier,
946
+ normalizedForm: pin.toNormalizedString(),
947
+ formattedForm: pin.toString(),
948
+ maskedForm: maskPersonalIdentityNumber(pin),
949
+ confidence: TextMatchConfidence.High,
950
+ value: pin
951
+ })
952
+ );
953
+ }
954
+ return out;
955
+ }
956
+ equals(other) {
957
+ return other != null && this.value === other.value;
958
+ }
959
+ compareTo(other) {
960
+ if (other == null) return 1;
961
+ return this.value < other.value ? -1 : this.value > other.value ? 1 : 0;
962
+ }
963
+ };
964
+ function maskPersonalIdentityNumber(p, options) {
965
+ const f = p.formatted;
966
+ if (options?.maskBirthDate) return "******-****";
967
+ return f.slice(0, f.length - 4) + "****";
968
+ }
969
+
970
+ // src/person/swedish-coordination-number.ts
971
+ var MAX_INPUT_LENGTH5 = 20;
972
+ var SCAN_PATTERN2 = /(?<!\d)(\d{6,8})([-+])(\d{4})(?!\d)/g;
973
+ var SwedishCoordinationNumber = class _SwedishCoordinationNumber {
974
+ static typeInfo = Object.freeze({
975
+ englishName: "Coordination Number",
976
+ localizedName: "Samordningsnummer",
977
+ emoji: "\u{1F194}",
978
+ sources: Object.freeze([
979
+ "https://skatteverket.se/privat/folkbokforing/samordningsnummer.4.5c281c7015abecc2e201130b.html",
980
+ "https://sv.wikipedia.org/wiki/Samordningsnummer"
981
+ ])
982
+ });
983
+ _pin;
984
+ _clock;
985
+ constructor(pin, clock) {
986
+ this._pin = pin;
987
+ this._clock = clock;
988
+ }
989
+ get formatted() {
990
+ return pinTo10Digit(this._pin, this._clock);
991
+ }
992
+ get value() {
993
+ return pinTo12Digit(this._pin);
994
+ }
995
+ get realDay() {
996
+ return this._pin.realDay;
997
+ }
998
+ get dateOfBirthHint() {
999
+ return pinDateOfBirth(this._pin);
1000
+ }
1001
+ get ageHint() {
1002
+ return pinAgeInYears(this._pin, this._clock);
1003
+ }
1004
+ get genderHint() {
1005
+ return pinGender(this._pin);
1006
+ }
1007
+ static tryParse(input, options) {
1008
+ if (input == null || input.trim() === "") return null;
1009
+ const sanitized = sanitizeInput(input).trim();
1010
+ if (sanitized.length === 0 || sanitized.length > MAX_INPUT_LENGTH5) return null;
1011
+ const clock = options?.clock ?? systemClock;
1012
+ const pin = parsePin(sanitized, clock);
1013
+ if (pin === null) return null;
1014
+ if (pin.kind !== "coordination") return null;
1015
+ return new _SwedishCoordinationNumber(pin, clock);
1016
+ }
1017
+ static parse(input, options) {
1018
+ const r = _SwedishCoordinationNumber.tryParse(input, options);
1019
+ if (r === null) throw new Error("Invalid Swedish coordination number.");
1020
+ return r;
1021
+ }
1022
+ static isValid(input) {
1023
+ return _SwedishCoordinationNumber.tryParse(input) !== null;
1024
+ }
1025
+ static format(input, options) {
1026
+ const r = _SwedishCoordinationNumber.tryParse(input, options);
1027
+ if (r) return r.formatted;
1028
+ if (options?.fallbackToTrimmedInputWhenInvalid && input != null && input.trim() !== "") {
1029
+ return input.trim();
1030
+ }
1031
+ return null;
1032
+ }
1033
+ static normalize(input, options) {
1034
+ const r = _SwedishCoordinationNumber.tryParse(input, options);
1035
+ if (r) return r.value;
1036
+ if (options?.fallbackToTrimmedInputWhenInvalid && input != null) {
1037
+ const t = input.trim();
1038
+ return t.length > 0 ? t : null;
1039
+ }
1040
+ return null;
1041
+ }
1042
+ static isNormalized(input) {
1043
+ return input != null && _SwedishCoordinationNumber.normalize(input) === input;
1044
+ }
1045
+ static validate(input) {
1046
+ if (input == null || input.trim() === "") {
1047
+ return invalidResult(
1048
+ input,
1049
+ ValidationErrorReason.InputIsEmpty,
1050
+ "Input is empty or whitespace.",
1051
+ "V\xE4rdet \xE4r tomt."
1052
+ );
1053
+ }
1054
+ const sanitized = sanitizeInput(input).trim();
1055
+ if (sanitized.length > MAX_INPUT_LENGTH5) {
1056
+ return invalidResult(
1057
+ input,
1058
+ ValidationErrorReason.InputTooLong,
1059
+ "Input contains too many characters.",
1060
+ "V\xE4rdet inneh\xE5ller f\xF6r m\xE5nga tecken."
1061
+ );
1062
+ }
1063
+ const pin = parsePin(sanitized);
1064
+ if (pin === null || pin.kind !== "coordination") {
1065
+ return invalidResult(
1066
+ input,
1067
+ ValidationErrorReason.InvalidFormat,
1068
+ "Invalid coordination number format.",
1069
+ "Ogiltigt format f\xF6r samordningsnummer."
1070
+ );
1071
+ }
1072
+ return validResult(input);
1073
+ }
1074
+ toNormalizedString() {
1075
+ return this.value;
1076
+ }
1077
+ toString() {
1078
+ return this.formatted;
1079
+ }
1080
+ to10DigitString() {
1081
+ return this.formatted;
1082
+ }
1083
+ to12DigitString() {
1084
+ return this.value;
1085
+ }
1086
+ static findCandidatesInText(text) {
1087
+ if (!text) return [];
1088
+ const out = [];
1089
+ SCAN_PATTERN2.lastIndex = 0;
1090
+ let m;
1091
+ while ((m = SCAN_PATTERN2.exec(text)) !== null) {
1092
+ const cn = _SwedishCoordinationNumber.tryParse(m[0]);
1093
+ if (!cn) continue;
1094
+ out.push(
1095
+ new TextCandidate({
1096
+ startIndex: m.index,
1097
+ length: m[0].length,
1098
+ originalText: m[0],
1099
+ typeName: "SwedishCoordinationNumber",
1100
+ category: TextCandidateCategory.PersonalIdentifier,
1101
+ normalizedForm: cn.toNormalizedString(),
1102
+ formattedForm: cn.toString(),
1103
+ maskedForm: maskCoordinationNumber(cn),
1104
+ confidence: TextMatchConfidence.High,
1105
+ value: cn
1106
+ })
1107
+ );
1108
+ }
1109
+ return out;
1110
+ }
1111
+ equals(other) {
1112
+ return other != null && this.value === other.value;
1113
+ }
1114
+ compareTo(other) {
1115
+ if (other == null) return 1;
1116
+ return this.value < other.value ? -1 : this.value > other.value ? 1 : 0;
1117
+ }
1118
+ };
1119
+ function maskCoordinationNumber(c, options) {
1120
+ const f = c.formatted;
1121
+ if (options?.maskBirthDate) return "******-****";
1122
+ return f.slice(0, f.length - 4) + "****";
1123
+ }
1124
+
1125
+ exports.PersonAge = PersonAge;
1126
+ exports.PersonFamilyName = PersonFamilyName;
1127
+ exports.PersonFullName = PersonFullName;
1128
+ exports.PersonGivenName = PersonGivenName;
1129
+ exports.SwedishCoordinationNumber = SwedishCoordinationNumber;
1130
+ exports.SwedishPersonalIdentityNumber = SwedishPersonalIdentityNumber;
1131
+ exports.maskCoordinationNumber = maskCoordinationNumber;
1132
+ exports.maskFamilyName = maskFamilyName;
1133
+ exports.maskFullName = maskFullName;
1134
+ exports.maskGivenName = maskGivenName;
1135
+ exports.maskPersonAge = maskPersonAge;
1136
+ exports.maskPersonalIdentityNumber = maskPersonalIdentityNumber;
1137
+ exports.parsePin = parsePin;
1138
+ exports.pinAgeInYears = pinAgeInYears;
1139
+ exports.pinDateOfBirth = pinDateOfBirth;
1140
+ exports.pinGender = pinGender;
1141
+ exports.pinTo10Digit = pinTo10Digit;
1142
+ exports.pinTo12Digit = pinTo12Digit;
1143
+ //# sourceMappingURL=index.cjs.map
1144
+ //# sourceMappingURL=index.cjs.map