Add helpers for working with words

This commit is contained in:
Tangent Wantwight 2023-08-26 01:16:22 -04:00
parent c39b4a4931
commit 1eb6d179be
2 changed files with 99 additions and 5 deletions

60
src/words.test.ts Normal file
View file

@ -0,0 +1,60 @@
import { AsHtml, AsText, Concat } from "./words";
describe("Text Words", () => {
test.each([
[{ enchanted: "apple" }, "apple"],
[{ enchanted: "<pie>" }, "<pie>"],
[{ text: "banana" }, "banana"],
[{ text: "<b>kiwi" }, "<b>kiwi"],
[{ html: "<b>cherry</b>" }, "<b>cherry</b>"],
])("AsText(%s)", (word, expected) => expect(AsText(word)).toEqual(expected));
test.each([
[{ enchanted: "apple" }, "apple"],
[{ enchanted: "<pie>" }, "&lt;pie&gt;"],
[{ text: "banana" }, "banana"],
[{ text: "<b>kiwi" }, "&lt;b&gt;kiwi"],
[{ html: "<b>cherry</b>" }, "<b>cherry</b>"],
])("AsHtml(%s)", (word, expected) => expect(AsHtml(word)).toEqual(expected));
test.each([
[null, { enchanted: "1" }, { text: "1" }],
[null, { enchanted: ">1" }, { text: ">1" }],
[null, { text: "2" }, { text: "2" }],
[null, { text: "<b>3</b>" }, { text: "<b>3</b>" }],
[null, { html: "2" }, { html: "2" }],
[null, { html: "<b>3</b>" }, { html: "<b>3</b>" }],
[{ enchanted: "&pple" }, { enchanted: "1" }, { text: "&pple1" }],
[{ enchanted: "&pple" }, { enchanted: ">1" }, { text: "&pple>1" }],
[{ enchanted: "&pple" }, { text: "2" }, { text: "&pple2" }],
[{ enchanted: "&pple" }, { text: "<b>3</b>" }, { text: "&pple<b>3</b>" }],
[{ enchanted: "&pple" }, { html: "2" }, { html: "&amp;pple2" }],
[
{ enchanted: "&pple" },
{ html: "<b>3</b>" },
{ html: "&amp;pple<b>3</b>" },
],
[{ text: "<b>anana" }, { enchanted: "1" }, { text: "<b>anana1" }],
[{ text: "<b>anana" }, { enchanted: ">1" }, { text: "<b>anana>1" }],
[{ text: "<b>anana" }, { text: "2" }, { text: "<b>anana2" }],
[{ text: "<b>anana" }, { text: "<b>3</b>" }, { text: "<b>anana<b>3</b>" }],
[{ text: "<b>anana" }, { html: "2" }, { html: "&lt;b&gt;anana2" }],
[
{ text: "<b>anana" },
{ html: "<b>3</b>" },
{ html: "&lt;b&gt;anana<b>3</b>" },
],
[{ html: "<img />" }, { enchanted: "1" }, { html: "<img />1" }],
[{ html: "<img />" }, { enchanted: ">1" }, { html: "<img />&gt;1" }],
[{ html: "<img />" }, { text: "2" }, { html: "<img />2" }],
[
{ html: "<img />" },
{ text: "<b>3</b>" },
{ html: "<img />&lt;b&gt;3&lt;/b&gt;" },
],
[{ html: "<img />" }, { html: "2" }, { html: "<img />2" }],
[{ html: "<img />" }, { html: "<b>3</b>" }, { html: "<img /><b>3</b>" }],
])("Concat(%s, %s)", (left, right, expected) =>
expect(Concat(left, right)).toEqual(expected)
);
});

View file

@ -1,3 +1,5 @@
import { escapeHtml } from "./helpers";
/**
* A word whose value is text with provenance- this literal value appeared in the source
* code, and was not the result of any backslash, variable, or command substitutions.
@ -29,7 +31,7 @@ export type HtmlWord = {
html: string;
};
export type TextPiece = TextWord;
export type TextPiece = EnchantedWord | TextWord | HtmlWord;
export type VariablePiece = { variable: string };
export type ScriptPiece = { script: Script };
export type InterpolatedPiece = TextPiece | VariablePiece | ScriptPiece;
@ -42,18 +44,50 @@ export type InterpolatedWord = {
pieces: InterpolatedPiece[];
};
export function AsText(word: TextPiece): string {
if ("enchanted" in word) {
return word.enchanted;
} else if ("text" in word) {
return word.text;
} else if ("html" in word) {
return word.html;
} else {
return "";
}
}
export function AsHtml(word: TextPiece): string {
if ("enchanted" in word) {
return escapeHtml(word.enchanted);
} else if ("text" in word) {
return escapeHtml(word.text);
} else if ("html" in word) {
return word.html;
} else {
return "";
}
}
// safely concatenate text pieces, converting as needed
export function Concat(left: TextPiece, right: TextPiece) {
return { text: left.text + right.text };
export function Concat(left: TextPiece | null, right: TextPiece) {
if (left === null) {
return "enchanted" in right ? { text: right.enchanted } : right;
}
if ("html" in left || "html" in right) {
return { html: AsHtml(left) + AsHtml(right) };
} else {
return { text: AsText(left) + AsText(right) };
}
}
function IsTextPiece(piece: InterpolatedPiece | undefined): piece is TextPiece {
return piece ? "text" in piece : false;
return piece
? "text" in piece || "enchanted" in piece || "html" in piece
: false;
}
export function SimplifyWord(
pieces: InterpolatedPiece[]
): InterpolatedWord | TextWord {
): InterpolatedWord | EnchantedWord | TextWord | HtmlWord {
const consolidated: InterpolatedPiece[] = [];
for (const piece of pieces) {
const top = consolidated[consolidated.length - 1];