@budiauktioner/buildi-primitives 0.2.1 → 0.3.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.
- package/CHANGELOG.md +44 -0
- package/PARITY.md +7 -7
- package/README.md +18 -1
- package/dist/cjs/contact/phone-number-test-data.js +1 -1
- package/dist/cjs/contact/phone-number-test-data.js.map +1 -1
- package/dist/cjs/contact/phone-number.js +36 -14
- package/dist/cjs/contact/phone-number.js.map +2 -2
- package/dist/cjs/organization/swedish-organization-number.js.map +2 -2
- package/dist/cjs/register-default-text-scanners.js +2 -0
- package/dist/cjs/register-default-text-scanners.js.map +2 -2
- package/dist/cjs/sample-data/index.js +18 -1
- package/dist/cjs/sample-data/index.js.map +2 -2
- package/dist/cjs/text-scanning/text-scan-result.js +3 -0
- package/dist/cjs/text-scanning/text-scan-result.js.map +2 -2
- package/dist/cjs/validation/validation-error-reason.js +6 -1
- package/dist/cjs/validation/validation-error-reason.js.map +2 -2
- package/dist/cjs/vehicle/index.js +4 -0
- package/dist/cjs/vehicle/index.js.map +2 -2
- package/dist/cjs/vehicle/watercraft-identification-number.js +332 -0
- package/dist/cjs/vehicle/watercraft-identification-number.js.map +7 -0
- package/dist/esm/contact/phone-number-test-data.js +1 -1
- package/dist/esm/contact/phone-number-test-data.js.map +1 -1
- package/dist/esm/contact/phone-number.js +36 -14
- package/dist/esm/contact/phone-number.js.map +2 -2
- package/dist/esm/organization/swedish-organization-number.js.map +2 -2
- package/dist/esm/register-default-text-scanners.js +2 -0
- package/dist/esm/register-default-text-scanners.js.map +2 -2
- package/dist/esm/sample-data/index.js +18 -1
- package/dist/esm/sample-data/index.js.map +2 -2
- package/dist/esm/text-scanning/text-scan-result.js +3 -0
- package/dist/esm/text-scanning/text-scan-result.js.map +2 -2
- package/dist/esm/validation/validation-error-reason.js +6 -1
- package/dist/esm/validation/validation-error-reason.js.map +2 -2
- package/dist/esm/vehicle/index.js +8 -0
- package/dist/esm/vehicle/index.js.map +2 -2
- package/dist/esm/vehicle/watercraft-identification-number.js +315 -0
- package/dist/esm/vehicle/watercraft-identification-number.js.map +7 -0
- package/dist/types/banking/index.d.cts +2 -2
- package/dist/types/banking/index.d.ts +2 -2
- package/dist/types/contact/index.d.cts +1 -1
- package/dist/types/contact/index.d.ts +1 -1
- package/dist/types/index.d.cts +2 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/sample-data/index.d.cts +10 -2
- package/dist/types/sample-data/index.d.ts +10 -2
- package/dist/types/text-scanning/index.d.cts +3 -1
- package/dist/types/text-scanning/index.d.ts +3 -1
- package/dist/types/validation/index.d.cts +4 -0
- package/dist/types/validation/index.d.ts +4 -0
- package/dist/types/vehicle/index.d.cts +2 -0
- package/dist/types/vehicle/index.d.ts +2 -0
- package/dist/types/watercraft-identification-number-Db1I2LQM.d.cts +123 -0
- package/dist/types/watercraft-identification-number-o8B3C6Nx.d.ts +123 -0
- package/package.json +18 -13
- package/dist/types/{swedish-swish-number-CL6Gx_h3.d.cts → swedish-swish-number-Bh-UbVoN.d.cts} +136 -136
- package/dist/types/{swedish-swish-number-DDG3mNDg.d.ts → swedish-swish-number-C2Wccuyr.d.ts} +136 -136
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var watercraft_identification_number_exports = {};
|
|
20
|
+
__export(watercraft_identification_number_exports, {
|
|
21
|
+
WatercraftIdentificationNumber: () => WatercraftIdentificationNumber,
|
|
22
|
+
WatercraftIdentificationNumberScheme: () => WatercraftIdentificationNumberScheme,
|
|
23
|
+
maskWatercraftIdentificationNumber: () => maskWatercraftIdentificationNumber
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(watercraft_identification_number_exports);
|
|
26
|
+
var import_country = require("../geography/country.js");
|
|
27
|
+
var import_input_sanitization = require("../internal/input-sanitization.js");
|
|
28
|
+
var import_text_candidate = require("../text-scanning/text-candidate.js");
|
|
29
|
+
var import_text_candidate_category = require("../text-scanning/text-candidate-category.js");
|
|
30
|
+
var import_text_match_confidence = require("../text-scanning/text-match-confidence.js");
|
|
31
|
+
var import_validation_error_reason = require("../validation/validation-error-reason.js");
|
|
32
|
+
var import_validation_issue = require("../validation/validation-issue.js");
|
|
33
|
+
var import_validation_result = require("../validation/validation-result.js");
|
|
34
|
+
const WatercraftIdentificationNumberScheme = {
|
|
35
|
+
Unknown: 0,
|
|
36
|
+
/**
|
|
37
|
+
* ISO 10087 craft or watercraft identification number (CIN/WIN): a two-letter
|
|
38
|
+
* country code, a hyphen and twelve characters, e.g. `NL-HXAB7A33G506`.
|
|
39
|
+
*/
|
|
40
|
+
Iso10087: 1,
|
|
41
|
+
/**
|
|
42
|
+
* United States hull identification number (HIN) in the twelve-character format
|
|
43
|
+
* required since 1 August 1984 by 33 CFR 181.25, e.g. `ZZZ00001A020`.
|
|
44
|
+
*/
|
|
45
|
+
UnitedStatesHullIdentificationNumber: 2
|
|
46
|
+
};
|
|
47
|
+
const MAX_INPUT_LENGTH = 30;
|
|
48
|
+
const ISO_LENGTH = 14;
|
|
49
|
+
const UNITED_STATES_LENGTH = 12;
|
|
50
|
+
const ALLOWED_CHARACTERS_PATTERN = /^[A-Z0-9-]+$/u;
|
|
51
|
+
const WHITESPACE_PATTERN = / +/g;
|
|
52
|
+
const LOWERCASE_ASCII_PATTERN = /[a-z]/g;
|
|
53
|
+
const DOTNET_WHITESPACE_ONLY_PATTERN = /^[\p{Z}\t\n\v\f\r\u0085]*$/u;
|
|
54
|
+
const DOTNET_TRIM_PATTERN = /^[\p{Z}\t\n\v\f\r\u0085]+|[\p{Z}\t\n\v\f\r\u0085]+$/gu;
|
|
55
|
+
const COUNTRY_CODE_PATTERN = /^[A-Z]{2}$/u;
|
|
56
|
+
const ISO_MANUFACTURER_CODE_PATTERN = /^[A-Z2-9]{3}$/u;
|
|
57
|
+
const UNITED_STATES_MANUFACTURER_CODE_PATTERN = /^[A-Z0-9]{3}$/u;
|
|
58
|
+
const SERIAL_NUMBER_PATTERN = /^[A-HJ-NPR-Z0-9]{5}$/u;
|
|
59
|
+
const YEAR_DIGITS_PATTERN = /^[0-9]{3}$/u;
|
|
60
|
+
const SCAN_PATTERN = /(?<![A-Z0-9-])(?:[A-Z]{2}-?[A-Z0-9]{12}|[A-Z0-9]{12})(?![A-Z0-9-])/gu;
|
|
61
|
+
class WatercraftIdentificationNumber {
|
|
62
|
+
static typeInfo = Object.freeze({
|
|
63
|
+
englishName: "Watercraft Identification Number",
|
|
64
|
+
localizedName: "Skrovnummer",
|
|
65
|
+
emoji: "\u{1F6A4}",
|
|
66
|
+
sources: Object.freeze([
|
|
67
|
+
"https://www.iso.org/standard/82383.html",
|
|
68
|
+
"https://www.ecfr.gov/current/title-33/chapter-I/subchapter-S/part-181/subpart-C/section-181.25",
|
|
69
|
+
"https://www.transportstyrelsen.se/sv/sjofart/fritidsbatar/lagar-och-regler-for-fritidsbatar/cemarkning/bygga-om-tillverka-distribuera-och-importera/tillverka/instruktionsbok-tillverkarskylt-och-win/"
|
|
70
|
+
])
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* The number in uppercase without separators: fourteen characters for ISO 10087,
|
|
74
|
+
* e.g. `NLHXAB7A33G506`, or twelve for a US HIN, e.g. `ZZZ00001A020`.
|
|
75
|
+
*/
|
|
76
|
+
value;
|
|
77
|
+
/**
|
|
78
|
+
* The number as it is marked on the hull: ISO 10087 with the hyphen after the
|
|
79
|
+
* country code, e.g. `NL-HXAB7A33G506`, and a US HIN unchanged, e.g. `ZZZ00001A020`.
|
|
80
|
+
*/
|
|
81
|
+
formatted;
|
|
82
|
+
/** Which of the two supported formats the number follows. */
|
|
83
|
+
scheme;
|
|
84
|
+
/**
|
|
85
|
+
* The ISO 3166-1 alpha-2 code of the country where the manufacturer is established,
|
|
86
|
+
* e.g. `NL`, or `null` for a US HIN, which carries no country.
|
|
87
|
+
*/
|
|
88
|
+
countryCode;
|
|
89
|
+
/** The country of {@link countryCode}, or `null` for a US HIN. */
|
|
90
|
+
country;
|
|
91
|
+
/** The three-character manufacturer identification code (MIC), e.g. `HXA`. */
|
|
92
|
+
manufacturerCode;
|
|
93
|
+
/** The five-character serial number assigned by the manufacturer, e.g. `B7A33`. */
|
|
94
|
+
serialNumber;
|
|
95
|
+
/**
|
|
96
|
+
* The production month letter, `A` for January through `L` for December. For a US
|
|
97
|
+
* HIN this is the month of certification when one is required, otherwise the month
|
|
98
|
+
* of manufacture.
|
|
99
|
+
*/
|
|
100
|
+
productionMonthCode;
|
|
101
|
+
/** The production month decoded from {@link productionMonthCode}, 1–12. */
|
|
102
|
+
productionMonth;
|
|
103
|
+
/** The last digit of the production year, 0–9. The decade is not encoded. */
|
|
104
|
+
productionYearDigit;
|
|
105
|
+
/** The last two digits of the model year as written, e.g. `06`. The century is not encoded. */
|
|
106
|
+
modelYearDigits;
|
|
107
|
+
constructor(value, scheme, country) {
|
|
108
|
+
this.value = value;
|
|
109
|
+
this.scheme = scheme;
|
|
110
|
+
this.country = country;
|
|
111
|
+
const isIso = scheme === WatercraftIdentificationNumberScheme.Iso10087;
|
|
112
|
+
const body = isIso ? value.slice(2) : value;
|
|
113
|
+
this.countryCode = isIso ? value.slice(0, 2) : null;
|
|
114
|
+
this.formatted = this.countryCode === null ? value : `${this.countryCode}-${body}`;
|
|
115
|
+
this.manufacturerCode = body.slice(0, 3);
|
|
116
|
+
this.serialNumber = body.slice(3, 8);
|
|
117
|
+
this.productionMonthCode = body[8];
|
|
118
|
+
this.productionMonth = body.charCodeAt(8) - 64;
|
|
119
|
+
this.productionYearDigit = body.charCodeAt(9) - 48;
|
|
120
|
+
this.modelYearDigits = body.slice(10, 12);
|
|
121
|
+
}
|
|
122
|
+
static tryParse(input) {
|
|
123
|
+
return WatercraftIdentificationNumber.tryParseCore(input, null);
|
|
124
|
+
}
|
|
125
|
+
static parse(input) {
|
|
126
|
+
const result = WatercraftIdentificationNumber.tryParse(input);
|
|
127
|
+
if (result === null) throw new Error("Invalid watercraft identification number.");
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
static isValid(input) {
|
|
131
|
+
return WatercraftIdentificationNumber.tryParse(input) !== null;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Returns the number as it is marked on the hull, e.g. `NL-HXAB7A33G506` or
|
|
135
|
+
* `ZZZ00001A020`.
|
|
136
|
+
*/
|
|
137
|
+
static format(input, options) {
|
|
138
|
+
const parsed = WatercraftIdentificationNumber.tryParse(input);
|
|
139
|
+
if (parsed !== null) return parsed.formatted;
|
|
140
|
+
return fallback(input, options);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Returns the number in uppercase without separators, e.g. `NLHXAB7A33G506` or
|
|
144
|
+
* `ZZZ00001A020`.
|
|
145
|
+
*/
|
|
146
|
+
static normalize(input, options) {
|
|
147
|
+
const parsed = WatercraftIdentificationNumber.tryParse(input);
|
|
148
|
+
if (parsed !== null) return parsed.value;
|
|
149
|
+
return fallback(input, options);
|
|
150
|
+
}
|
|
151
|
+
static isNormalized(input) {
|
|
152
|
+
return input != null && WatercraftIdentificationNumber.normalize(input) === input;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Describes every invalid segment of the input, one issue per segment, or reports
|
|
156
|
+
* it as valid.
|
|
157
|
+
*/
|
|
158
|
+
static validate(input) {
|
|
159
|
+
const issues = [];
|
|
160
|
+
return WatercraftIdentificationNumber.tryParseCore(input, issues) !== null ? (0, import_validation_result.validResult)(input) : (0, import_validation_result.invalidResult)(input, issues);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Finds watercraft identification number candidates in unstructured text. An ISO
|
|
164
|
+
* 10087 number written with its hyphen is reported with medium confidence; one
|
|
165
|
+
* without the hyphen, and a US HIN, are bare runs of letters and digits and
|
|
166
|
+
* reported with low confidence. Results are heuristic and may include false
|
|
167
|
+
* positives.
|
|
168
|
+
*/
|
|
169
|
+
static findCandidatesInText(text) {
|
|
170
|
+
if (!text) return [];
|
|
171
|
+
const upper = toAsciiUpper(text);
|
|
172
|
+
const out = [];
|
|
173
|
+
const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);
|
|
174
|
+
let match;
|
|
175
|
+
while ((match = pattern.exec(upper)) !== null) {
|
|
176
|
+
const value = WatercraftIdentificationNumber.tryParse(match[0]);
|
|
177
|
+
if (value === null) continue;
|
|
178
|
+
out.push(
|
|
179
|
+
new import_text_candidate.TextCandidate({
|
|
180
|
+
startIndex: match.index,
|
|
181
|
+
length: match[0].length,
|
|
182
|
+
originalText: text.slice(match.index, match.index + match[0].length),
|
|
183
|
+
typeName: "WatercraftIdentificationNumber",
|
|
184
|
+
category: import_text_candidate_category.TextCandidateCategory.Vehicle,
|
|
185
|
+
normalizedForm: value.toNormalizedString(),
|
|
186
|
+
formattedForm: value.toString(),
|
|
187
|
+
maskedForm: maskWatercraftIdentificationNumber(value),
|
|
188
|
+
confidence: match[0].includes("-") ? import_text_match_confidence.TextMatchConfidence.Medium : import_text_match_confidence.TextMatchConfidence.Low,
|
|
189
|
+
value
|
|
190
|
+
})
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
/** Returns the number without separators, e.g. `NLHXAB7A33G506`. */
|
|
196
|
+
toNormalizedString() {
|
|
197
|
+
return this.value;
|
|
198
|
+
}
|
|
199
|
+
/** Returns the number as it is marked on the hull, e.g. `NL-HXAB7A33G506`. */
|
|
200
|
+
toString() {
|
|
201
|
+
return this.formatted;
|
|
202
|
+
}
|
|
203
|
+
equals(other) {
|
|
204
|
+
return other != null && this.value === other.value;
|
|
205
|
+
}
|
|
206
|
+
compareTo(other) {
|
|
207
|
+
if (other == null) return 1;
|
|
208
|
+
return this.value < other.value ? -1 : this.value > other.value ? 1 : 0;
|
|
209
|
+
}
|
|
210
|
+
static tryParseCore(input, issues) {
|
|
211
|
+
const fail = (reason, english, swedish) => {
|
|
212
|
+
issues?.push(new import_validation_issue.ValidationIssue(reason, english, swedish));
|
|
213
|
+
return false;
|
|
214
|
+
};
|
|
215
|
+
if (isNullOrWhiteSpace(input)) {
|
|
216
|
+
fail(import_validation_error_reason.ValidationErrorReason.InputIsEmpty, "Input is empty or whitespace.", "V\xE4rdet \xE4r tomt.");
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const cleaned = toAsciiUpper((0, import_input_sanitization.sanitizeInput)(input).replace(WHITESPACE_PATTERN, ""));
|
|
220
|
+
if (cleaned.length > MAX_INPUT_LENGTH) {
|
|
221
|
+
fail(
|
|
222
|
+
import_validation_error_reason.ValidationErrorReason.InputTooLong,
|
|
223
|
+
"Input contains too many characters.",
|
|
224
|
+
"V\xE4rdet inneh\xE5ller f\xF6r m\xE5nga tecken."
|
|
225
|
+
);
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
if (!ALLOWED_CHARACTERS_PATTERN.test(cleaned)) {
|
|
229
|
+
fail(
|
|
230
|
+
import_validation_error_reason.ValidationErrorReason.InvalidCharacters,
|
|
231
|
+
"Only letters A\u2013Z, digits and the hyphen after the country code are allowed.",
|
|
232
|
+
"Endast bokst\xE4verna A\u2013Z, siffror och bindestrecket efter landskoden \xE4r till\xE5tna."
|
|
233
|
+
);
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
const hyphenIndex = cleaned.indexOf("-");
|
|
237
|
+
const hasCountrySeparator = hyphenIndex >= 0;
|
|
238
|
+
if (hasCountrySeparator && (hyphenIndex !== 2 || cleaned.indexOf("-", hyphenIndex + 1) >= 0)) {
|
|
239
|
+
fail(
|
|
240
|
+
import_validation_error_reason.ValidationErrorReason.InvalidFormat,
|
|
241
|
+
"A hyphen is only allowed directly after the two-letter country code.",
|
|
242
|
+
"Bindestreck f\xE5r bara st\xE5 direkt efter den tv\xE5bokstaviga landskoden."
|
|
243
|
+
);
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const compact = hasCountrySeparator ? cleaned.slice(0, hyphenIndex) + cleaned.slice(hyphenIndex + 1) : cleaned;
|
|
247
|
+
const scheme = compact.length === ISO_LENGTH ? WatercraftIdentificationNumberScheme.Iso10087 : compact.length === UNITED_STATES_LENGTH && !hasCountrySeparator ? WatercraftIdentificationNumberScheme.UnitedStatesHullIdentificationNumber : WatercraftIdentificationNumberScheme.Unknown;
|
|
248
|
+
if (scheme === WatercraftIdentificationNumberScheme.Unknown) {
|
|
249
|
+
fail(
|
|
250
|
+
import_validation_error_reason.ValidationErrorReason.InvalidLength,
|
|
251
|
+
"Must be 14 characters after an ISO 10087 country code and hyphen, or 12 characters for a US HIN.",
|
|
252
|
+
"M\xE5ste vara 14 tecken enligt ISO 10087 (landskod, bindestreck och 12 tecken) eller 12 tecken f\xF6r ett amerikanskt HIN."
|
|
253
|
+
);
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
const isIso = scheme === WatercraftIdentificationNumberScheme.Iso10087;
|
|
257
|
+
const body = isIso ? compact.slice(2) : compact;
|
|
258
|
+
let isValid = true;
|
|
259
|
+
let country = null;
|
|
260
|
+
if (isIso) {
|
|
261
|
+
country = resolveCountry(compact.slice(0, 2));
|
|
262
|
+
if (country === null) {
|
|
263
|
+
isValid = fail(
|
|
264
|
+
import_validation_error_reason.ValidationErrorReason.UnknownCountryCode,
|
|
265
|
+
"The first two characters must be an ISO 3166-1 alpha-2 country code.",
|
|
266
|
+
"De tv\xE5 f\xF6rsta tecknen m\xE5ste vara en landskod enligt ISO 3166-1 alpha-2."
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (isIso && !ISO_MANUFACTURER_CODE_PATTERN.test(body.slice(0, 3))) {
|
|
271
|
+
isValid = fail(
|
|
272
|
+
import_validation_error_reason.ValidationErrorReason.InvalidManufacturerCode,
|
|
273
|
+
"The manufacturer code must be three letters or digits, except the digits 0 and 1.",
|
|
274
|
+
"Tillverkarkoden m\xE5ste vara tre bokst\xE4ver eller siffror, men inte siffrorna 0 och 1."
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
if (!isIso && !UNITED_STATES_MANUFACTURER_CODE_PATTERN.test(body.slice(0, 3))) {
|
|
278
|
+
isValid = fail(
|
|
279
|
+
import_validation_error_reason.ValidationErrorReason.InvalidManufacturerCode,
|
|
280
|
+
"The manufacturer code must be three letters or digits.",
|
|
281
|
+
"Tillverkarkoden m\xE5ste vara tre bokst\xE4ver eller siffror."
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
if (!SERIAL_NUMBER_PATTERN.test(body.slice(3, 8))) {
|
|
285
|
+
isValid = fail(
|
|
286
|
+
import_validation_error_reason.ValidationErrorReason.InvalidSerialNumber,
|
|
287
|
+
"The serial number must be five letters or digits, except the letters I, O and Q.",
|
|
288
|
+
"Serienumret m\xE5ste vara fem bokst\xE4ver eller siffror, men inte bokst\xE4verna I, O och Q."
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
const monthCode = body[8];
|
|
292
|
+
if (monthCode < "A" || monthCode > "L") {
|
|
293
|
+
isValid = fail(
|
|
294
|
+
import_validation_error_reason.ValidationErrorReason.InvalidMonthCode,
|
|
295
|
+
"The production month must be a letter from A (January) to L (December).",
|
|
296
|
+
"Tillverkningsm\xE5naden m\xE5ste vara en bokstav fr\xE5n A (januari) till L (december)."
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
if (!YEAR_DIGITS_PATTERN.test(body.slice(9, 12))) {
|
|
300
|
+
isValid = fail(
|
|
301
|
+
import_validation_error_reason.ValidationErrorReason.InvalidYearDigits,
|
|
302
|
+
"The production year and model year must be digits.",
|
|
303
|
+
"Tillverknings\xE5r och \xE5rsmodell m\xE5ste anges med siffror."
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
if (!isValid) return null;
|
|
307
|
+
return new WatercraftIdentificationNumber(compact, scheme, country);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function maskWatercraftIdentificationNumber(win) {
|
|
311
|
+
const prefix = win.countryCode === null ? win.manufacturerCode : `${win.countryCode}-${win.manufacturerCode}`;
|
|
312
|
+
return prefix + "*".repeat(win.formatted.length - prefix.length);
|
|
313
|
+
}
|
|
314
|
+
function resolveCountry(code) {
|
|
315
|
+
if (!COUNTRY_CODE_PATTERN.test(code)) return null;
|
|
316
|
+
const parsed = import_country.Country.tryParse(code);
|
|
317
|
+
return parsed !== null && parsed.alpha2Code === code ? parsed : null;
|
|
318
|
+
}
|
|
319
|
+
function toAsciiUpper(text) {
|
|
320
|
+
return text.replace(LOWERCASE_ASCII_PATTERN, (c) => String.fromCharCode(c.charCodeAt(0) - 32));
|
|
321
|
+
}
|
|
322
|
+
function fallback(input, options) {
|
|
323
|
+
if (options?.fallbackToTrimmedInputWhenInvalid !== true || isNullOrWhiteSpace(input)) return null;
|
|
324
|
+
return trimLikeDotnet(input);
|
|
325
|
+
}
|
|
326
|
+
function isNullOrWhiteSpace(input) {
|
|
327
|
+
return input == null || DOTNET_WHITESPACE_ONLY_PATTERN.test(input);
|
|
328
|
+
}
|
|
329
|
+
function trimLikeDotnet(input) {
|
|
330
|
+
return input.replace(DOTNET_TRIM_PATTERN, "");
|
|
331
|
+
}
|
|
332
|
+
//# sourceMappingURL=watercraft-identification-number.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/vehicle/watercraft-identification-number.ts"],
|
|
4
|
+
"sourcesContent": ["import { Country } from \"../geography/country.js\";\nimport { sanitizeInput } from \"../internal/input-sanitization.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { ValidationErrorReason } from \"../validation/validation-error-reason.js\";\nimport { ValidationIssue } from \"../validation/validation-issue.js\";\nimport {\n invalidResult,\n validResult,\n type ValidationResult,\n} from \"../validation/validation-result.js\";\n\n/** Options for {@link WatercraftIdentificationNumber.format} and `normalize`. */\nexport interface WatercraftIdentificationNumberFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n}\n\n/** The scheme a {@link WatercraftIdentificationNumber} was written in. */\nexport const WatercraftIdentificationNumberScheme = {\n Unknown: 0,\n /**\n * ISO 10087 craft or watercraft identification number (CIN/WIN): a two-letter\n * country code, a hyphen and twelve characters, e.g. `NL-HXAB7A33G506`.\n */\n Iso10087: 1,\n /**\n * United States hull identification number (HIN) in the twelve-character format\n * required since 1 August 1984 by 33 CFR 181.25, e.g. `ZZZ00001A020`.\n */\n UnitedStatesHullIdentificationNumber: 2,\n} as const;\n\nexport type WatercraftIdentificationNumberScheme =\n (typeof WatercraftIdentificationNumberScheme)[keyof typeof WatercraftIdentificationNumberScheme];\n\nconst MAX_INPUT_LENGTH = 30;\nconst ISO_LENGTH = 14;\nconst UNITED_STATES_LENGTH = 12;\n\nconst ALLOWED_CHARACTERS_PATTERN = /^[A-Z0-9-]+$/u;\n// sanitizeInput has already turned every whitespace character into an ASCII space and dropped\n// U+0085, U+FEFF, \\v and \\f, so a space is all that is left to strip. `\\s` would differ from the\n// .NET port, where it also matches U+0085 but not U+FEFF.\nconst WHITESPACE_PATTERN = / +/g;\nconst LOWERCASE_ASCII_PATTERN = /[a-z]/g;\nconst DOTNET_WHITESPACE_ONLY_PATTERN = /^[\\p{Z}\\t\\n\\v\\f\\r\\u0085]*$/u;\nconst DOTNET_TRIM_PATTERN = /^[\\p{Z}\\t\\n\\v\\f\\r\\u0085]+|[\\p{Z}\\t\\n\\v\\f\\r\\u0085]+$/gu;\nconst COUNTRY_CODE_PATTERN = /^[A-Z]{2}$/u;\n\n// ISO 10087 \u00A74.3: letters and numerals, except the numerals 0 and 1.\nconst ISO_MANUFACTURER_CODE_PATTERN = /^[A-Z2-9]{3}$/u;\n\n// 33 CFR 181.25(a) leaves the characters of a Coast Guard assigned code unrestricted.\nconst UNITED_STATES_MANUFACTURER_CODE_PATTERN = /^[A-Z0-9]{3}$/u;\n\n// ISO 10087 \u00A74.4 and 33 CFR 181.25(b): letters and numerals, except the letters I, O and Q.\nconst SERIAL_NUMBER_PATTERN = /^[A-HJ-NPR-Z0-9]{5}$/u;\n\nconst YEAR_DIGITS_PATTERN = /^[0-9]{3}$/u;\n\nconst SCAN_PATTERN = /(?<![A-Z0-9-])(?:[A-Z]{2}-?[A-Z0-9]{12}|[A-Z0-9]{12})(?![A-Z0-9-])/gu;\n\n/**\n * A watercraft identification number (`skrovnummer`), the hull marking of a small\n * craft: either the ISO 10087 craft identification number (CIN, now called WIN by\n * Transportstyrelsen) of fourteen characters plus a hyphen, or the twelve-character\n * US hull identification number (HIN).\n *\n * The number is assigned by the manufacturer and carries no check digit, so a parsed\n * value is structurally valid only \u2014 it does not prove that the manufacturer code is\n * registered or that the number belongs to a particular craft. The production year\n * and model year are encoded as one and two digits respectively, so the century\n * cannot be derived from the number alone; they are exposed as digits rather than\n * full years. Older markings that predate these formats (for example US HINs from\n * before August 1984) are not accepted.\n *\n * Sources:\n * - https://www.iso.org/standard/82383.html\n * - https://www.ecfr.gov/current/title-33/chapter-I/subchapter-S/part-181/subpart-C/section-181.25\n * - https://www.transportstyrelsen.se/sv/sjofart/fritidsbatar/lagar-och-regler-for-fritidsbatar/cemarkning/bygga-om-tillverka-distribuera-och-importera/tillverka/instruktionsbok-tillverkarskylt-och-win/\n */\nexport class WatercraftIdentificationNumber {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Watercraft Identification Number\",\n localizedName: \"Skrovnummer\",\n emoji: \"\uD83D\uDEA4\",\n sources: Object.freeze([\n \"https://www.iso.org/standard/82383.html\",\n \"https://www.ecfr.gov/current/title-33/chapter-I/subchapter-S/part-181/subpart-C/section-181.25\",\n \"https://www.transportstyrelsen.se/sv/sjofart/fritidsbatar/lagar-och-regler-for-fritidsbatar/cemarkning/bygga-om-tillverka-distribuera-och-importera/tillverka/instruktionsbok-tillverkarskylt-och-win/\",\n ]),\n });\n\n /**\n * The number in uppercase without separators: fourteen characters for ISO 10087,\n * e.g. `NLHXAB7A33G506`, or twelve for a US HIN, e.g. `ZZZ00001A020`.\n */\n readonly value: string;\n\n /**\n * The number as it is marked on the hull: ISO 10087 with the hyphen after the\n * country code, e.g. `NL-HXAB7A33G506`, and a US HIN unchanged, e.g. `ZZZ00001A020`.\n */\n readonly formatted: string;\n\n /** Which of the two supported formats the number follows. */\n readonly scheme: WatercraftIdentificationNumberScheme;\n\n /**\n * The ISO 3166-1 alpha-2 code of the country where the manufacturer is established,\n * e.g. `NL`, or `null` for a US HIN, which carries no country.\n */\n readonly countryCode: string | null;\n\n /** The country of {@link countryCode}, or `null` for a US HIN. */\n readonly country: Country | null;\n\n /** The three-character manufacturer identification code (MIC), e.g. `HXA`. */\n readonly manufacturerCode: string;\n\n /** The five-character serial number assigned by the manufacturer, e.g. `B7A33`. */\n readonly serialNumber: string;\n\n /**\n * The production month letter, `A` for January through `L` for December. For a US\n * HIN this is the month of certification when one is required, otherwise the month\n * of manufacture.\n */\n readonly productionMonthCode: string;\n\n /** The production month decoded from {@link productionMonthCode}, 1\u201312. */\n readonly productionMonth: number;\n\n /** The last digit of the production year, 0\u20139. The decade is not encoded. */\n readonly productionYearDigit: number;\n\n /** The last two digits of the model year as written, e.g. `06`. The century is not encoded. */\n readonly modelYearDigits: string;\n\n private constructor(\n value: string,\n scheme: WatercraftIdentificationNumberScheme,\n country: Country | null,\n ) {\n this.value = value;\n this.scheme = scheme;\n this.country = country;\n\n const isIso = scheme === WatercraftIdentificationNumberScheme.Iso10087;\n const body = isIso ? value.slice(2) : value;\n this.countryCode = isIso ? value.slice(0, 2) : null;\n this.formatted = this.countryCode === null ? value : `${this.countryCode}-${body}`;\n this.manufacturerCode = body.slice(0, 3);\n this.serialNumber = body.slice(3, 8);\n this.productionMonthCode = body[8]!;\n this.productionMonth = body.charCodeAt(8) - 64;\n this.productionYearDigit = body.charCodeAt(9) - 48;\n this.modelYearDigits = body.slice(10, 12);\n }\n\n static tryParse(input: string | null | undefined): WatercraftIdentificationNumber | null {\n return WatercraftIdentificationNumber.tryParseCore(input, null);\n }\n\n static parse(input: string): WatercraftIdentificationNumber {\n const result = WatercraftIdentificationNumber.tryParse(input);\n if (result === null) throw new Error(\"Invalid watercraft identification number.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return WatercraftIdentificationNumber.tryParse(input) !== null;\n }\n\n /**\n * Returns the number as it is marked on the hull, e.g. `NL-HXAB7A33G506` or\n * `ZZZ00001A020`.\n */\n static format(\n input: string | null | undefined,\n options?: WatercraftIdentificationNumberFormatOptions,\n ): string | null {\n const parsed = WatercraftIdentificationNumber.tryParse(input);\n if (parsed !== null) return parsed.formatted;\n return fallback(input, options);\n }\n\n /**\n * Returns the number in uppercase without separators, e.g. `NLHXAB7A33G506` or\n * `ZZZ00001A020`.\n */\n static normalize(\n input: string | null | undefined,\n options?: WatercraftIdentificationNumberFormatOptions,\n ): string | null {\n const parsed = WatercraftIdentificationNumber.tryParse(input);\n if (parsed !== null) return parsed.value;\n return fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && WatercraftIdentificationNumber.normalize(input) === input;\n }\n\n /**\n * Describes every invalid segment of the input, one issue per segment, or reports\n * it as valid.\n */\n static validate(input: string | null | undefined): ValidationResult {\n const issues: ValidationIssue[] = [];\n return WatercraftIdentificationNumber.tryParseCore(input, issues) !== null\n ? validResult(input)\n : invalidResult(input, issues);\n }\n\n /**\n * Finds watercraft identification number candidates in unstructured text. An ISO\n * 10087 number written with its hyphen is reported with medium confidence; one\n * without the hyphen, and a US HIN, are bare runs of letters and digits and\n * reported with low confidence. Results are heuristic and may include false\n * positives.\n */\n static findCandidatesInText(\n text: string,\n ): readonly TextCandidate<WatercraftIdentificationNumber>[] {\n if (!text) return [];\n\n const upper = toAsciiUpper(text);\n const out: TextCandidate<WatercraftIdentificationNumber>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(upper)) !== null) {\n const value = WatercraftIdentificationNumber.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<WatercraftIdentificationNumber>({\n startIndex: match.index,\n length: match[0].length,\n originalText: text.slice(match.index, match.index + match[0].length),\n typeName: \"WatercraftIdentificationNumber\",\n category: TextCandidateCategory.Vehicle,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskWatercraftIdentificationNumber(value),\n confidence: match[0].includes(\"-\") ? TextMatchConfidence.Medium : TextMatchConfidence.Low,\n value,\n }),\n );\n }\n\n return out;\n }\n\n /** Returns the number without separators, e.g. `NLHXAB7A33G506`. */\n toNormalizedString(): string {\n return this.value;\n }\n\n /** Returns the number as it is marked on the hull, e.g. `NL-HXAB7A33G506`. */\n toString(): string {\n return this.formatted;\n }\n\n equals(other: WatercraftIdentificationNumber | null | undefined): boolean {\n return other != null && this.value === other.value;\n }\n\n compareTo(other: WatercraftIdentificationNumber | null | undefined): number {\n if (other == null) return 1;\n return this.value < other.value ? -1 : this.value > other.value ? 1 : 0;\n }\n\n private static tryParseCore(\n input: string | null | undefined,\n issues: ValidationIssue[] | null,\n ): WatercraftIdentificationNumber | null {\n const fail = (reason: ValidationErrorReason, english: string, swedish: string): false => {\n issues?.push(new ValidationIssue(reason, english, swedish));\n return false;\n };\n\n if (isNullOrWhiteSpace(input)) {\n fail(ValidationErrorReason.InputIsEmpty, \"Input is empty or whitespace.\", \"V\u00E4rdet \u00E4r tomt.\");\n return null;\n }\n\n const cleaned = toAsciiUpper(sanitizeInput(input).replace(WHITESPACE_PATTERN, \"\"));\n\n if (cleaned.length > MAX_INPUT_LENGTH) {\n fail(\n ValidationErrorReason.InputTooLong,\n \"Input contains too many characters.\",\n \"V\u00E4rdet inneh\u00E5ller f\u00F6r m\u00E5nga tecken.\",\n );\n return null;\n }\n\n if (!ALLOWED_CHARACTERS_PATTERN.test(cleaned)) {\n fail(\n ValidationErrorReason.InvalidCharacters,\n \"Only letters A\u2013Z, digits and the hyphen after the country code are allowed.\",\n \"Endast bokst\u00E4verna A\u2013Z, siffror och bindestrecket efter landskoden \u00E4r till\u00E5tna.\",\n );\n return null;\n }\n\n const hyphenIndex = cleaned.indexOf(\"-\");\n const hasCountrySeparator = hyphenIndex >= 0;\n if (hasCountrySeparator && (hyphenIndex !== 2 || cleaned.indexOf(\"-\", hyphenIndex + 1) >= 0)) {\n fail(\n ValidationErrorReason.InvalidFormat,\n \"A hyphen is only allowed directly after the two-letter country code.\",\n \"Bindestreck f\u00E5r bara st\u00E5 direkt efter den tv\u00E5bokstaviga landskoden.\",\n );\n return null;\n }\n\n const compact = hasCountrySeparator\n ? cleaned.slice(0, hyphenIndex) + cleaned.slice(hyphenIndex + 1)\n : cleaned;\n const scheme =\n compact.length === ISO_LENGTH\n ? WatercraftIdentificationNumberScheme.Iso10087\n : compact.length === UNITED_STATES_LENGTH && !hasCountrySeparator\n ? WatercraftIdentificationNumberScheme.UnitedStatesHullIdentificationNumber\n : WatercraftIdentificationNumberScheme.Unknown;\n\n if (scheme === WatercraftIdentificationNumberScheme.Unknown) {\n fail(\n ValidationErrorReason.InvalidLength,\n \"Must be 14 characters after an ISO 10087 country code and hyphen, or 12 characters for a US HIN.\",\n \"M\u00E5ste vara 14 tecken enligt ISO 10087 (landskod, bindestreck och 12 tecken) eller 12 tecken f\u00F6r ett amerikanskt HIN.\",\n );\n return null;\n }\n\n const isIso = scheme === WatercraftIdentificationNumberScheme.Iso10087;\n const body = isIso ? compact.slice(2) : compact;\n let isValid = true;\n let country: Country | null = null;\n\n if (isIso) {\n country = resolveCountry(compact.slice(0, 2));\n if (country === null) {\n isValid = fail(\n ValidationErrorReason.UnknownCountryCode,\n \"The first two characters must be an ISO 3166-1 alpha-2 country code.\",\n \"De tv\u00E5 f\u00F6rsta tecknen m\u00E5ste vara en landskod enligt ISO 3166-1 alpha-2.\",\n );\n }\n }\n\n if (isIso && !ISO_MANUFACTURER_CODE_PATTERN.test(body.slice(0, 3))) {\n isValid = fail(\n ValidationErrorReason.InvalidManufacturerCode,\n \"The manufacturer code must be three letters or digits, except the digits 0 and 1.\",\n \"Tillverkarkoden m\u00E5ste vara tre bokst\u00E4ver eller siffror, men inte siffrorna 0 och 1.\",\n );\n }\n\n if (!isIso && !UNITED_STATES_MANUFACTURER_CODE_PATTERN.test(body.slice(0, 3))) {\n isValid = fail(\n ValidationErrorReason.InvalidManufacturerCode,\n \"The manufacturer code must be three letters or digits.\",\n \"Tillverkarkoden m\u00E5ste vara tre bokst\u00E4ver eller siffror.\",\n );\n }\n\n if (!SERIAL_NUMBER_PATTERN.test(body.slice(3, 8))) {\n isValid = fail(\n ValidationErrorReason.InvalidSerialNumber,\n \"The serial number must be five letters or digits, except the letters I, O and Q.\",\n \"Serienumret m\u00E5ste vara fem bokst\u00E4ver eller siffror, men inte bokst\u00E4verna I, O och Q.\",\n );\n }\n\n const monthCode = body[8]!;\n if (monthCode < \"A\" || monthCode > \"L\") {\n isValid = fail(\n ValidationErrorReason.InvalidMonthCode,\n \"The production month must be a letter from A (January) to L (December).\",\n \"Tillverkningsm\u00E5naden m\u00E5ste vara en bokstav fr\u00E5n A (januari) till L (december).\",\n );\n }\n\n if (!YEAR_DIGITS_PATTERN.test(body.slice(9, 12))) {\n isValid = fail(\n ValidationErrorReason.InvalidYearDigits,\n \"The production year and model year must be digits.\",\n \"Tillverknings\u00E5r och \u00E5rsmodell m\u00E5ste anges med siffror.\",\n );\n }\n\n if (!isValid) return null;\n\n return new WatercraftIdentificationNumber(compact, scheme, country);\n }\n}\n\n/**\n * Returns a watercraft identification number with only the country and manufacturer\n * codes visible, e.g. `NL-HXAB7A33G506` becomes `NL-HXA*********` and\n * `ZZZ00001A020` becomes `ZZZ*********`.\n */\nexport function maskWatercraftIdentificationNumber(win: WatercraftIdentificationNumber): string {\n const prefix =\n win.countryCode === null ? win.manufacturerCode : `${win.countryCode}-${win.manufacturerCode}`;\n return prefix + \"*\".repeat(win.formatted.length - prefix.length);\n}\n\nfunction resolveCountry(code: string): Country | null {\n if (!COUNTRY_CODE_PATTERN.test(code)) return null;\n const parsed = Country.tryParse(code);\n return parsed !== null && parsed.alpha2Code === code ? parsed : null;\n}\n\n/**\n * Upper-cases a\u2013z only and leaves every other code unit as it is, so the length and\n * match offsets are unchanged. `toUpperCase` maps some non-ASCII letters onto ASCII\n * (`\u0131` \u2192 `I`, `\u017F` \u2192 `S`), which would let a look-alike pass as A\u2013Z; the .NET port uses\n * the same ASCII-only rule.\n */\nfunction toAsciiUpper(text: string): string {\n return text.replace(LOWERCASE_ASCII_PATTERN, (c) => String.fromCharCode(c.charCodeAt(0) - 32));\n}\n\nfunction fallback(\n input: string | null | undefined,\n options?: WatercraftIdentificationNumberFormatOptions,\n): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true || isNullOrWhiteSpace(input)) return null;\n return trimLikeDotnet(input);\n}\n\n/**\n * .NET `string.IsNullOrWhiteSpace` and `string.Trim()` use `char.IsWhiteSpace`, which counts\n * U+0085 and not U+FEFF \u2014 the reverse of `String.prototype.trim`. These mirror the .NET port so\n * the empty check and the fallback text agree for every input.\n */\nfunction isNullOrWhiteSpace(input: string | null | undefined): input is null | undefined {\n return input == null || DOTNET_WHITESPACE_ONLY_PATTERN.test(input);\n}\n\nfunction trimLikeDotnet(input: string): string {\n return input.replace(DOTNET_TRIM_PATTERN, \"\");\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -18,7 +18,7 @@ const PhoneNumberTestData = {
|
|
|
18
18
|
get landlineMalmo() {
|
|
19
19
|
return generateRange("04062804", 0, 99);
|
|
20
20
|
},
|
|
21
|
-
/** Landline Stockholm: 08-
|
|
21
|
+
/** Landline Stockholm: 08-465 004 00 through 08-465 004 99 (100 numbers). */
|
|
22
22
|
get landlineStockholm() {
|
|
23
23
|
return generateRange("08465004", 0, 99);
|
|
24
24
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/contact/phone-number-test-data.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * PTS (Post- och telestyrelsen) reserves phone number ranges for use in fiction\n * and testing \u2014 these numbers are never assigned to real subscribers.\n *\n * {@link PhoneNumberTestData} enumerates every reserved number;\n * `PhoneNumber.isSwedishTestPhoneNumber` checks whether a parsed number falls in\n * a reserved range.\n *\n * Source: https://pts.se/internet-och-telefoni/telefonnummer-och-adressering/telefonnummer-till-bocker-och-filmer/\n */\nfunction generateRange(prefix: string, from: number, to: number): readonly string[] {\n const result: string[] = [];\n for (let i = from; i <= to; i++) {\n result.push(prefix + String(i).padStart(2, \"0\"));\n }\n return Object.freeze(result);\n}\n\nexport const PhoneNumberTestData = {\n /** Mobile: 070-174 06 05 through 070-174 06 99 (95 numbers). */\n get mobile(): readonly string[] {\n return generateRange(\"07017406\", 5, 99);\n },\n\n /** Landline Gothenburg: 031-390 06 00 through 031-390 06 99 (100 numbers). */\n get landlineGothenburg(): readonly string[] {\n return generateRange(\"03139006\", 0, 99);\n },\n\n /** Landline Malm\u00F6: 040-628 04 00 through 040-628 04 99 (100 numbers). */\n get landlineMalmo(): readonly string[] {\n return generateRange(\"04062804\", 0, 99);\n },\n\n /** Landline Stockholm: 08-
|
|
4
|
+
"sourcesContent": ["/**\n * PTS (Post- och telestyrelsen) reserves phone number ranges for use in fiction\n * and testing \u2014 these numbers are never assigned to real subscribers.\n *\n * {@link PhoneNumberTestData} enumerates every reserved number;\n * `PhoneNumber.isSwedishTestPhoneNumber` checks whether a parsed number falls in\n * a reserved range.\n *\n * Source: https://pts.se/internet-och-telefoni/telefonnummer-och-adressering/telefonnummer-till-bocker-och-filmer/\n */\nfunction generateRange(prefix: string, from: number, to: number): readonly string[] {\n const result: string[] = [];\n for (let i = from; i <= to; i++) {\n result.push(prefix + String(i).padStart(2, \"0\"));\n }\n return Object.freeze(result);\n}\n\nexport const PhoneNumberTestData = {\n /** Mobile: 070-174 06 05 through 070-174 06 99 (95 numbers). */\n get mobile(): readonly string[] {\n return generateRange(\"07017406\", 5, 99);\n },\n\n /** Landline Gothenburg: 031-390 06 00 through 031-390 06 99 (100 numbers). */\n get landlineGothenburg(): readonly string[] {\n return generateRange(\"03139006\", 0, 99);\n },\n\n /** Landline Malm\u00F6: 040-628 04 00 through 040-628 04 99 (100 numbers). */\n get landlineMalmo(): readonly string[] {\n return generateRange(\"04062804\", 0, 99);\n },\n\n /** Landline Stockholm: 08-465 004 00 through 08-465 004 99 (100 numbers). */\n get landlineStockholm(): readonly string[] {\n return generateRange(\"08465004\", 0, 99);\n },\n\n /** Landline Kiruna: 0980-31 92 00 through 0980-31 92 99 (100 numbers). */\n get landlineKiruna(): readonly string[] {\n return generateRange(\"09803192\", 0, 99);\n },\n\n /** All reserved test phone numbers across all ranges (495 numbers). */\n get all(): readonly string[] {\n return Object.freeze([\n ...PhoneNumberTestData.mobile,\n ...PhoneNumberTestData.landlineGothenburg,\n ...PhoneNumberTestData.landlineMalmo,\n ...PhoneNumberTestData.landlineStockholm,\n ...PhoneNumberTestData.landlineKiruna,\n ]);\n },\n};\n"],
|
|
5
5
|
"mappings": "AAUA,SAAS,cAAc,QAAgB,MAAc,IAA+B;AAClF,QAAM,SAAmB,CAAC;AAC1B,WAAS,IAAI,MAAM,KAAK,IAAI,KAAK;AAC/B,WAAO,KAAK,SAAS,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,EACjD;AACA,SAAO,OAAO,OAAO,MAAM;AAC7B;AAEO,MAAM,sBAAsB;AAAA;AAAA,EAEjC,IAAI,SAA4B;AAC9B,WAAO,cAAc,YAAY,GAAG,EAAE;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,qBAAwC;AAC1C,WAAO,cAAc,YAAY,GAAG,EAAE;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,gBAAmC;AACrC,WAAO,cAAc,YAAY,GAAG,EAAE;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,oBAAuC;AACzC,WAAO,cAAc,YAAY,GAAG,EAAE;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,iBAAoC;AACtC,WAAO,cAAc,YAAY,GAAG,EAAE;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,MAAyB;AAC3B,WAAO,OAAO,OAAO;AAAA,MACnB,GAAG,oBAAoB;AAAA,MACvB,GAAG,oBAAoB;AAAA,MACvB,GAAG,oBAAoB;AAAA,MACvB,GAAG,oBAAoB;AAAA,MACvB,GAAG,oBAAoB;AAAA,IACzB,CAAC;AAAA,EACH;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -197,7 +197,7 @@ class PhoneNumber {
|
|
|
197
197
|
return this.countryCallingCode.value === dcc ? this.toLocalString() : this.toDisplayInternationalString();
|
|
198
198
|
}
|
|
199
199
|
const subscriber = this.digits.slice(2 + this.countryCallingCode.value.length);
|
|
200
|
-
if (this.isSwedish) return formatSwedishLocal(
|
|
200
|
+
if (this.isSwedish) return formatSwedishLocal(subscriber);
|
|
201
201
|
return "0" + subscriber;
|
|
202
202
|
}
|
|
203
203
|
toE164String() {
|
|
@@ -208,6 +208,7 @@ class PhoneNumber {
|
|
|
208
208
|
}
|
|
209
209
|
toDisplayInternationalString() {
|
|
210
210
|
const subscriber = this.digits.slice(2 + this.countryCallingCode.value.length);
|
|
211
|
+
if (this.isSwedish) return formatSwedishInternational(subscriber);
|
|
211
212
|
return "+" + this.countryCallingCode.value + " " + formatInternationalSubscriberDigits(this.countryCallingCode.value, subscriber);
|
|
212
213
|
}
|
|
213
214
|
toString() {
|
|
@@ -281,22 +282,43 @@ function formatInternationalSubscriberDigits(callingCode, digits) {
|
|
|
281
282
|
return digits;
|
|
282
283
|
}
|
|
283
284
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
285
|
+
const SWEDISH_TWO_DIGIT_DESTINATION_CODES = /* @__PURE__ */ new Set([
|
|
286
|
+
..."11 13 16 18 19 21 23 26 31 33 35 36 40 42 44 46 54 60 63 90".split(" "),
|
|
287
|
+
..."10 20 70 71 72 73 74 75 76 77 79 99".split(" ")
|
|
288
|
+
]);
|
|
289
|
+
const SWEDISH_THREE_DIGIT_DESTINATION_CODES_OVERRIDING_TWO_DIGIT = /* @__PURE__ */ new Set(["900"]);
|
|
290
|
+
function swedishDestinationCodeLength(nationalSignificantNumber) {
|
|
291
|
+
if (nationalSignificantNumber.startsWith("8")) return 1;
|
|
292
|
+
if (SWEDISH_THREE_DIGIT_DESTINATION_CODES_OVERRIDING_TWO_DIGIT.has(
|
|
293
|
+
nationalSignificantNumber.slice(0, 3)
|
|
294
|
+
)) {
|
|
295
|
+
return 3;
|
|
288
296
|
}
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
297
|
+
if (SWEDISH_TWO_DIGIT_DESTINATION_CODES.has(nationalSignificantNumber.slice(0, 2))) return 2;
|
|
298
|
+
return 3;
|
|
299
|
+
}
|
|
300
|
+
function groupSwedishSubscriberNumber(subscriber) {
|
|
301
|
+
if (subscriber.length === 8) {
|
|
302
|
+
return `${subscriber.slice(0, 3)} ${subscriber.slice(3, 6)} ${subscriber.slice(6)}`;
|
|
293
303
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
304
|
+
const firstGroupLength = subscriber.length % 2 === 1 ? 3 : 2;
|
|
305
|
+
const groups = [subscriber.slice(0, firstGroupLength)];
|
|
306
|
+
for (let i = firstGroupLength; i < subscriber.length; i += 2) {
|
|
307
|
+
groups.push(subscriber.slice(i, i + 2));
|
|
298
308
|
}
|
|
299
|
-
return
|
|
309
|
+
return groups.join(" ");
|
|
310
|
+
}
|
|
311
|
+
function splitSwedishNationalNumber(nationalSignificantNumber) {
|
|
312
|
+
const length = swedishDestinationCodeLength(nationalSignificantNumber);
|
|
313
|
+
return [nationalSignificantNumber.slice(0, length), nationalSignificantNumber.slice(length)];
|
|
314
|
+
}
|
|
315
|
+
function formatSwedishLocal(nationalSignificantNumber) {
|
|
316
|
+
const [destinationCode, subscriber] = splitSwedishNationalNumber(nationalSignificantNumber);
|
|
317
|
+
return `0${destinationCode}-${groupSwedishSubscriberNumber(subscriber)}`;
|
|
318
|
+
}
|
|
319
|
+
function formatSwedishInternational(nationalSignificantNumber) {
|
|
320
|
+
const [destinationCode, subscriber] = splitSwedishNationalNumber(nationalSignificantNumber);
|
|
321
|
+
return `+46 ${destinationCode} ${groupSwedishSubscriberNumber(subscriber)}`;
|
|
300
322
|
}
|
|
301
323
|
export {
|
|
302
324
|
PhoneNumber,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/contact/phone-number.ts"],
|
|
4
|
-
"sourcesContent": ["import { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { PrimitivesDefaults } from \"../primitives-defaults.js\";\nimport { sanitizeInput } from \"../internal/input-sanitization.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { Country } from \"../geography/index.js\";\nimport { PhoneCallingCode } from \"./phone-calling-code.js\";\n\nconst MAX_INPUT_LENGTH = 50;\nconst URI_PREFIXES = [\"callto:\", \"tel:\", \"sms:\", \"call:\"];\n\nconst TWO_DIGIT_CODES = new Set([\n \"20\",\n \"27\",\n \"30\",\n \"31\",\n \"32\",\n \"33\",\n \"34\",\n \"36\",\n \"39\",\n \"40\",\n \"41\",\n \"43\",\n \"44\",\n \"45\",\n \"46\",\n \"47\",\n \"48\",\n \"49\",\n \"51\",\n \"52\",\n \"53\",\n \"54\",\n \"55\",\n \"56\",\n \"57\",\n \"58\",\n \"60\",\n \"61\",\n \"62\",\n \"63\",\n \"64\",\n \"65\",\n \"66\",\n \"81\",\n \"82\",\n \"84\",\n \"86\",\n \"90\",\n \"91\",\n \"92\",\n \"93\",\n \"94\",\n \"95\",\n \"98\",\n]);\n\nconst LEADING_ZERO_SIGNIFICANT = new Set([\"39\"]);\n\nconst SCAN =\n /(?:(?:\\+|00)\\d{1,3}[\\s-]\\(?\\d{1,4}\\)?[\\s-]?\\d[\\d\\s-]{5,12}\\d)|(?:(?:\\+|00)\\d{7,15})|(?:0\\d{1,3}[\\s-]?\\d[\\d\\s-]{5,10}\\d)/g;\n\n/**\n * A phone number (`telefonnummer`). Stored normalized as `00` + country code +\n * subscriber digits (e.g. `0046701740633`). Use {@link toE164String} for the\n * `+`-prefixed E.164 form.\n */\nexport class PhoneNumber {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Phone Number\",\n localizedName: \"Telefonnummer\",\n emoji: \"\\u{1F4DE}\",\n sources: Object.freeze([\n \"https://pts.se/\",\n \"https://www.itu.int/rec/T-REC-E.164/\",\n \"https://en.wikipedia.org/wiki/E.164\",\n ]),\n });\n\n readonly digits: string;\n readonly countryCallingCode: PhoneCallingCode;\n readonly country: Country | null;\n readonly isSwedish: boolean;\n readonly isMobile: boolean;\n\n private constructor(digits: string, isSwedish: boolean, isMobile: boolean) {\n this.digits = digits;\n this.isSwedish = isSwedish;\n this.isMobile = isMobile;\n this.countryCallingCode = PhoneCallingCode.fromResolvedDigits(resolveCallingCode(digits));\n this.country = Country.tryFindByCallingCode(this.countryCallingCode.value);\n }\n\n get isSwedishTestPhoneNumber(): boolean {\n if (!this.isSwedish) return false;\n const local = this.digits.slice(4);\n return (\n isInPtsRange(local, \"7017406\", 5, 99) ||\n isInPtsRange(local, \"3139006\", 0, 99) ||\n isInPtsRange(local, \"4062804\", 0, 99) ||\n isInPtsRange(local, \"8465004\", 0, 99) ||\n isInPtsRange(local, \"9803192\", 0, 99)\n );\n }\n\n get formatted(): string {\n return this.isSwedish ? this.toLocalString() : this.toDisplayInternationalString();\n }\n\n static tryParse(\n input: string | null | undefined,\n defaultCallingCode?: string | PhoneCallingCode | Country | null,\n ): PhoneNumber | null {\n if (input == null || input.trim() === \"\") return null;\n const dcc = resolveDefaultCallingCode(defaultCallingCode);\n if (!dcc) return null;\n\n let cleaned = sanitizeInput(input).trim();\n if (cleaned.length > MAX_INPUT_LENGTH) return null;\n\n for (const prefix of URI_PREFIXES) {\n if (cleaned.toLowerCase().startsWith(prefix)) {\n cleaned = cleaned.slice(prefix.length).trimStart();\n break;\n }\n }\n\n const hasPlus = cleaned.startsWith(\"+\");\n const withOAs0 = cleaned.replace(/O/g, \"0\");\n const digitsOnly = withOAs0.replace(/[^\\d]/g, \"\");\n if (digitsOnly === \"\") return null;\n\n let e164: string;\n if (hasPlus) {\n if (digitsOnly.length < 7 || digitsOnly.length > 15) return null;\n e164 = stripTrunkZeroAfterCallingCode(digitsOnly);\n } else if (digitsOnly.startsWith(\"00\")) {\n const cn = digitsOnly.slice(2);\n if (cn.length < 7 || cn.length > 15) return null;\n e164 = stripTrunkZeroAfterCallingCode(cn);\n } else if (digitsOnly.startsWith(dcc) && digitsOnly.length >= dcc.length + 7) {\n const subscriber = digitsOnly.slice(dcc.length);\n e164 = dcc + stripSingleTrunkZero(dcc, subscriber);\n } else if (digitsOnly.startsWith(\"0\")) {\n const subscriber = stripSingleTrunkZero(dcc, digitsOnly);\n const total = dcc.length + subscriber.length;\n if (total < 7 || total > 15) return null;\n e164 = dcc + subscriber;\n } else if (dcc === \"46\" && digitsOnly.length === 9 && digitsOnly.startsWith(\"7\")) {\n e164 = \"46\" + digitsOnly;\n } else {\n return null;\n }\n\n if (e164.length < 7 || e164.length > 15) return null;\n const isSwedish = e164.startsWith(\"46\");\n if (isSwedish) {\n const local = e164.slice(2);\n if (local.length < 7 || local.length > 9) return null;\n }\n const isMobile = isSwedish && e164.slice(2).startsWith(\"7\");\n return new PhoneNumber(\"00\" + e164, isSwedish, isMobile);\n }\n\n static parse(\n input: string,\n defaultCallingCode?: string | PhoneCallingCode | Country | null,\n ): PhoneNumber {\n const r = PhoneNumber.tryParse(input, defaultCallingCode);\n if (r === null) throw new Error(\"Invalid phone number.\");\n return r;\n }\n\n static isValid(\n input: string | null | undefined,\n defaultCallingCode?: string | PhoneCallingCode | Country | null,\n ): boolean {\n return PhoneNumber.tryParse(input, defaultCallingCode) !== null;\n }\n\n static format(\n input: string | null | undefined,\n options?: {\n defaultCallingCode?: string | PhoneCallingCode | Country | null;\n fallbackToTrimmedInputWhenInvalid?: boolean;\n },\n ): string | null {\n const dcc =\n resolveDefaultCallingCode(options?.defaultCallingCode) ??\n PrimitivesDefaults.defaultCallingCode;\n const r = PhoneNumber.tryParse(input, dcc);\n if (r) {\n return r.countryCallingCode.value === dcc\n ? r.toLocalString()\n : r.toDisplayInternationalString();\n }\n if (options?.fallbackToTrimmedInputWhenInvalid && input != null && input.trim() !== \"\") {\n return input.trim();\n }\n return null;\n }\n\n static normalize(\n input: string | null | undefined,\n options?: {\n defaultCallingCode?: string | PhoneCallingCode | Country | null;\n fallbackToTrimmedInputWhenInvalid?: boolean;\n },\n ): string | null {\n const r = PhoneNumber.tryParse(input, options?.defaultCallingCode);\n if (r) return r.digits;\n if (options?.fallbackToTrimmedInputWhenInvalid && input != null) {\n const t = input.trim();\n return t.length > 0 ? t : null;\n }\n return null;\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && PhoneNumber.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<PhoneNumber>[] {\n if (!text) return [];\n const out: TextCandidate<PhoneNumber>[] = [];\n SCAN.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = SCAN.exec(text)) !== null) {\n const phone = PhoneNumber.tryParse(m[0]);\n if (!phone) continue;\n out.push(\n new TextCandidate<PhoneNumber>({\n startIndex: m.index,\n length: m[0].length,\n originalText: m[0],\n typeName: \"PhoneNumber\",\n category: TextCandidateCategory.Contact,\n normalizedForm: phone.toNormalizedString(),\n formattedForm: phone.toString(),\n maskedForm: maskPhoneNumber(phone),\n confidence: TextMatchConfidence.Medium,\n value: phone,\n }),\n );\n }\n return out;\n }\n\n toNormalizedString(): string {\n return this.digits;\n }\n\n toLocalString(defaultCallingCode?: PhoneCallingCode | Country): string {\n if (defaultCallingCode) {\n const dcc =\n defaultCallingCode instanceof PhoneCallingCode\n ? defaultCallingCode.value\n : defaultCallingCode.callingCode;\n return this.countryCallingCode.value === dcc\n ? this.toLocalString()\n : this.toDisplayInternationalString();\n }\n const subscriber = this.digits.slice(2 + this.countryCallingCode.value.length);\n if (this.isSwedish) return formatSwedishLocal(\"0\" + subscriber);\n return \"0\" + subscriber;\n }\n\n toE164String(): string {\n return \"+\" + this.digits.slice(2);\n }\n toInternationalString(): string {\n return this.toE164String();\n }\n\n toDisplayInternationalString(): string {\n const subscriber = this.digits.slice(2 + this.countryCallingCode.value.length);\n return (\n \"+\" +\n this.countryCallingCode.value +\n \" \" +\n formatInternationalSubscriberDigits(this.countryCallingCode.value, subscriber)\n );\n }\n\n toString(): string {\n return this.formatted;\n }\n\n equals(other: PhoneNumber | null | undefined): boolean {\n return other != null && this.digits === other.digits;\n }\n compareTo(other: PhoneNumber | null | undefined): number {\n if (other == null) return 1;\n return this.digits < other.digits ? -1 : this.digits > other.digits ? 1 : 0;\n }\n}\n\n/** Mask a phone number, keeping country code and last 4 digits visible. */\nexport function maskPhoneNumber(p: PhoneNumber): string {\n const f = p.toE164String();\n if (f.length <= 5) return f.replace(/\\d/g, \"*\");\n const cc = \"+\" + p.countryCallingCode.value;\n const subscriber = f.slice(cc.length);\n if (subscriber.length <= 4) return cc + \"*\".repeat(subscriber.length);\n return cc + \"*\".repeat(subscriber.length - 4) + subscriber.slice(-4);\n}\n\nfunction resolveDefaultCallingCode(\n d: string | PhoneCallingCode | Country | null | undefined,\n): string | null {\n if (d == null) return PrimitivesDefaults.defaultCallingCode;\n if (typeof d === \"string\") return d;\n if (d instanceof PhoneCallingCode) return d.value;\n return d.callingCode;\n}\n\nfunction resolveCallingCode(digits: string): string {\n return resolveCallingCodeFromE164(digits.slice(2));\n}\n\nfunction resolveCallingCodeFromE164(e164: string): string {\n if (e164.length === 0) return \"\";\n if (e164[0] === \"1\" || e164[0] === \"7\") return e164.slice(0, 1);\n if (e164.length >= 2 && TWO_DIGIT_CODES.has(e164.slice(0, 2))) return e164.slice(0, 2);\n return e164.length >= 3 ? e164.slice(0, 3) : e164;\n}\n\nfunction stripTrunkZeroAfterCallingCode(e164: string): string {\n const cc = resolveCallingCodeFromE164(e164);\n if (cc.length === 0 || cc.length >= e164.length) return e164;\n const subscriber = e164.slice(cc.length);\n return cc + stripSingleTrunkZero(cc, subscriber);\n}\n\nfunction stripSingleTrunkZero(callingCode: string, subscriber: string): string {\n if (subscriber.length === 0 || subscriber[0] !== \"0\") return subscriber;\n if (LEADING_ZERO_SIGNIFICANT.has(callingCode)) return subscriber;\n return subscriber.slice(1);\n}\n\nfunction isInPtsRange(local: string, prefix: string, from: number, to: number): boolean {\n if (!local.startsWith(prefix)) return false;\n const suffix = local.slice(prefix.length);\n if (suffix.length !== 2) return false;\n const n = parseInt(suffix, 10);\n return Number.isFinite(n) && n >= from && n <= to;\n}\n\nfunction formatInternationalSubscriberDigits(callingCode: string, digits: string): string {\n if (callingCode === \"1\" && digits.length === 10) {\n return `${digits.slice(0, 3)} ${digits.slice(3, 6)} ${digits.slice(6, 10)}`;\n }\n switch (digits.length) {\n case 7:\n return `${digits.slice(0, 3)} ${digits.slice(3, 5)} ${digits.slice(5, 7)}`;\n case 8:\n return `${digits.slice(0, 2)} ${digits.slice(2, 4)} ${digits.slice(4, 6)} ${digits.slice(6, 8)}`;\n case 9:\n return `${digits.slice(0, 2)} ${digits.slice(2, 5)} ${digits.slice(5, 7)} ${digits.slice(7, 9)}`;\n case 10:\n return `${digits.slice(0, 2)} ${digits.slice(2, 6)} ${digits.slice(6, 10)}`;\n case 11:\n return `${digits.slice(0, 3)} ${digits.slice(3, 7)} ${digits.slice(7, 11)}`;\n default:\n return digits;\n }\n}\n\nfunction formatSwedishLocal(number: string): string {\n const digits = number.replace(/^0+/, \"\");\n if (digits.length === 9) {\n return `0${digits.slice(0, 3)}-${digits.slice(3, 5)} ${digits.slice(5, 7)} ${digits.slice(7, 9)}`;\n }\n if (digits.length === 7) {\n const area = digits.slice(0, 1);\n const rest = digits.slice(1);\n return `0${area}-${rest.slice(0, 2)} ${rest.slice(2, 4)} ${rest.slice(4, 6)}`;\n }\n if (digits.length === 8) {\n const area = digits.slice(0, 1);\n const rest = digits.slice(1);\n return `0${area}-${rest.slice(0, 2)} ${rest.slice(2, 4)} ${rest.slice(4, 7)}`;\n }\n return number;\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { PrimitivesDefaults } from \"../primitives-defaults.js\";\nimport { sanitizeInput } from \"../internal/input-sanitization.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { Country } from \"../geography/index.js\";\nimport { PhoneCallingCode } from \"./phone-calling-code.js\";\n\nconst MAX_INPUT_LENGTH = 50;\nconst URI_PREFIXES = [\"callto:\", \"tel:\", \"sms:\", \"call:\"];\n\nconst TWO_DIGIT_CODES = new Set([\n \"20\",\n \"27\",\n \"30\",\n \"31\",\n \"32\",\n \"33\",\n \"34\",\n \"36\",\n \"39\",\n \"40\",\n \"41\",\n \"43\",\n \"44\",\n \"45\",\n \"46\",\n \"47\",\n \"48\",\n \"49\",\n \"51\",\n \"52\",\n \"53\",\n \"54\",\n \"55\",\n \"56\",\n \"57\",\n \"58\",\n \"60\",\n \"61\",\n \"62\",\n \"63\",\n \"64\",\n \"65\",\n \"66\",\n \"81\",\n \"82\",\n \"84\",\n \"86\",\n \"90\",\n \"91\",\n \"92\",\n \"93\",\n \"94\",\n \"95\",\n \"98\",\n]);\n\nconst LEADING_ZERO_SIGNIFICANT = new Set([\"39\"]);\n\nconst SCAN =\n /(?:(?:\\+|00)\\d{1,3}[\\s-]\\(?\\d{1,4}\\)?[\\s-]?\\d[\\d\\s-]{5,12}\\d)|(?:(?:\\+|00)\\d{7,15})|(?:0\\d{1,3}[\\s-]?\\d[\\d\\s-]{5,10}\\d)/g;\n\n/**\n * A phone number (`telefonnummer`). Stored normalized as `00` + country code +\n * subscriber digits (e.g. `0046701740633`). Use {@link toE164String} for the\n * `+`-prefixed E.164 form.\n */\nexport class PhoneNumber {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Phone Number\",\n localizedName: \"Telefonnummer\",\n emoji: \"\\u{1F4DE}\",\n sources: Object.freeze([\n \"https://pts.se/\",\n \"https://www.itu.int/rec/T-REC-E.164/\",\n \"https://en.wikipedia.org/wiki/E.164\",\n ]),\n });\n\n readonly digits: string;\n readonly countryCallingCode: PhoneCallingCode;\n readonly country: Country | null;\n readonly isSwedish: boolean;\n readonly isMobile: boolean;\n\n private constructor(digits: string, isSwedish: boolean, isMobile: boolean) {\n this.digits = digits;\n this.isSwedish = isSwedish;\n this.isMobile = isMobile;\n this.countryCallingCode = PhoneCallingCode.fromResolvedDigits(resolveCallingCode(digits));\n this.country = Country.tryFindByCallingCode(this.countryCallingCode.value);\n }\n\n get isSwedishTestPhoneNumber(): boolean {\n if (!this.isSwedish) return false;\n const local = this.digits.slice(4);\n return (\n isInPtsRange(local, \"7017406\", 5, 99) ||\n isInPtsRange(local, \"3139006\", 0, 99) ||\n isInPtsRange(local, \"4062804\", 0, 99) ||\n isInPtsRange(local, \"8465004\", 0, 99) ||\n isInPtsRange(local, \"9803192\", 0, 99)\n );\n }\n\n get formatted(): string {\n return this.isSwedish ? this.toLocalString() : this.toDisplayInternationalString();\n }\n\n static tryParse(\n input: string | null | undefined,\n defaultCallingCode?: string | PhoneCallingCode | Country | null,\n ): PhoneNumber | null {\n if (input == null || input.trim() === \"\") return null;\n const dcc = resolveDefaultCallingCode(defaultCallingCode);\n if (!dcc) return null;\n\n let cleaned = sanitizeInput(input).trim();\n if (cleaned.length > MAX_INPUT_LENGTH) return null;\n\n for (const prefix of URI_PREFIXES) {\n if (cleaned.toLowerCase().startsWith(prefix)) {\n cleaned = cleaned.slice(prefix.length).trimStart();\n break;\n }\n }\n\n const hasPlus = cleaned.startsWith(\"+\");\n const withOAs0 = cleaned.replace(/O/g, \"0\");\n const digitsOnly = withOAs0.replace(/[^\\d]/g, \"\");\n if (digitsOnly === \"\") return null;\n\n let e164: string;\n if (hasPlus) {\n if (digitsOnly.length < 7 || digitsOnly.length > 15) return null;\n e164 = stripTrunkZeroAfterCallingCode(digitsOnly);\n } else if (digitsOnly.startsWith(\"00\")) {\n const cn = digitsOnly.slice(2);\n if (cn.length < 7 || cn.length > 15) return null;\n e164 = stripTrunkZeroAfterCallingCode(cn);\n } else if (digitsOnly.startsWith(dcc) && digitsOnly.length >= dcc.length + 7) {\n const subscriber = digitsOnly.slice(dcc.length);\n e164 = dcc + stripSingleTrunkZero(dcc, subscriber);\n } else if (digitsOnly.startsWith(\"0\")) {\n const subscriber = stripSingleTrunkZero(dcc, digitsOnly);\n const total = dcc.length + subscriber.length;\n if (total < 7 || total > 15) return null;\n e164 = dcc + subscriber;\n } else if (dcc === \"46\" && digitsOnly.length === 9 && digitsOnly.startsWith(\"7\")) {\n e164 = \"46\" + digitsOnly;\n } else {\n return null;\n }\n\n if (e164.length < 7 || e164.length > 15) return null;\n const isSwedish = e164.startsWith(\"46\");\n if (isSwedish) {\n const local = e164.slice(2);\n if (local.length < 7 || local.length > 9) return null;\n }\n const isMobile = isSwedish && e164.slice(2).startsWith(\"7\");\n return new PhoneNumber(\"00\" + e164, isSwedish, isMobile);\n }\n\n static parse(\n input: string,\n defaultCallingCode?: string | PhoneCallingCode | Country | null,\n ): PhoneNumber {\n const r = PhoneNumber.tryParse(input, defaultCallingCode);\n if (r === null) throw new Error(\"Invalid phone number.\");\n return r;\n }\n\n static isValid(\n input: string | null | undefined,\n defaultCallingCode?: string | PhoneCallingCode | Country | null,\n ): boolean {\n return PhoneNumber.tryParse(input, defaultCallingCode) !== null;\n }\n\n static format(\n input: string | null | undefined,\n options?: {\n defaultCallingCode?: string | PhoneCallingCode | Country | null;\n fallbackToTrimmedInputWhenInvalid?: boolean;\n },\n ): string | null {\n const dcc =\n resolveDefaultCallingCode(options?.defaultCallingCode) ??\n PrimitivesDefaults.defaultCallingCode;\n const r = PhoneNumber.tryParse(input, dcc);\n if (r) {\n return r.countryCallingCode.value === dcc\n ? r.toLocalString()\n : r.toDisplayInternationalString();\n }\n if (options?.fallbackToTrimmedInputWhenInvalid && input != null && input.trim() !== \"\") {\n return input.trim();\n }\n return null;\n }\n\n static normalize(\n input: string | null | undefined,\n options?: {\n defaultCallingCode?: string | PhoneCallingCode | Country | null;\n fallbackToTrimmedInputWhenInvalid?: boolean;\n },\n ): string | null {\n const r = PhoneNumber.tryParse(input, options?.defaultCallingCode);\n if (r) return r.digits;\n if (options?.fallbackToTrimmedInputWhenInvalid && input != null) {\n const t = input.trim();\n return t.length > 0 ? t : null;\n }\n return null;\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && PhoneNumber.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<PhoneNumber>[] {\n if (!text) return [];\n const out: TextCandidate<PhoneNumber>[] = [];\n SCAN.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = SCAN.exec(text)) !== null) {\n const phone = PhoneNumber.tryParse(m[0]);\n if (!phone) continue;\n out.push(\n new TextCandidate<PhoneNumber>({\n startIndex: m.index,\n length: m[0].length,\n originalText: m[0],\n typeName: \"PhoneNumber\",\n category: TextCandidateCategory.Contact,\n normalizedForm: phone.toNormalizedString(),\n formattedForm: phone.toString(),\n maskedForm: maskPhoneNumber(phone),\n confidence: TextMatchConfidence.Medium,\n value: phone,\n }),\n );\n }\n return out;\n }\n\n toNormalizedString(): string {\n return this.digits;\n }\n\n toLocalString(defaultCallingCode?: PhoneCallingCode | Country): string {\n if (defaultCallingCode) {\n const dcc =\n defaultCallingCode instanceof PhoneCallingCode\n ? defaultCallingCode.value\n : defaultCallingCode.callingCode;\n return this.countryCallingCode.value === dcc\n ? this.toLocalString()\n : this.toDisplayInternationalString();\n }\n const subscriber = this.digits.slice(2 + this.countryCallingCode.value.length);\n if (this.isSwedish) return formatSwedishLocal(subscriber);\n return \"0\" + subscriber;\n }\n\n toE164String(): string {\n return \"+\" + this.digits.slice(2);\n }\n toInternationalString(): string {\n return this.toE164String();\n }\n\n toDisplayInternationalString(): string {\n const subscriber = this.digits.slice(2 + this.countryCallingCode.value.length);\n if (this.isSwedish) return formatSwedishInternational(subscriber);\n return (\n \"+\" +\n this.countryCallingCode.value +\n \" \" +\n formatInternationalSubscriberDigits(this.countryCallingCode.value, subscriber)\n );\n }\n\n toString(): string {\n return this.formatted;\n }\n\n equals(other: PhoneNumber | null | undefined): boolean {\n return other != null && this.digits === other.digits;\n }\n compareTo(other: PhoneNumber | null | undefined): number {\n if (other == null) return 1;\n return this.digits < other.digits ? -1 : this.digits > other.digits ? 1 : 0;\n }\n}\n\n/** Mask a phone number, keeping country code and last 4 digits visible. */\nexport function maskPhoneNumber(p: PhoneNumber): string {\n const f = p.toE164String();\n if (f.length <= 5) return f.replace(/\\d/g, \"*\");\n const cc = \"+\" + p.countryCallingCode.value;\n const subscriber = f.slice(cc.length);\n if (subscriber.length <= 4) return cc + \"*\".repeat(subscriber.length);\n return cc + \"*\".repeat(subscriber.length - 4) + subscriber.slice(-4);\n}\n\nfunction resolveDefaultCallingCode(\n d: string | PhoneCallingCode | Country | null | undefined,\n): string | null {\n if (d == null) return PrimitivesDefaults.defaultCallingCode;\n if (typeof d === \"string\") return d;\n if (d instanceof PhoneCallingCode) return d.value;\n return d.callingCode;\n}\n\nfunction resolveCallingCode(digits: string): string {\n return resolveCallingCodeFromE164(digits.slice(2));\n}\n\nfunction resolveCallingCodeFromE164(e164: string): string {\n if (e164.length === 0) return \"\";\n if (e164[0] === \"1\" || e164[0] === \"7\") return e164.slice(0, 1);\n if (e164.length >= 2 && TWO_DIGIT_CODES.has(e164.slice(0, 2))) return e164.slice(0, 2);\n return e164.length >= 3 ? e164.slice(0, 3) : e164;\n}\n\nfunction stripTrunkZeroAfterCallingCode(e164: string): string {\n const cc = resolveCallingCodeFromE164(e164);\n if (cc.length === 0 || cc.length >= e164.length) return e164;\n const subscriber = e164.slice(cc.length);\n return cc + stripSingleTrunkZero(cc, subscriber);\n}\n\nfunction stripSingleTrunkZero(callingCode: string, subscriber: string): string {\n if (subscriber.length === 0 || subscriber[0] !== \"0\") return subscriber;\n if (LEADING_ZERO_SIGNIFICANT.has(callingCode)) return subscriber;\n return subscriber.slice(1);\n}\n\nfunction isInPtsRange(local: string, prefix: string, from: number, to: number): boolean {\n if (!local.startsWith(prefix)) return false;\n const suffix = local.slice(prefix.length);\n if (suffix.length !== 2) return false;\n const n = parseInt(suffix, 10);\n return Number.isFinite(n) && n >= from && n <= to;\n}\n\nfunction formatInternationalSubscriberDigits(callingCode: string, digits: string): string {\n if (callingCode === \"1\" && digits.length === 10) {\n return `${digits.slice(0, 3)} ${digits.slice(3, 6)} ${digits.slice(6, 10)}`;\n }\n switch (digits.length) {\n case 7:\n return `${digits.slice(0, 3)} ${digits.slice(3, 5)} ${digits.slice(5, 7)}`;\n case 8:\n return `${digits.slice(0, 2)} ${digits.slice(2, 4)} ${digits.slice(4, 6)} ${digits.slice(6, 8)}`;\n case 9:\n return `${digits.slice(0, 2)} ${digits.slice(2, 5)} ${digits.slice(5, 7)} ${digits.slice(7, 9)}`;\n case 10:\n return `${digits.slice(0, 2)} ${digits.slice(2, 6)} ${digits.slice(6, 10)}`;\n case 11:\n return `${digits.slice(0, 3)} ${digits.slice(3, 7)} ${digits.slice(7, 11)}`;\n default:\n return digits;\n }\n}\n\n// Two-digit national destination codes (NDCs) from PTS's numbering plan. 8 (Stockholm) is the\n// only one-digit NDC; every NDC not listed here is three digits.\nconst SWEDISH_TWO_DIGIT_DESTINATION_CODES = new Set([\n ...\"11 13 16 18 19 21 23 26 31 33 35 36 40 42 44 46 54 60 63 90\".split(\" \"),\n ...\"10 20 70 71 72 73 74 75 76 77 79 99\".split(\" \"),\n]);\n\n// 900 (premium rate) is the only three-digit NDC that starts with a two-digit NDC (90, Ume\u00E5).\nconst SWEDISH_THREE_DIGIT_DESTINATION_CODES_OVERRIDING_TWO_DIGIT = new Set([\"900\"]);\n\nfunction swedishDestinationCodeLength(nationalSignificantNumber: string): number {\n if (nationalSignificantNumber.startsWith(\"8\")) return 1;\n if (\n SWEDISH_THREE_DIGIT_DESTINATION_CODES_OVERRIDING_TWO_DIGIT.has(\n nationalSignificantNumber.slice(0, 3),\n )\n ) {\n return 3;\n }\n if (SWEDISH_TWO_DIGIT_DESTINATION_CODES.has(nationalSignificantNumber.slice(0, 2))) return 2;\n return 3;\n}\n\n/**\n * Groups a Swedish subscriber number as recommended by Svenska skrivregler:\n * `NN NN`, `NNN NN`, `NN NN NN`, `NNN NN NN` and `NNN NNN NN`.\n */\nfunction groupSwedishSubscriberNumber(subscriber: string): string {\n if (subscriber.length === 8) {\n return `${subscriber.slice(0, 3)} ${subscriber.slice(3, 6)} ${subscriber.slice(6)}`;\n }\n const firstGroupLength = subscriber.length % 2 === 1 ? 3 : 2;\n const groups = [subscriber.slice(0, firstGroupLength)];\n for (let i = firstGroupLength; i < subscriber.length; i += 2) {\n groups.push(subscriber.slice(i, i + 2));\n }\n return groups.join(\" \");\n}\n\nfunction splitSwedishNationalNumber(nationalSignificantNumber: string): [string, string] {\n const length = swedishDestinationCodeLength(nationalSignificantNumber);\n return [nationalSignificantNumber.slice(0, length), nationalSignificantNumber.slice(length)];\n}\n\nfunction formatSwedishLocal(nationalSignificantNumber: string): string {\n const [destinationCode, subscriber] = splitSwedishNationalNumber(nationalSignificantNumber);\n return `0${destinationCode}-${groupSwedishSubscriberNumber(subscriber)}`;\n}\n\nfunction formatSwedishInternational(nationalSignificantNumber: string): string {\n const [destinationCode, subscriber] = splitSwedishNationalNumber(nationalSignificantNumber);\n return `+46 ${destinationCode} ${groupSwedishSubscriberNumber(subscriber)}`;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|