218 lines
5.9 KiB
TypeScript
218 lines
5.9 KiB
TypeScript
/* Storage for Per Char Checks */
|
|
// Builder for per character
|
|
import ChecksData, {
|
|
doubleSpace,
|
|
formattingChar,
|
|
invalidFormatting,
|
|
isSpaceOrNewLine,
|
|
isFormattingSignal,
|
|
resettingSignal,
|
|
} from "./checksData.ts";
|
|
import {
|
|
isResettingSignal,
|
|
logOrThrowProblem,
|
|
setupUtil,
|
|
} from "./checksUtil.ts";
|
|
|
|
/**
|
|
* Makes various space and newline related checks, and checks formatting.
|
|
*/
|
|
export default function checkSpacesAndFormatting(
|
|
shouldCheck: boolean,
|
|
value: string,
|
|
id: number,
|
|
name: string,
|
|
key: string,
|
|
): string {
|
|
const data = new ChecksData(shouldCheck, value, id, name, key);
|
|
setupUtil(data);
|
|
|
|
checkFormatting(data);
|
|
|
|
if (doubleSpace.test(data.value)) {
|
|
logOrThrowProblem("Double Space(s)");
|
|
data.value = data.value.replace(doubleSpace, " ");
|
|
}
|
|
|
|
const trimmedResult = data.value.trim();
|
|
|
|
if (trimmedResult !== data.value) {
|
|
logOrThrowProblem("Extra Spaces or New Lines at Beginning or End");
|
|
data.value = trimmedResult;
|
|
}
|
|
|
|
if (!data.value.includes("\n")) return data.value;
|
|
|
|
const lineBuilder: string[] = [];
|
|
for (const bit of data.value.split("\n")) {
|
|
const trimmedBit = bit.trim();
|
|
|
|
if (trimmedBit !== bit)
|
|
logOrThrowProblem("Extra Spaces at Beginning or End of a Line");
|
|
|
|
lineBuilder.push(trimmedBit);
|
|
}
|
|
return lineBuilder.join("\n");
|
|
}
|
|
|
|
/**
|
|
* Whole string formatting checks.
|
|
*/
|
|
function checkFormatting(data: ChecksData) {
|
|
if (!data.value.includes(formattingChar)) return;
|
|
|
|
checkFormattingChar(data);
|
|
|
|
/* End of String Checks */
|
|
let prevChar = data.processor.getLast();
|
|
|
|
// Check for redundant formatting at end
|
|
if (isFormattingSignal.test(prevChar.char)) {
|
|
// If not resetting change, or we have no need to reset
|
|
// Note the second case should be caught by redundant formatting check, so no need to check
|
|
if (!isResettingSignal(prevChar.char)) {
|
|
logOrThrowProblem("Redundant Formatting At End");
|
|
data.processor.removeLast();
|
|
}
|
|
|
|
// For continued processing, refresh prevChar
|
|
prevChar = data.processor.getLast();
|
|
}
|
|
|
|
data.saveValue();
|
|
|
|
// Check for missing resetting signal at end
|
|
if (
|
|
!isResettingSignal(prevChar.char) &&
|
|
prevChar.formatBefore !== resettingSignal
|
|
) {
|
|
logOrThrowProblem("Resetting Formatting At End", "Missing", "Adding");
|
|
|
|
// Trim value, then add §r to it
|
|
data.value = data.value.trim() + formattingChar + resettingSignal;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Per character formatting checks.
|
|
*/
|
|
function checkFormattingChar(data: ChecksData) {
|
|
while (data.processor.hasNext()) {
|
|
const char = data.processor.toNext();
|
|
|
|
// If not formatting signal, ignore
|
|
if (!char.char.includes(formattingChar)) {
|
|
data.processor.add(char.char);
|
|
continue;
|
|
}
|
|
|
|
let signal = "";
|
|
|
|
// Check for invalid formatting, including legacy 'f' signal
|
|
if (invalidFormatting.test(char.char)) {
|
|
logOrThrowProblem(
|
|
`Invalid Formatting Signal '${char.char}'`,
|
|
"",
|
|
"Replacing",
|
|
"",
|
|
"with '§r'",
|
|
);
|
|
|
|
// BQu treats signals like §z as a resetting signal, so make them reset
|
|
// Yes, even ones followed after by `'`, a space, or a newline
|
|
signal = "r";
|
|
} else signal = char.char.replace(isFormattingSignal, "$1");
|
|
|
|
// Note: Do not use char.char past this point, use signal instead!
|
|
|
|
// Check if formatting is right after another (ignoring spaces, newlines, etc.)
|
|
let prevIgnoreSpaces = data.processor.getLastNonSpaceLike();
|
|
if (isFormattingSignal.test(prevIgnoreSpaces.char.char)) {
|
|
logOrThrowProblem("Redundant Formatting");
|
|
|
|
// Remove previous formatting
|
|
// Note: this won't be called if not found, as empty string is not a formatting signal
|
|
// Instead of splicing, remove all, then add back, so we ensure correct formatting of spaces
|
|
const empties = data.processor.result.slice(prevIgnoreSpaces.index + 1);
|
|
data.processor.removeLast(
|
|
data.processor.result.length - prevIgnoreSpaces.index,
|
|
);
|
|
|
|
empties.forEach((char) => data.processor.add(char.char));
|
|
}
|
|
|
|
/* Redundant Formatting Checks */
|
|
// Check if formatting does nothing
|
|
if (data.processor.getCurrentFormat() === signal) {
|
|
logOrThrowProblem("Redundant Formatting");
|
|
|
|
// No need to do anything, just continue
|
|
continue;
|
|
}
|
|
|
|
/* End Redundant Formatting Checks */
|
|
|
|
/* Formatting Order Checks */
|
|
// Make sure resetting formatting is BEFORE spaces
|
|
if (signal === "r") {
|
|
if (isSpaceOrNewLine.test(data.processor.getLast().char)) {
|
|
logOrThrowProblem(
|
|
"Resetting Formatting",
|
|
"",
|
|
"Moving",
|
|
"After Space(s)",
|
|
"Before Space(s)",
|
|
);
|
|
|
|
// Refetch ignore spaces, it may have changed
|
|
prevIgnoreSpaces = data.processor.getLastNonSpaceLike();
|
|
if (prevIgnoreSpaces.index === -1) {
|
|
// We don't need to add resetting formatting at start of processor
|
|
// Also, this condition should have already been caught through redundant checks
|
|
// Ignore
|
|
continue;
|
|
}
|
|
|
|
// Move in before spaces (Add after existing character, so use index + 1)
|
|
// Instead of splicing, remove all, then add back, so we ensure correct formatting of spaces
|
|
const empties = data.processor.result.slice(prevIgnoreSpaces.index + 1);
|
|
data.processor.removeLast(
|
|
data.processor.result.length - prevIgnoreSpaces.index - 1, // -1, we don't want to remove last-non-space char itself
|
|
);
|
|
|
|
data.processor.addFormat(signal);
|
|
empties.forEach((char) => data.processor.add(char.char));
|
|
continue;
|
|
}
|
|
data.processor.addFormat(signal);
|
|
continue;
|
|
}
|
|
|
|
// Make sure non-resetting formatting is AFTER spaces
|
|
// Note: we don't have to check if have next, as empty string is not space or newline
|
|
if (!isSpaceOrNewLine.test(data.processor.getNext().char)) {
|
|
data.processor.addFormat(signal);
|
|
continue;
|
|
}
|
|
|
|
logOrThrowProblem(
|
|
"Non-Resetting Formatting",
|
|
"",
|
|
"Moving",
|
|
"Before Space(s)",
|
|
"After Space(s)",
|
|
);
|
|
|
|
// Add all upcoming space/newline characters
|
|
while (
|
|
data.processor.hasNext() &&
|
|
isSpaceOrNewLine.test(data.processor.getNext().char)
|
|
) {
|
|
data.processor.add(data.processor.toNext().char);
|
|
}
|
|
|
|
// Add formatting
|
|
data.processor.addFormat(signal);
|
|
}
|
|
}
|