react-native-advanced-input-mask
Version:
Text input mask for React Native on iOS, Android and web. Synchronous and easy formatting without hustle
189 lines (167 loc) • 5.01 kB
text/typescript
import FormatError from "./FormatError";
export default class FormatSanitizer {
public static sanitize(formatString: string): string {
FormatSanitizer.checkOpenBraces(formatString);
const blocks = this.divideBlocksWithMixedCharacters(
this.getFormatBlocks(formatString),
);
return FormatSanitizer.sortFormatBlocks(blocks).join("");
}
private static getFormatBlocks(formatString: string): string[] {
const blocks: string[] = [];
let currentBlock = "";
let escape = false;
for (const char of formatString) {
if (char === "\\") {
if (!escape) {
escape = true;
currentBlock += char;
continue;
}
}
if ((char === "[" || char === "{") && !escape) {
if (currentBlock.length > 0) {
blocks.push(currentBlock);
}
currentBlock = "";
}
currentBlock += char;
if ((char === "]" || char === "}") && !escape) {
blocks.push(currentBlock);
currentBlock = "";
}
escape = false;
}
if (currentBlock.length > 0) {
blocks.push(currentBlock);
}
return blocks;
}
private static divideBlocksWithMixedCharacters(blocks: string[]): string[] {
const resultingBlocks: string[] = [];
for (const block of blocks) {
if (block.startsWith("[")) {
let blockBuffer = "";
for (let i = 0; i < block.length; i++) {
const blockCharacter = block[i];
if (blockCharacter === "[") {
blockBuffer += blockCharacter;
continue;
}
if (blockCharacter === "]" && !blockBuffer.endsWith("\\")) {
blockBuffer += blockCharacter;
resultingBlocks.push(blockBuffer);
break;
}
if (
(blockCharacter === "0" || blockCharacter === "9") &&
(blockBuffer.includes("A") ||
blockBuffer.includes("a") ||
blockBuffer.includes("-") ||
blockBuffer.includes("_"))
) {
blockBuffer += "]";
resultingBlocks.push(blockBuffer);
blockBuffer = "[" + blockCharacter;
continue;
}
if (
(blockCharacter === "A" || blockCharacter === "a") &&
(blockBuffer.includes("0") ||
blockBuffer.includes("9") ||
blockBuffer.includes("-") ||
blockBuffer.includes("_"))
) {
blockBuffer += "]";
resultingBlocks.push(blockBuffer);
blockBuffer = "[" + blockCharacter;
continue;
}
if (
(blockCharacter === "-" || blockCharacter === "_") &&
(blockBuffer.includes("0") ||
blockBuffer.includes("9") ||
blockBuffer.includes("A") ||
blockBuffer.includes("a"))
) {
blockBuffer += "]";
resultingBlocks.push(blockBuffer);
blockBuffer = "[" + blockCharacter;
continue;
}
blockBuffer += blockCharacter;
}
} else {
resultingBlocks.push(block);
}
}
return resultingBlocks;
}
private static sortFormatBlocks(blocks: string[]): string[] {
const sortedBlocks: string[] = [];
for (const block of blocks) {
let sortedBlock: string;
if (block.startsWith("[")) {
if (
block.includes("0") ||
block.includes("9") ||
block.includes("A") ||
block.includes("a")
) {
sortedBlock =
"[" +
block.replace("[", "").replace("]", "").split("").sort().join("") +
"]";
} else {
// For `_` or `-`, temporarily replace for sorting
sortedBlock =
"[" +
block
.replace("[", "")
.replace("]", "")
.replace("_", "A")
.replace("-", "a")
.split("")
.sort()
.join("") +
"]";
sortedBlock = sortedBlock.replace("A", "_").replace("a", "-");
}
} else {
sortedBlock = block;
}
sortedBlocks.push(sortedBlock);
}
return sortedBlocks;
}
private static checkOpenBraces(str: string): void {
let escape = false;
let squareBraceOpen = false;
let curlyBraceOpen = false;
for (const char of str) {
if (char === "\\") {
escape = !escape;
continue;
}
if (char === "[") {
if (squareBraceOpen) {
throw new FormatError();
}
squareBraceOpen = !escape;
}
if (char === "]" && !escape) {
squareBraceOpen = false;
}
if (char === "{") {
if (curlyBraceOpen) {
throw new FormatError();
}
curlyBraceOpen = !escape;
}
if (char === "}" && !escape) {
curlyBraceOpen = false;
}
escape = false;
}
}
}