UNPKG

@lacussoft/cpf-fmt

Version:

Utility to format CPF (Brazilian Individual's Taxpayer ID)

828 lines (811 loc) 132 kB
/** * Lacus Solutions :: cpf-fmt v3.0.0 * * @author Julio L. Muller. * @license MIT - 2021-2026 */ 'use strict'; var utils = require('@lacussoft/utils'); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; /** * Base error class for all `cpf-fmt` type-related errors. * * This abstract class extends the native `TypeError` and serves as the base for * all type validation errors in the CPF formatter. It ensures proper prototype * chain setup and automatically sets the error name from the constructor. */ var CpfFormatterTypeError = /** @class */ (function (_super) { __extends(CpfFormatterTypeError, _super); function CpfFormatterTypeError(actualInput, actualType, expectedType, message) { var _newTarget = this.constructor; var _this = _super.call(this, message) || this; Object.setPrototypeOf(_this, _newTarget.prototype); _this.name = _this.constructor.name; _this.actualInput = actualInput; _this.actualType = actualType; _this.expectedType = expectedType; return _this; } return CpfFormatterTypeError; }(TypeError)); /** * Error raised when the input provided to the CPF formatter is not of the * expected type {@link CpfInput}. The error message includes both the actual * input type and the expected type. */ var CpfFormatterInputTypeError = /** @class */ (function (_super) { __extends(CpfFormatterInputTypeError, _super); function CpfFormatterInputTypeError(actualInput, expectedType) { var actualInputType = utils.describeType(actualInput); return _super.call(this, actualInput, actualInputType, expectedType, "CPF input must be of type ".concat(expectedType, ". Got ").concat(actualInputType, ".")) || this; } return CpfFormatterInputTypeError; }(CpfFormatterTypeError)); /** * Error raised when a specific option in the formatter configuration has an * invalid type. The error message includes the option name, the actual input * type and the expected type. */ var CpfFormatterOptionsTypeError = /** @class */ (function (_super) { __extends(CpfFormatterOptionsTypeError, _super); function CpfFormatterOptionsTypeError(optionName, actualInput, expectedType) { var _this = this; var actualInputType = utils.describeType(actualInput); _this = _super.call(this, actualInput, actualInputType, expectedType, "CPF formatting option \"".concat(optionName, "\" must be of type ").concat(expectedType, ". Got ").concat(actualInputType, ".")) || this; _this.optionName = optionName; return _this; } return CpfFormatterOptionsTypeError; }(CpfFormatterTypeError)); /** * Base exception for all `cpf-fmt` rules-related errors. * * This abstract class extends the native `Error` and serves as the base for all * non-type-related errors in the `CpfFormatter` and its dependencies. It is * suitable for validation errors, range errors, and other business logic * exceptions that are not strictly type-related. It ensures proper prototype * chain setup and automatically sets the error name from the constructor. */ var CpfFormatterException = /** @class */ (function (_super) { __extends(CpfFormatterException, _super); function CpfFormatterException(message) { var _newTarget = this.constructor; var _this = _super.call(this, message) || this; Object.setPrototypeOf(_this, _newTarget.prototype); _this.name = _this.constructor.name; return _this; } return CpfFormatterException; }(Error)); /** * Exception raised when `hiddenStart` or `hiddenEnd` option values are outside * the valid range for CPF formatting. The valid range bounds are typically * between 0 and 10 (inclusive), representing the indices of the 11-digit CPF * string. The error message includes the option name, the actual input value, * and the expected range bounds. */ var CpfFormatterOptionsHiddenRangeInvalidException = /** @class */ (function (_super) { __extends(CpfFormatterOptionsHiddenRangeInvalidException, _super); function CpfFormatterOptionsHiddenRangeInvalidException(optionName, actualInput, minExpectedValue, maxExpectedValue) { var _this = _super.call(this, "CPF formatting option \"".concat(optionName, "\" must be an integer between ").concat(minExpectedValue, " and ").concat(maxExpectedValue, ". Got ").concat(actualInput, ".")) || this; _this.optionName = optionName; _this.actualInput = actualInput; _this.minExpectedValue = minExpectedValue; _this.maxExpectedValue = maxExpectedValue; return _this; } return CpfFormatterOptionsHiddenRangeInvalidException; }(CpfFormatterException)); /** * Exception raised when a character is not allowed to be used as a key * character on options. */ var CpfFormatterOptionsForbiddenKeyCharacterException = /** @class */ (function (_super) { __extends(CpfFormatterOptionsForbiddenKeyCharacterException, _super); function CpfFormatterOptionsForbiddenKeyCharacterException(optionName, actualInput, forbiddenCharacters) { var _this = _super.call(this, "Value \"".concat(actualInput, "\" for CPF formatting option \"").concat(optionName, "\" contains disallowed characters (\"").concat(forbiddenCharacters.join('", "'), "\").")) || this; _this.optionName = optionName; _this.actualInput = actualInput; _this.forbiddenCharacters = forbiddenCharacters; return _this; } return CpfFormatterOptionsForbiddenKeyCharacterException; }(CpfFormatterException)); /** * Exception raised when the CPF string input (after optional processing) does * not have the required length. A valid CPF must contain exactly 11 digits. The * error message distinguishes between the original input and the evaluated one * (which strips punctuation characters). */ var CpfFormatterInputLengthException = /** @class */ (function (_super) { __extends(CpfFormatterInputLengthException, _super); function CpfFormatterInputLengthException(actualInput, evaluatedInput, expectedLength) { var _this = this; var fmtActualInput = typeof actualInput === 'string' ? "\"".concat(actualInput, "\"") : JSON.stringify(actualInput); var fmtEvaluatedInput = actualInput === evaluatedInput ? "".concat(evaluatedInput.length) : "".concat(evaluatedInput.length, " in \"").concat(evaluatedInput, "\""); _this = _super.call(this, "CPF input ".concat(fmtActualInput, " does not contain ").concat(expectedLength, " digits. Got ").concat(fmtEvaluatedInput, ".")) || this; _this.actualInput = actualInput; _this.evaluatedInput = evaluatedInput; _this.expectedLength = expectedLength; return _this; } return CpfFormatterInputLengthException; }(CpfFormatterException)); /** * The standard length of a CPF (Cadastro de Pessoa Física) identifier (11 * digits). */ var CPF_LENGTH = 11; /** * Minimum valid index for the hidden range (inclusive). Must be between 0 and * CPF_LENGTH - 1. */ var MIN_HIDDEN_RANGE = 0; /** * Maximum valid index for the hidden range (inclusive). Must be between 0 and * CPF_LENGTH - 1. */ var MAX_HIDDEN_RANGE = CPF_LENGTH - 1; /** * Class to store the options for the CPF formatter. This class provides a * centralized way to configure how CPF numbers are formatted, including * delimiters, hidden digit ranges, HTML escaping, URL encoding, and error * handling callbacks. */ var CpfFormatterOptions = /** @class */ (function () { /** * Creates a new instance of `CpfFormatterOptions`. * * Options can be provided in multiple ways: * * 1. As a single options object or another `CpfFormatterOptions` instance. * 2. As multiple override objects that are merged in order (later overrides take * precedence) * * All options are optional and will default to their predefined values if not * provided. The `hiddenStart` and `hiddenEnd` options are validated to ensure * they are within the valid range [0, CPF_LENGTH - 1] and will be swapped if * `hiddenStart > hiddenEnd`. * * @throws {CpfFormatterOptionsTypeError} If any option has an invalid type. * @throws {CpfFormatterOptionsHiddenRangeInvalidException} If `hiddenStart` * or `hiddenEnd` are out of valid range. * @throws {CpfFormatterOptionsForbiddenKeyCharacterException} If any key * option (`hiddenKey`, `dotKey`, `dashKey`) contains a disallowed * character. */ function CpfFormatterOptions(defaultOptions) { var overrides = []; for (var _i = 1; _i < arguments.length; _i++) { overrides[_i - 1] = arguments[_i]; } this._options = {}; this.hidden = defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.hidden; this.hiddenKey = defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.hiddenKey; this.dotKey = defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.dotKey; this.dashKey = defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.dashKey; this.escape = defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.escape; this.encode = defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.encode; this.onFail = defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.onFail; this.setHiddenRange(defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.hiddenStart, defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.hiddenEnd); for (var _a = 0, overrides_1 = overrides; _a < overrides_1.length; _a++) { var override = overrides_1[_a]; this.set(override); } } Object.defineProperty(CpfFormatterOptions.prototype, "all", { /** * Returns a shallow copy of all current options, frozen to prevent * modification. This is useful for creating immutable snapshots of the * current configuration. */ get: function () { var options = __assign({}, this._options); return Object.freeze(options); }, enumerable: false, configurable: true }); Object.defineProperty(CpfFormatterOptions.prototype, "hidden", { /** * Gets whether hidden digit replacement is enabled. When `true`, digits * within the `hiddenStart` to `hiddenEnd` range will be replaced with the * `hiddenKey` character. */ get: function () { return this._options.hidden; }, /** * Sets whether hidden digit replacement is enabled. When set to `true`, * digits within the `hiddenStart` to `hiddenEnd` range will be replaced with * the `hiddenKey` character. The value is converted to a boolean using * `Boolean()`, so truthy/falsy values are handled appropriately. */ set: function (value) { var actualHidden = value !== null && value !== void 0 ? value : CpfFormatterOptions.DEFAULT_HIDDEN; actualHidden = Boolean(actualHidden); this._options.hidden = actualHidden; }, enumerable: false, configurable: true }); Object.defineProperty(CpfFormatterOptions.prototype, "hiddenKey", { /** * Gets the string used to replace hidden CPF digits. This string is used when * `hidden` is `true` to mask digits in the range from `hiddenStart` to * `hiddenEnd` (inclusive). */ get: function () { return this._options.hiddenKey; }, /** * Sets the string used to replace hidden CPF digits. This string is used when * `hidden` is `true` to mask digits in the range from `hiddenStart` to * `hiddenEnd` (inclusive). * * @throws {CpfFormatterOptionsTypeError} If the value is not a string. * @throws {CpfFormatterOptionsForbiddenKeyCharacterException} If the value * contains any disallowed key character. */ set: function (value) { var actualHiddenKey = value !== null && value !== void 0 ? value : CpfFormatterOptions.DEFAULT_HIDDEN_KEY; if (typeof actualHiddenKey !== 'string') { throw new CpfFormatterOptionsTypeError('hiddenKey', actualHiddenKey, 'string'); } this._assertNoDisallowedKeyCharacters('hiddenKey', actualHiddenKey); this._options.hiddenKey = actualHiddenKey; }, enumerable: false, configurable: true }); Object.defineProperty(CpfFormatterOptions.prototype, "hiddenStart", { /** * Gets the start index (inclusive) for hiding CPF digits. This is the first * position in the CPF string where digits will be replaced with the * `hiddenKey` string when `hidden` is `true`. Must be between `0` and `10` * (`CPF_LENGTH - 1`). */ get: function () { return this._options.hiddenStart; }, /** * Sets the start index (inclusive) for hiding CPF digits. This is the first * position in the CPF string where digits will be replaced with the * `hiddenKey` when `hidden` is `true`. The value is validated and will be * swapped with `hiddenEnd` if necessary to ensure `hiddenStart <= * hiddenEnd`. * * @throws {CpfFormatterOptionsTypeError} If the value is not an integer. * @throws {CpfFormatterOptionsHiddenRangeInvalidException} If the value is * out of valid range [0, CPF_LENGTH - 1] */ set: function (value) { this.setHiddenRange(value, this._options.hiddenEnd); }, enumerable: false, configurable: true }); Object.defineProperty(CpfFormatterOptions.prototype, "hiddenEnd", { /** * Gets the end index (inclusive) for hiding CPF digits. This is the last * position in the CPF string where digits will be replaced with the * `hiddenKey` string when `hidden` is `true`. Must be between `0` and `10` * (`CPF_LENGTH - 1`). */ get: function () { return this._options.hiddenEnd; }, /** * Sets the end index (inclusive) for hiding CPF digits. This is the last * position in the CPF string where digits will be replaced with the * `hiddenKey` when `hidden` is `true`. The value is validated and will be * swapped with `hiddenStart` if necessary to ensure `hiddenStart <= * hiddenEnd`. * * @throws {CpfFormatterOptionsTypeError} If the value is not an integer. * @throws {CpfFormatterOptionsHiddenRangeInvalidException} If the value is * out of valid range [`0`, `CPF_LENGTH - 1`] */ set: function (value) { this.setHiddenRange(this._options.hiddenStart, value); }, enumerable: false, configurable: true }); Object.defineProperty(CpfFormatterOptions.prototype, "dotKey", { /** * Gets the string used as the dot delimiter. This string is used to separate * the first groups of digits in the formatted CPF (e.g., `"."` in * "123.456.789-10"). */ get: function () { return this._options.dotKey; }, /** * Sets the string used as the dot delimiter. This string is used to separate * the first groups of digits in the formatted CPF (e.g., `"."` in * `"123.456.789-10"`). * * @throws {CpfFormatterOptionsTypeError} If the value is not a string. * @throws {CpfFormatterOptionsForbiddenKeyCharacterException} If the value * contains any disallowed key character. */ set: function (value) { var actualDotKey = value !== null && value !== void 0 ? value : CpfFormatterOptions.DEFAULT_DOT_KEY; if (typeof actualDotKey !== 'string') { throw new CpfFormatterOptionsTypeError('dotKey', actualDotKey, 'string'); } this._assertNoDisallowedKeyCharacters('dotKey', actualDotKey); this._options.dotKey = actualDotKey; }, enumerable: false, configurable: true }); Object.defineProperty(CpfFormatterOptions.prototype, "dashKey", { /** * Gets the string used as the dash delimiter. This string is used to separate * the check digits at the end in the formatted CPF (e.g., `"-"` in * `"123.456.789-10"`). */ get: function () { return this._options.dashKey; }, /** * Sets the string used as the dash delimiter. This string is used to separate * the check digits at the end in the formatted CPF (e.g., `"-"` in * `"123.456.789-10"`). * * @throws {CpfFormatterOptionsTypeError} If the value is not a string. * @throws {CpfFormatterOptionsForbiddenKeyCharacterException} If the value * contains any disallowed key character. */ set: function (value) { var actualDashKey = value !== null && value !== void 0 ? value : CpfFormatterOptions.DEFAULT_DASH_KEY; if (typeof actualDashKey !== 'string') { throw new CpfFormatterOptionsTypeError('dashKey', actualDashKey, 'string'); } this._assertNoDisallowedKeyCharacters('dashKey', actualDashKey); this._options.dashKey = actualDashKey; }, enumerable: false, configurable: true }); Object.defineProperty(CpfFormatterOptions.prototype, "escape", { /** * Gets whether HTML escaping is enabled. When `true`, HTML special characters * (like `<`, `>`, `&`, etc.) in the formatted CPF string will be escaped. * This is useful when using custom delimiters that may contain HTML * characters or when displaying CPF in HTML. */ get: function () { return this._options.escape; }, /** * Sets whether HTML escaping is enabled. When set to `true`, HTML special * characters (like `<`, `>`, `&`, etc.) in the formatted CPF string will be * escaped. This is useful when using custom delimiters that may contain HTML * characters or when displaying CPF in HTML. The value is converted to a * boolean using `Boolean()`, so truthy/falsy values are handled * appropriately. */ set: function (value) { var actualEscape = value !== null && value !== void 0 ? value : CpfFormatterOptions.DEFAULT_ESCAPE; actualEscape = Boolean(actualEscape); this._options.escape = actualEscape; }, enumerable: false, configurable: true }); Object.defineProperty(CpfFormatterOptions.prototype, "encode", { /** * Gets whether URL encoding is enabled. When `true`, the formatted CPF string * will be URL-encoded, making it safe to use in URL query parameters or path * segments. */ get: function () { return this._options.encode; }, /** * Sets whether URL encoding is enabled. When set to `true`, the formatted CPF * string will be URL-encoded, making it safe to use in URL query parameters * or path segments. The value is converted to a boolean using `Boolean()`, so * truthy/falsy values are handled appropriately. */ set: function (value) { var actualEncode = value !== null && value !== void 0 ? value : CpfFormatterOptions.DEFAULT_ENCODE; actualEncode = Boolean(actualEncode); this._options.encode = actualEncode; }, enumerable: false, configurable: true }); Object.defineProperty(CpfFormatterOptions.prototype, "onFail", { /** * Gets the callback function executed when formatting fails. This function is * called when the formatter encounters an error (e.g., invalid input, invalid * options). It receives the input value and an optional error object, and * should return a string to use as the fallback output. */ get: function () { return this._options.onFail; }, /** * Sets the callback function executed when formatting fails. This function is * called when the formatter encounters an error (e.g., invalid input, invalid * options). It receives the input value and an optional error object, and * should return a string to use as the fallback output. * * @throws {CpfFormatterOptionsTypeError} If the value is not a function. */ set: function (value) { var actualOnFail = value !== null && value !== void 0 ? value : CpfFormatterOptions.DEFAULT_ON_FAIL; if (typeof actualOnFail !== 'function') { throw new CpfFormatterOptionsTypeError('onFail', value, 'function'); } this._options.onFail = actualOnFail; }, enumerable: false, configurable: true }); /** * Sets the hiddenStart and hiddenEnd options with proper validation and * sanitization. This method validates that both indices are integers within * the valid range [`0`, `CPF_LENGTH - 1`]. If `hiddenStart > hiddenEnd`, the * values are automatically swapped to ensure a valid range. This method is * used internally by the `hiddenStart` and `hiddenEnd` setters to maintain * consistency. * * @throws {CpfFormatterOptionsTypeError} If either value is not an integer. * @throws {CpfFormatterOptionsHiddenRangeInvalidException} If either value is * out of valid range [`0`, `CPF_LENGTH - 1`] */ CpfFormatterOptions.prototype.setHiddenRange = function (hiddenStart, hiddenEnd) { var _a; var actualHiddenStart = hiddenStart !== null && hiddenStart !== void 0 ? hiddenStart : CpfFormatterOptions.DEFAULT_HIDDEN_START; var actualHiddenEnd = hiddenEnd !== null && hiddenEnd !== void 0 ? hiddenEnd : CpfFormatterOptions.DEFAULT_HIDDEN_END; if (typeof actualHiddenStart !== 'number' || !Number.isInteger(actualHiddenStart)) { throw new CpfFormatterOptionsTypeError('hiddenStart', actualHiddenStart, 'integer'); } if (typeof actualHiddenEnd !== 'number' || !Number.isInteger(actualHiddenEnd)) { throw new CpfFormatterOptionsTypeError('hiddenEnd', actualHiddenEnd, 'integer'); } if (actualHiddenStart < MIN_HIDDEN_RANGE || actualHiddenStart > MAX_HIDDEN_RANGE) { throw new CpfFormatterOptionsHiddenRangeInvalidException('hiddenStart', actualHiddenStart, MIN_HIDDEN_RANGE, MAX_HIDDEN_RANGE); } if (actualHiddenEnd < MIN_HIDDEN_RANGE || actualHiddenEnd > MAX_HIDDEN_RANGE) { throw new CpfFormatterOptionsHiddenRangeInvalidException('hiddenEnd', actualHiddenEnd, MIN_HIDDEN_RANGE, MAX_HIDDEN_RANGE); } if (actualHiddenStart > actualHiddenEnd) { _a = [actualHiddenEnd, actualHiddenStart], actualHiddenStart = _a[0], actualHiddenEnd = _a[1]; } this._options.hiddenStart = actualHiddenStart; this._options.hiddenEnd = actualHiddenEnd; return this; }; /** * Sets multiple options at once. This method allows you to update multiple * options in a single call. Only the provided options are updated; options * not included in the object retain their current values. You can pass either * a partial options object or another `CpfFormatterOptions` instance. * * @throws {CpfFormatterOptionsTypeError} If any option has an invalid type. * @throws {CpfFormatterOptionsHiddenRangeInvalidException} If `hiddenStart` * or `hiddenEnd` are out of valid range. * @throws {CpfFormatterOptionsForbiddenKeyCharacterException} If any key * option (`hiddenKey`, `dotKey`, `dashKey`) contains a disallowed * character. */ CpfFormatterOptions.prototype.set = function (options) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; this.hidden = (_a = options.hidden) !== null && _a !== void 0 ? _a : this.hidden; this.hiddenKey = (_b = options.hiddenKey) !== null && _b !== void 0 ? _b : this.hiddenKey; this.dotKey = (_c = options.dotKey) !== null && _c !== void 0 ? _c : this.dotKey; this.dashKey = (_d = options.dashKey) !== null && _d !== void 0 ? _d : this.dashKey; this.escape = (_e = options.escape) !== null && _e !== void 0 ? _e : this.escape; this.encode = (_f = options.encode) !== null && _f !== void 0 ? _f : this.encode; this.onFail = (_g = options.onFail) !== null && _g !== void 0 ? _g : this.onFail; this.setHiddenRange((_h = options.hiddenStart) !== null && _h !== void 0 ? _h : this.hiddenStart, (_j = options.hiddenEnd) !== null && _j !== void 0 ? _j : this.hiddenEnd); return this; }; /** * Throws if the given string contains any disallowed key character. * * @throws {CpfFormatterOptionsForbiddenKeyCharacterException} If `value` * contains any character from `getDisallowedKeyCharacters()`. */ CpfFormatterOptions.prototype._assertNoDisallowedKeyCharacters = function (optionName, value) { var forbiddenChars = CpfFormatterOptions.DISALLOWED_KEY_CHARACTERS; var hasForbiddenChars = forbiddenChars.some(function (ch) { return value.includes(ch); }); if (hasForbiddenChars) { throw new CpfFormatterOptionsForbiddenKeyCharacterException(optionName, value, forbiddenChars); } }; /** * Default value for the `hidden` option. When `false`, all CPF digits are * displayed. */ CpfFormatterOptions.DEFAULT_HIDDEN = false; /** * Default string used to replace hidden CPF digits. */ CpfFormatterOptions.DEFAULT_HIDDEN_KEY = '*'; /** * Default start index (inclusive) for hiding CPF digits. Digits from this * index onwards will be replaced with the `hiddenKey` value. */ CpfFormatterOptions.DEFAULT_HIDDEN_START = 3; /** * Default end index (inclusive) for hiding CPF digits. Digits up to and * including this index will be replaced with the `hiddenKey` value. */ CpfFormatterOptions.DEFAULT_HIDDEN_END = 10; /** * Default string used as the dot delimiter in formatted CPF. Used to separate * the first groups of digits (XXX.XXX.XXX). */ CpfFormatterOptions.DEFAULT_DOT_KEY = '.'; /** * Default string used as the dash delimiter in formatted CPF. Used to * separate the first group of digits from the check digits at the end (-XX). */ CpfFormatterOptions.DEFAULT_DASH_KEY = '-'; /** * Default value for the `escape` option. When `false`, HTML special * characters are not escaped. */ CpfFormatterOptions.DEFAULT_ESCAPE = false; /** * Default value for the `encode` option. When `false`, the CPF string is not * URL-encoded. */ CpfFormatterOptions.DEFAULT_ENCODE = false; /** * Default callback function executed when formatting fails. Returns an empty * string by default. */ CpfFormatterOptions.DEFAULT_ON_FAIL = function DEFAULT_ON_FAIL() { return ''; }; /** * Characters that are not allowed in key options (`hiddenKey`, `dotKey`, * `dashKey`). They are reserved for internal formatting logic. * * For now, it's only used to replace the hidden key placeholder in the * CpfFormatter class. However, this set of characters is reserved for future * use already. */ CpfFormatterOptions.DISALLOWED_KEY_CHARACTERS = Object.freeze([ '\u00e5', '\u00eb', '\u00ef', '\u00f6', ]); return CpfFormatterOptions; }()); Object.freeze(CpfFormatterOptions); /** * @typedef {import('./exceptions').CpfFormatterOptionsTypeError} CpfFormatterOptionsTypeError * * * @typedef {import('./exceptions').CpfFormatterOptionsHiddenRangeInvalidException} CpfFormatterOptionsHiddenRangeInvalidException */ /** * A rarely-used 1-length character that is replaced with `hiddenKey` when * `hidden` is `true`. */ var HIDDEN_KEY_PLACEHOLDER = CpfFormatterOptions.DISALLOWED_KEY_CHARACTERS[0]; /** * Formatter for CPF (Cadastro de Pessoa Física) identifiers. It normalizes and * optionally masks, HTML-escapes, or URL-encodes 11-digit CPF input. Accepts a * string or array of strings; non-numeric characters are stripped. Invalid * input type is handled by throwing; invalid length is handled via the * configured `onFail` callback instead of throwing. */ var CpfFormatter = /** @class */ (function () { /** * Creates a new `CpfFormatter` with optional default options. * * Default options apply to every call to `format` unless overridden by the * per-call `options` argument. Options control masking, HTML escaping, URL * encoding, and the callback used when formatting fails. * * When `defaultOptions` is a `CpfFormatterOptions` instance, that instance is * used directly (no copy is created). Mutating it later (e.g. via the * `options` getter or the original reference) affects future `format` calls * that do not pass per-call options. When a plain object or nothing is * passed, a new `CpfFormatterOptions` instance is created from it. * * @throws {CpfFormatterOptionsTypeError} If any option has an invalid type. * @throws {CpfFormatterOptionsHiddenRangeInvalidException} If `hiddenStart` * or `hiddenEnd` are out of valid range. */ function CpfFormatter(defaultOptions) { this._options = defaultOptions instanceof CpfFormatterOptions ? defaultOptions : new CpfFormatterOptions(defaultOptions); } Object.defineProperty(CpfFormatter.prototype, "options", { /** * Returns the default options used by this formatter when per-call options * are not provided. * * The returned object is the same instance used internally; mutating it (e.g. * via setters on `CpfFormatterOptions`) affects future `format` calls that do * not pass `options`. */ get: function () { return this._options; }, enumerable: false, configurable: true }); /** * Formats a CPF value into a normalized 11-digit string. * * Input is normalized by stripping non-numeric characters. If the result * length is not exactly 11, the configured `onFail` callback is invoked with * the string value and an error; its return value is used as the result. If * the input is not a string or array of strings, this method throws. * * When valid, the result may be further transformed according to options: * * - If `hidden` is `true`, digits between `hiddenStart` and `hiddenEnd` * (inclusive) are replaced with `hiddenKey`. * - If `escape` is `true`, HTML special characters are escaped. * - If `encode` is `true`, the string is passed through `encodeURIComponent`. * * Per-call `options` are merged over the instance default options for this * call only; the instance defaults are unchanged. * * @throws {CpfFormatterOptionsTypeError} If any option has an invalid type. * @throws {CpfFormatterOptionsHiddenRangeInvalidException} If `hiddenStart` * or `hiddenEnd` are out of valid range. * @throws {CpfFormatterInputTypeError} If the input is not a string or array * of strings. */ CpfFormatter.prototype.format = function (cpfInput, options) { var actualInput = this._toStringInput(cpfInput); var actualOptions = options ? new CpfFormatterOptions(this._options, options) : this._options; var digitsOnly = actualInput.replace(/\D/g, ''); var formattedCpf = digitsOnly; if (formattedCpf.length !== CPF_LENGTH) { var exception = new CpfFormatterInputLengthException(cpfInput, formattedCpf, CPF_LENGTH); return actualOptions.onFail(cpfInput, exception); } if (actualOptions.hidden) { var startingPart = formattedCpf.slice(0, actualOptions.hiddenStart); var endingPart = formattedCpf.slice(actualOptions.hiddenEnd + 1); var hiddenPartLength = actualOptions.hiddenEnd - actualOptions.hiddenStart + 1; var hiddenPart = HIDDEN_KEY_PLACEHOLDER.repeat(hiddenPartLength); formattedCpf = startingPart + hiddenPart + endingPart; } formattedCpf = formattedCpf.slice(0, 3) + actualOptions.dotKey + formattedCpf.slice(3, 6) + actualOptions.dotKey + formattedCpf.slice(6, 9) + actualOptions.dashKey + formattedCpf.slice(9, 11); formattedCpf = formattedCpf.replace(new RegExp(HIDDEN_KEY_PLACEHOLDER, 'g'), actualOptions.hiddenKey); if (actualOptions.escape) { formattedCpf = utils.escapeHTML(formattedCpf); } if (actualOptions.encode) { formattedCpf = encodeURIComponent(formattedCpf); } return formattedCpf; }; /** * Normalizes the input to a string. * * @throws {CpfFormatterInputTypeError} If the input is not a string or array * of strings. */ CpfFormatter.prototype._toStringInput = function (cpfInput) { if (typeof cpfInput === 'string') { return cpfInput; } if (Array.isArray(cpfInput)) { for (var _i = 0, cpfInput_1 = cpfInput; _i < cpfInput_1.length; _i++) { var item = cpfInput_1[_i]; if (typeof item !== 'string') { throw new CpfFormatterInputTypeError(cpfInput, 'string or string[]'); } } return cpfInput.join(''); } throw new CpfFormatterInputTypeError(cpfInput, 'string or string[]'); }; return CpfFormatter; }()); Object.freeze(CpfFormatter); /** * Helper function to simplify the usage of the {@link CpfFormatter} class. * * Formats a CPF string according to the given options. With no options, returns * the traditional CPF format (e.g. `123.456.789-10`). Invalid input or length * is handled by the configured `onFail` callback instead of throwing. */ function cpfFmt$1(cpfInput, options) { return new CpfFormatter(options).format(cpfInput); } var all = /*#__PURE__*/Object.freeze({ __proto__: null, CPF_LENGTH: CPF_LENGTH, CpfFormatter: CpfFormatter, CpfFormatterException: CpfFormatterException, CpfFormatterInputLengthException: CpfFormatterInputLengthException, CpfFormatterInputTypeError: CpfFormatterInputTypeError, CpfFormatterOptions: CpfFormatterOptions, CpfFormatterOptionsForbiddenKeyCharacterException: CpfFormatterOptionsForbiddenKeyCharacterException, CpfFormatterOptionsHiddenRangeInvalidException: CpfFormatterOptionsHiddenRangeInvalidException, CpfFormatterOptionsTypeError: CpfFormatterOptionsTypeError, CpfFormatterTypeError: CpfFormatterTypeError, cpfFmt: cpfFmt$1, default: cpfFmt$1 }); var baseCpfFmt = cpfFmt$1, rest = __rest(all, ["default", "cpfFmt"]); var cpfFmt = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return baseCpfFmt.apply(void 0, args); }; var index_cjs = Object.assign(cpfFmt, rest); module.exports = index_cjs; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi8uLi8uLi9ub2RlX21vZHVsZXMvLmJ1bi9Acm9sbHVwK3BsdWdpbi10eXBlc2NyaXB0QDEyLjMuMCtkNjQ5Njc5OGQxOGE5MDg5L25vZGVfbW9kdWxlcy90c2xpYi90c2xpYi5lczYuanMiLCIuLi9zcmMvZXhjZXB0aW9ucy50cyIsIi4uL3NyYy9jcGYtZm9ybWF0dGVyLW9wdGlvbnMudHMiLCIuLi9zcmMvY3BmLWZvcm1hdHRlci50cyIsIi4uL3NyYy9jcGYtZm10LnRzIiwiLi4vc3JjL2luZGV4LmNqcy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcbkNvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLlxyXG5cclxuUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kL29yIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBmb3IgYW55XHJcbnB1cnBvc2Ugd2l0aCBvciB3aXRob3V0IGZlZSBpcyBoZXJlYnkgZ3JhbnRlZC5cclxuXHJcblRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIgQU5EIFRIRSBBVVRIT1IgRElTQ0xBSU1TIEFMTCBXQVJSQU5USUVTIFdJVEhcclxuUkVHQVJEIFRPIFRISVMgU09GVFdBUkUgSU5DTFVESU5HIEFMTCBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZXHJcbkFORCBGSVRORVNTLiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SIEJFIExJQUJMRSBGT1IgQU5ZIFNQRUNJQUwsIERJUkVDVCxcclxuSU5ESVJFQ1QsIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPUiBBTlkgREFNQUdFUyBXSEFUU09FVkVSIFJFU1VMVElORyBGUk9NXHJcbkxPU1MgT0YgVVNFLCBEQVRBIE9SIFBST0ZJVFMsIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBORUdMSUdFTkNFIE9SXHJcbk9USEVSIFRPUlRJT1VTIEFDVElPTiwgQVJJU0lORyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1JcclxuUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogKi9cclxuLyogZ2xvYmFsIFJlZmxlY3QsIFByb21pc2UsIFN1cHByZXNzZWRFcnJvciwgU3ltYm9sLCBJdGVyYXRvciAqL1xyXG5cclxudmFyIGV4dGVuZFN0YXRpY3MgPSBmdW5jdGlvbihkLCBiKSB7XHJcbiAgICBleHRlbmRTdGF0aWNzID0gT2JqZWN0LnNldFByb3RvdHlwZU9mIHx8XHJcbiAgICAgICAgKHsgX19wcm90b19fOiBbXSB9IGluc3RhbmNlb2YgQXJyYXkgJiYgZnVuY3Rpb24gKGQsIGIpIHsgZC5fX3Byb3RvX18gPSBiOyB9KSB8fFxyXG4gICAgICAgIGZ1bmN0aW9uIChkLCBiKSB7IGZvciAodmFyIHAgaW4gYikgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChiLCBwKSkgZFtwXSA9IGJbcF07IH07XHJcbiAgICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2V4dGVuZHMoZCwgYikge1xyXG4gICAgaWYgKHR5cGVvZiBiICE9PSBcImZ1bmN0aW9uXCIgJiYgYiAhPT0gbnVsbClcclxuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2xhc3MgZXh0ZW5kcyB2YWx1ZSBcIiArIFN0cmluZyhiKSArIFwiIGlzIG5vdCBhIGNvbnN0cnVjdG9yIG9yIG51bGxcIik7XHJcbiAgICBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG4gICAgZnVuY3Rpb24gX18oKSB7IHRoaXMuY29uc3RydWN0b3IgPSBkOyB9XHJcbiAgICBkLnByb3RvdHlwZSA9IGIgPT09IG51bGwgPyBPYmplY3QuY3JlYXRlKGIpIDogKF9fLnByb3RvdHlwZSA9IGIucHJvdG90eXBlLCBuZXcgX18oKSk7XHJcbn1cclxuXHJcbmV4cG9ydCB2YXIgX19hc3NpZ24gPSBmdW5jdGlvbigpIHtcclxuICAgIF9fYXNzaWduID0gT2JqZWN0LmFzc2lnbiB8fCBmdW5jdGlvbiBfX2Fzc2lnbih0KSB7XHJcbiAgICAgICAgZm9yICh2YXIgcywgaSA9IDEsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XHJcbiAgICAgICAgICAgIHMgPSBhcmd1bWVudHNbaV07XHJcbiAgICAgICAgICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSkgdFtwXSA9IHNbcF07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0O1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIF9fYXNzaWduLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3Jlc3QocywgZSkge1xyXG4gICAgdmFyIHQgPSB7fTtcclxuICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSAmJiBlLmluZGV4T2YocCkgPCAwKVxyXG4gICAgICAgIHRbcF0gPSBzW3BdO1xyXG4gICAgaWYgKHMgIT0gbnVsbCAmJiB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyA9PT0gXCJmdW5jdGlvblwiKVxyXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBwID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhzKTsgaSA8IHAubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgaWYgKGUuaW5kZXhPZihwW2ldKSA8IDAgJiYgT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKHMsIHBbaV0pKVxyXG4gICAgICAgICAgICAgICAgdFtwW2ldXSA9IHNbcFtpXV07XHJcbiAgICAgICAgfVxyXG4gICAgcmV0dXJuIHQ7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2RlY29yYXRlKGRlY29yYXRvcnMsIHRhcmdldCwga2V5LCBkZXNjKSB7XHJcbiAgICB2YXIgYyA9IGFyZ3VtZW50cy5sZW5ndGgsIHIgPSBjIDwgMyA/IHRhcmdldCA6IGRlc2MgPT09IG51bGwgPyBkZXNjID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0YXJnZXQsIGtleSkgOiBkZXNjLCBkO1xyXG4gICAgaWYgKHR5cGVvZiBSZWZsZWN0ID09PSBcIm9iamVjdFwiICYmIHR5cGVvZiBSZWZsZWN0LmRlY29yYXRlID09PSBcImZ1bmN0aW9uXCIpIHIgPSBSZWZsZWN0LmRlY29yYXRlKGRlY29yYXRvcnMsIHRhcmdldCwga2V5LCBkZXNjKTtcclxuICAgIGVsc2UgZm9yICh2YXIgaSA9IGRlY29yYXRvcnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIGlmIChkID0gZGVjb3JhdG9yc1tpXSkgciA9IChjIDwgMyA/IGQocikgOiBjID4gMyA/IGQodGFyZ2V0LCBrZXksIHIpIDogZCh0YXJnZXQsIGtleSkpIHx8IHI7XHJcbiAgICByZXR1cm4gYyA+IDMgJiYgciAmJiBPYmplY3QuZGVmaW5lUHJvcGVydHkodGFyZ2V0LCBrZXksIHIpLCByO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19wYXJhbShwYXJhbUluZGV4LCBkZWNvcmF0b3IpIHtcclxuICAgIHJldHVybiBmdW5jdGlvbiAodGFyZ2V0LCBrZXkpIHsgZGVjb3JhdG9yKHRhcmdldCwga2V5LCBwYXJhbUluZGV4KTsgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19lc0RlY29yYXRlKGN0b3IsIGRlc2NyaXB0b3JJbiwgZGVjb3JhdG9ycywgY29udGV4dEluLCBpbml0aWFsaXplcnMsIGV4dHJhSW5pdGlhbGl6ZXJzKSB7XHJcbiAgICBmdW5jdGlvbiBhY2NlcHQoZikgeyBpZiAoZiAhPT0gdm9pZCAwICYmIHR5cGVvZiBmICE9PSBcImZ1bmN0aW9uXCIpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJGdW5jdGlvbiBleHBlY3RlZFwiKTsgcmV0dXJuIGY7IH1cclxuICAgIHZhciBraW5kID0gY29udGV4dEluLmtpbmQsIGtleSA9IGtpbmQgPT09IFwiZ2V0dGVyXCIgPyBcImdldFwiIDoga2luZCA9PT0gXCJzZXR0ZXJcIiA/IFwic2V0XCIgOiBcInZhbHVlXCI7XHJcbiAgICB2YXIgdGFyZ2V0ID0gIWRlc2NyaXB0b3JJbiAmJiBjdG9yID8gY29udGV4dEluW1wic3RhdGljXCJdID8gY3RvciA6IGN0b3IucHJvdG90eXBlIDogbnVsbDtcclxuICAgIHZhciBkZXNjcmlwdG9yID0gZGVzY3JpcHRvckluIHx8ICh0YXJnZXQgPyBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwgY29udGV4dEluLm5hbWUpIDoge30pO1xyXG4gICAgdmFyIF8sIGRvbmUgPSBmYWxzZTtcclxuICAgIGZvciAodmFyIGkgPSBkZWNvcmF0b3JzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XHJcbiAgICAgICAgdmFyIGNvbnRleHQgPSB7fTtcclxuICAgICAgICBmb3IgKHZhciBwIGluIGNvbnRleHRJbikgY29udGV4dFtwXSA9IHAgPT09IFwiYWNjZXNzXCIgPyB7fSA6IGNvbnRleHRJbltwXTtcclxuICAgICAgICBmb3IgKHZhciBwIGluIGNvbnRleHRJbi5hY2Nlc3MpIGNvbnRleHQuYWNjZXNzW3BdID0gY29udGV4dEluLmFjY2Vzc1twXTtcclxuICAgICAgICBjb250ZXh0LmFkZEluaXRpYWxpemVyID0gZnVuY3Rpb24gKGYpIHsgaWYgKGRvbmUpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgYWRkIGluaXRpYWxpemVycyBhZnRlciBkZWNvcmF0aW9uIGhhcyBjb21wbGV0ZWRcIik7IGV4dHJhSW5pdGlhbGl6ZXJzLnB1c2goYWNjZXB0KGYgfHwgbnVsbCkpOyB9O1xyXG4gICAgICAgIHZhciByZXN1bHQgPSAoMCwgZGVjb3JhdG9yc1tpXSkoa2luZCA9PT0gXCJhY2Nlc3NvclwiID8geyBnZXQ6IGRlc2NyaXB0b3IuZ2V0LCBzZXQ6IGRlc2NyaXB0b3Iuc2V0IH0gOiBkZXNjcmlwdG9yW2tleV0sIGNvbnRleHQpO1xyXG4gICAgICAgIGlmIChraW5kID09PSBcImFjY2Vzc29yXCIpIHtcclxuICAgICAgICAgICAgaWYgKHJlc3VsdCA9PT0gdm9pZCAwKSBjb250aW51ZTtcclxuICAgICAgICAgICAgaWYgKHJlc3VsdCA9PT0gbnVsbCB8fCB0eXBlb2YgcmVzdWx0ICE9PSBcIm9iamVjdFwiKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiT2JqZWN0IGV4cGVjdGVkXCIpO1xyXG4gICAgICAgICAgICBpZiAoXyA9IGFjY2VwdChyZXN1bHQuZ2V0KSkgZGVzY3JpcHRvci5nZXQgPSBfO1xyXG4gICAgICAgICAgICBpZiAoXyA9IGFjY2VwdChyZXN1bHQuc2V0KSkgZGVzY3JpcHRvci5zZXQgPSBfO1xyXG4gICAgICAgICAgICBpZiAoXyA9IGFjY2VwdChyZXN1bHQuaW5pdCkpIGluaXRpYWxpemVycy51bnNoaWZ0KF8pO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIGlmIChfID0gYWNjZXB0KHJlc3VsdCkpIHtcclxuICAgICAgICAgICAgaWYgKGtpbmQgPT09IFwiZmllbGRcIikgaW5pdGlhbGl6ZXJzLnVuc2hpZnQoXyk7XHJcbiAgICAgICAgICAgIGVsc2UgZGVzY3JpcHRvcltrZXldID0gXztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAodGFyZ2V0KSBPYmplY3QuZGVmaW5lUHJvcGVydHkodGFyZ2V0LCBjb250ZXh0SW4ubmFtZSwgZGVzY3JpcHRvcik7XHJcbiAgICBkb25lID0gdHJ1ZTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3J1bkluaXRpYWxpemVycyh0aGlzQXJnLCBpbml0aWFsaXplcnMsIHZhbHVlKSB7XHJcbiAgICB2YXIgdXNlVmFsdWUgPSBhcmd1bWVudHMubGVuZ3RoID4gMjtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaW5pdGlhbGl6ZXJzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgdmFsdWUgPSB1c2VWYWx1ZSA/IGluaXRpYWxpemVyc1tpXS5jYWxsKHRoaXNBcmcsIHZhbHVlKSA6IGluaXRpYWxpemVyc1tpXS5jYWxsKHRoaXNBcmcpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHVzZVZhbHVlID8gdmFsdWUgOiB2b2lkIDA7XHJcbn07XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19wcm9wS2V5KHgpIHtcclxuICAgIHJldHVybiB0eXBlb2YgeCA9PT0gXCJzeW1ib2xcIiA/IHggOiBcIlwiLmNvbmNhdCh4KTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3NldEZ1bmN0aW9uTmFtZShmLCBuYW1lLCBwcmVmaXgpIHtcclxuICAgIGlmICh0eXBlb2YgbmFtZSA9PT0gXCJzeW1ib2xcIikgbmFtZSA9IG5hbWUuZGVzY3JpcHRpb24gPyBcIltcIi5jb25jYXQobmFtZS5kZXNjcmlwdGlvbiwgXCJdXCIpIDogXCJcIjtcclxuICAgIHJldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZiwgXCJuYW1lXCIsIHsgY29uZmlndXJhYmxlOiB0cnVlLCB2YWx1ZTogcHJlZml4ID8gXCJcIi5jb25jYXQocHJlZml4LCBcIiBcIiwgbmFtZSkgOiBuYW1lIH0pO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fbWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpIHtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5tZXRhZGF0YSA9PT0gXCJmdW5jdGlvblwiKSByZXR1cm4gUmVmbGVjdC5tZXRhZGF0YShtZXRhZGF0YUtleSwgbWV0YWRhdGFWYWx1ZSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2F3YWl0ZXIodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XHJcbiAgICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkgeyByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHZhbHVlKTsgfSk7IH1cclxuICAgIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xyXG4gICAgICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvci5uZXh0KHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiByZWplY3RlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkgeyByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTsgfVxyXG4gICAgICAgIHN0ZXAoKGdlbmVyYXRvciA9IGdlbmVyYXRvci5hcHBseSh0aGlzQXJnLCBfYXJndW1lbnRzIHx8IFtdKSkubmV4dCgpKTtcclxuICAgIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19nZW5lcmF0b3IodGhpc0FyZywgYm9keSkge1xyXG4gICAgdmFyIF8gPSB7IGxhYmVsOiAwLCBzZW50OiBmdW5jdGlvbigpIHsgaWYgKHRbMF0gJiAxKSB0aHJvdyB0WzFdOyByZXR1cm4gdFsxXTsgfSwgdHJ5czogW10sIG9wczogW10gfSwgZiwgeSwgdCwgZyA9IE9iamVjdC5jcmVhdGUoKHR5cGVvZiBJdGVyYXRvciA9PT0gXCJmdW5jdGlvblwiID8gSXRlcmF0b3IgOiBPYmplY3QpLnByb3RvdHlwZSk7XHJcbiAgICByZXR1cm4gZy5uZXh0ID0gdmVyYigwKSwgZ1tcInRocm93XCJdID0gdmVyYigxKSwgZ1tcInJldHVyblwiXSA9IHZlcmIoMiksIHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiAoZ1tTeW1ib2wuaXRlcmF0b3JdID0gZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzOyB9KSwgZztcclxuICAgIGZ1bmN0aW9uIHZlcmIobikgeyByZXR1cm4gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIHN0ZXAoW24sIHZdKTsgfTsgfVxyXG4gICAgZnVuY3Rpb24gc3RlcChvcCkge1xyXG4gICAgICAgIGlmIChmKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiR2VuZXJhdG9yIGlzIGFscmVhZHkgZXhlY3V0aW5nLlwiKTtcclxuICAgICAgICB3aGlsZSAoZyAmJiAoZyA9IDAsIG9wWzBdICYmIChfID0gMCkpLCBfKSB0cnkge1xyXG4gICAgICAgICAgICBpZiAoZiA9IDEsIHkgJiYgKHQgPSBvcFswXSAmIDIgPyB5W1wicmV0dXJuXCJdIDogb3BbMF0gPyB5W1widGhyb3dcIl0gfHwgKCh0ID0geVtcInJldHVyblwiXSkgJiYgdC5jYWxsKHkpLCAwKSA6IHkubmV4dCkgJiYgISh0ID0gdC5jYWxsKHksIG9wWzFdKSkuZG9uZSkgcmV0dXJuIHQ7XHJcbiAgICAgICAgICAgIGlmICh5ID0gMCwgdCkgb3AgPSBbb3BbMF0gJiAyLCB0LnZhbHVlXTtcclxuICAgICAgICAgICAgc3dpdGNoIChvcFswXSkge1xyXG4gICAgICAgICAgICAgICAgY2FzZSAwOiBjYXNlIDE6IHQgPSBvcDsgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICBjYXNlIDQ6IF8ubGFiZWwrKzsgcmV0dXJuIHsgdmFsdWU6IG9wWzFdLCBkb25lOiBmYWxzZSB9O1xyXG4gICAgICAgICAgICAgICAgY2FzZSA1OiBfLmxhYmVsKys7IHkgPSBvcFsxXTsgb3AgPSBbMF07IGNvbnRpbnVlO1xyXG4gICAgICAgICAgICAgICAgY2FzZSA3OiBvcCA9IF8ub3BzLnBvcCgpOyBfLnRyeXMucG9wKCk7IGNvbnRpbnVlO1xyXG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgICAgICAgICBpZiAoISh0ID0gXy50cnlzLCB0ID0gdC5sZW5ndGggPiAwICYmIHRbdC5sZW5ndGggLSAxXSkgJiYgKG9wWzBdID09PSA2IHx8IG9wWzBdID09PSAyKSkgeyBfID0gMDsgY29udGludWU7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAob3BbMF0gPT09IDMgJiYgKCF0IHx8IChvcFsxXSA+IHRbMF0gJiYgb3BbMV0gPCB0WzNdKSkpIHsgXy5sYWJlbCA9IG9wWzFdOyBicmVhazsgfVxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChvcFswXSA9PT0gNiAmJiBfLmx