- Delete old Vite+Svelte frontend - Initialize new SvelteKit project with TypeScript - Configure Tailwind CSS v4 + DaisyUI - Implement JWT authentication with auto-refresh - Create login page with form validation (Zod) - Add protected route guards - Update Docker configuration for single-stage build - Add E2E tests with Playwright (6/11 passing) - Fix Svelte 5 reactivity with $state() runes Known issues: - 5 E2E tests failing (timing/async issues) - Token refresh implementation needs debugging - Validation error display timing
219 lines
11 KiB
JavaScript
219 lines
11 KiB
JavaScript
"use strict";
|
|
|
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.chooseFormatForNumber = chooseFormatForNumber;
|
|
exports["default"] = formatNumber;
|
|
var _matchesEntirely = _interopRequireDefault(require("./helpers/matchesEntirely.js"));
|
|
var _formatNationalNumberUsingFormat = _interopRequireDefault(require("./helpers/formatNationalNumberUsingFormat.js"));
|
|
var _metadata = _interopRequireWildcard(require("./metadata.js"));
|
|
var _getIddPrefix = _interopRequireDefault(require("./helpers/getIddPrefix.js"));
|
|
var _RFC = require("./helpers/RFC3966.js");
|
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
// This is a port of Google Android `libphonenumber`'s
|
|
// `phonenumberutil.js` of December 31th, 2018.
|
|
//
|
|
// https://github.com/googlei18n/libphonenumber/commits/master/javascript/i18n/phonenumbers/phonenumberutil.js
|
|
|
|
var DEFAULT_OPTIONS = {
|
|
formatExtension: function formatExtension(formattedNumber, extension, metadata) {
|
|
return "".concat(formattedNumber).concat(metadata.ext()).concat(extension);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Formats a phone number.
|
|
*
|
|
* format(phoneNumberInstance, 'INTERNATIONAL', { ..., v2: true }, metadata)
|
|
* format(phoneNumberInstance, 'NATIONAL', { ..., v2: true }, metadata)
|
|
*
|
|
* format({ phone: '8005553535', country: 'RU' }, 'INTERNATIONAL', { ... }, metadata)
|
|
* format({ phone: '8005553535', country: 'RU' }, 'NATIONAL', undefined, metadata)
|
|
*
|
|
* @param {object|PhoneNumber} input — If `options.v2: true` flag is passed, the `input` should be a `PhoneNumber` instance. Otherwise, it should be an object of shape `{ phone: '...', country: '...' }`.
|
|
* @param {string} format
|
|
* @param {object} [options]
|
|
* @param {object} metadata
|
|
* @return {string}
|
|
*/
|
|
function formatNumber(input, format, options, metadata) {
|
|
// Apply default options.
|
|
if (options) {
|
|
// Using ES6 "rest spread" syntax here didn't work with `babel`/`istanbul`
|
|
// for some weird reason: this line of code would cause the code coverage
|
|
// to show as not 100%. That's because `babel`/`istanbul`, for some weird reason,
|
|
// apparently doesn't know how to properly exclude Babel polyfills from code coverage.
|
|
//
|
|
// options = { ...DEFAULT_OPTIONS, ...options }
|
|
//
|
|
options = merge({}, DEFAULT_OPTIONS, options);
|
|
} else {
|
|
options = DEFAULT_OPTIONS;
|
|
}
|
|
metadata = new _metadata["default"](metadata);
|
|
|
|
// Normally, the `input` object is supposed to be a `PhoneNumber` class instance.
|
|
// Also, according to the `PhoneNumber` class source code, `country` can't be "001".
|
|
// It means that normally `input.country` or `input.countryCallingCode` is supposed
|
|
// to be present because either of the two is always required to exist in a `PhoneNumber` instance.
|
|
// This means that realistically, it's gonna step into either the first `if`
|
|
// or the following `else if`, and normally it won't even reach the legacy-compatibility
|
|
// `else return input.phone || ''` part.
|
|
// So normally, it won't ever return an empty string here.
|
|
if (input.country && input.country !== '001') {
|
|
// Validate `input.country`.
|
|
if (!metadata.hasCountry(input.country)) {
|
|
throw new Error("Unknown country: ".concat(input.country));
|
|
}
|
|
metadata.selectNumberingPlan(input.country);
|
|
} else if (input.countryCallingCode) {
|
|
metadata.selectNumberingPlan(input.countryCallingCode);
|
|
} else return input.phone || '';
|
|
var countryCallingCode = metadata.countryCallingCode();
|
|
var nationalNumber = options.v2 ? input.nationalNumber : input.phone;
|
|
|
|
// This variable should have been declared inside `case`s
|
|
// but Babel has a bug and it says "duplicate variable declaration".
|
|
var number;
|
|
switch (format) {
|
|
case 'NATIONAL':
|
|
// Normally, the `input` object is supposed to be a `PhoneNumber` class instance,
|
|
// and a `PhoneNumber` class instance is always required to have a `nationalNumber`.
|
|
// This means that the `if (!nationalNumber)` below is just for legacy-compatibility
|
|
// and it normally can't really happen, so normally it won't ever return an empty string here.
|
|
if (!nationalNumber) {
|
|
return '';
|
|
}
|
|
number = formatNationalNumber(nationalNumber, input.carrierCode, 'NATIONAL', metadata, options);
|
|
return addExtension(number, input.ext, metadata, options.formatExtension);
|
|
case 'INTERNATIONAL':
|
|
// Legacy argument support.
|
|
// (`{ country: ..., phone: '' }`)
|
|
if (!nationalNumber) {
|
|
return "+".concat(countryCallingCode);
|
|
}
|
|
number = formatNationalNumber(nationalNumber, null, 'INTERNATIONAL', metadata, options);
|
|
number = "+".concat(countryCallingCode, " ").concat(number);
|
|
return addExtension(number, input.ext, metadata, options.formatExtension);
|
|
case 'E.164':
|
|
// `E.164` doesn't define "phone number extensions".
|
|
return "+".concat(countryCallingCode).concat(nationalNumber);
|
|
case 'RFC3966':
|
|
return (0, _RFC.formatRFC3966)({
|
|
number: "+".concat(countryCallingCode).concat(nationalNumber),
|
|
ext: input.ext
|
|
});
|
|
|
|
// For reference, here's Google's IDD formatter:
|
|
// https://github.com/google/libphonenumber/blob/32719cf74e68796788d1ca45abc85dcdc63ba5b9/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java#L1546
|
|
// Not saying that this IDD formatter replicates it 1:1, but it seems to work.
|
|
// Who would even need to format phone numbers in IDD format anyway?
|
|
case 'IDD':
|
|
// If the required `fromCountry` parameter is not passed, it will return `undefined`.
|
|
if (!options.fromCountry) {
|
|
return;
|
|
// throw new Error('`fromCountry` option not passed for IDD-prefixed formatting.')
|
|
}
|
|
var formattedNumber = formatIDD(nationalNumber, input.carrierCode, countryCallingCode, options.fromCountry, metadata);
|
|
// If the country of the phone number doesn't support IDD calling, it will return `undefined`.
|
|
if (!formattedNumber) {
|
|
return;
|
|
}
|
|
return addExtension(formattedNumber, input.ext, metadata, options.formatExtension);
|
|
default:
|
|
throw new Error("Unknown \"format\" argument passed to \"formatNumber()\": \"".concat(format, "\""));
|
|
}
|
|
}
|
|
function formatNationalNumber(number, carrierCode, formatAs, metadata, options) {
|
|
var format = chooseFormatForNumber(metadata.formats(), number);
|
|
if (!format) {
|
|
return number;
|
|
}
|
|
return (0, _formatNationalNumberUsingFormat["default"])(number, format, {
|
|
useInternationalFormat: formatAs === 'INTERNATIONAL',
|
|
withNationalPrefix: format.nationalPrefixIsOptionalWhenFormattingInNationalFormat() && options && options.nationalPrefix === false ? false : true,
|
|
carrierCode: carrierCode,
|
|
metadata: metadata
|
|
});
|
|
}
|
|
function chooseFormatForNumber(availableFormats, nationalNumber) {
|
|
// Using a `for ... of` loop here didn't work with `babel`/`istanbul`:
|
|
// for some weird reason, it showed code coverage less than 100%.
|
|
// That's because `babel`/`istanbul`, for some weird reason,
|
|
// apparently doesn't know how to properly exclude Babel polyfills from code coverage.
|
|
//
|
|
// for (const format of availableFormats) { ... }
|
|
//
|
|
return pickFirstMatchingElement(availableFormats, function (format) {
|
|
// Validate leading digits.
|
|
// The test case for "else path" could be found by searching for
|
|
// "format.leadingDigitsPatterns().length === 0".
|
|
if (format.leadingDigitsPatterns().length > 0) {
|
|
// The last leading_digits_pattern is used here, as it is the most detailed
|
|
var lastLeadingDigitsPattern = format.leadingDigitsPatterns()[format.leadingDigitsPatterns().length - 1];
|
|
// If leading digits don't match then move on to the next phone number format
|
|
if (nationalNumber.search(lastLeadingDigitsPattern) !== 0) {
|
|
return false;
|
|
}
|
|
}
|
|
// Check that the national number matches the phone number format regular expression
|
|
return (0, _matchesEntirely["default"])(nationalNumber, format.pattern());
|
|
});
|
|
}
|
|
function addExtension(formattedNumber, ext, metadata, formatExtension) {
|
|
return ext ? formatExtension(formattedNumber, ext, metadata) : formattedNumber;
|
|
}
|
|
function formatIDD(nationalNumber, carrierCode, countryCallingCode, fromCountry, metadata) {
|
|
var fromCountryCallingCode = (0, _metadata.getCountryCallingCode)(fromCountry, metadata.metadata);
|
|
// When calling within the same country calling code.
|
|
if (fromCountryCallingCode === countryCallingCode) {
|
|
var formattedNumber = formatNationalNumber(nationalNumber, carrierCode, 'NATIONAL', metadata);
|
|
// For NANPA regions, return the national format for these regions
|
|
// but prefix it with the country calling code.
|
|
if (countryCallingCode === '1') {
|
|
return countryCallingCode + ' ' + formattedNumber;
|
|
}
|
|
// If regions share a country calling code, the country calling code need
|
|
// not be dialled. This also applies when dialling within a region, so this
|
|
// if clause covers both these cases. Technically this is the case for
|
|
// dialling from La Reunion to other overseas departments of France (French
|
|
// Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover
|
|
// this edge case for now and for those cases return the version including
|
|
// country calling code. Details here:
|
|
// http://www.petitfute.com/voyage/225-info-pratiques-reunion
|
|
//
|
|
return formattedNumber;
|
|
}
|
|
var iddPrefix = (0, _getIddPrefix["default"])(fromCountry, undefined, metadata.metadata);
|
|
if (iddPrefix) {
|
|
return "".concat(iddPrefix, " ").concat(countryCallingCode, " ").concat(formatNationalNumber(nationalNumber, null, 'INTERNATIONAL', metadata));
|
|
}
|
|
}
|
|
function merge() {
|
|
var i = 1;
|
|
for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
objects[_key] = arguments[_key];
|
|
}
|
|
while (i < objects.length) {
|
|
if (objects[i]) {
|
|
for (var key in objects[i]) {
|
|
objects[0][key] = objects[i][key];
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
return objects[0];
|
|
}
|
|
function pickFirstMatchingElement(elements, testFunction) {
|
|
var i = 0;
|
|
while (i < elements.length) {
|
|
if (testFunction(elements[i])) {
|
|
return elements[i];
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
//# sourceMappingURL=format.js.map
|