Skip to content

Commit

Permalink
Refactor escapeCharacters.test.ts and escapeCharacters.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
Mearman committed Mar 10, 2024
1 parent 6ff3ca9 commit f245d8d
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 15 deletions.
127 changes: 112 additions & 15 deletions __tests__/escapeCharacters.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,118 @@
import {
EscapeCharacterMap,
fromEscaped,
toEscaped,
replaceAllEscapedWithUnescaped,
replaceAllUnescapedWithEscaped,
} from "../src/util/escapeCharacters";

describe("escapeCharacters", () => {
describe("fromEscaped", () => {
describe.each(Array.from(EscapeCharacterMap.entries()))(
"",
(unescaped, escaped) => {
test(`should return ${unescaped} for ${escaped}`, () => {
expect(fromEscaped(escaped)).toBe(unescaped);
});
test(`should return ${escaped} for ${unescaped}`, () => {
expect(toEscaped(unescaped)).toBe(escaped);
});
}
);
const entries = Array.from(EscapeCharacterMap.entries());

describe.each(entries)(`"%s": "%s"`, (unescaped, escaped) => {
const f = {
escaped: createStringVariants(escaped),
unescaped: createStringVariants(unescaped),
mixed: createStringVariants(unescaped, escaped),
};
describe("replaceAllEscapedWithUnescaped", () => {
describe("contiguous", () => {
describe("escaped", () => {
test(`"${f.escaped.contiguous}" -> "${f.unescaped.contiguous}"`, () => {
const result = replaceAllEscapedWithUnescaped(f.escaped.contiguous);
expect(result).toBe(f.unescaped.contiguous);
});
});
describe("unescaped", () => {
test(`"${f.unescaped.contiguous}" -> "${f.unescaped.contiguous}"`, () => {
const result = replaceAllEscapedWithUnescaped(f.unescaped.contiguous);
expect(result).toBe(f.unescaped.contiguous);
});
});
describe("mixed", () => {
test(`"${f.mixed.contiguous}" -> "${f.unescaped.contiguous}"`, () => {
const result = replaceAllEscapedWithUnescaped(f.mixed.contiguous);
expect(result).toBe(f.unescaped.contiguous);
});
});
});
describe("non-contiguous", () => {
describe("escaped", () => {
test(`"${f.escaped.nonContiguous}" -> "${f.unescaped.nonContiguous}"`, () => {
const result = replaceAllEscapedWithUnescaped(
f.escaped.nonContiguous
);
expect(result).toBe(f.unescaped.nonContiguous);
});
});
describe("unescaped", () => {
test(`"${f.unescaped.nonContiguous}" -> "${f.unescaped.nonContiguous}"`, () => {
const result = replaceAllEscapedWithUnescaped(
f.unescaped.nonContiguous
);
expect(result).toBe(f.unescaped.nonContiguous);
});
});
describe("mixed", () => {
test(`"${f.mixed.nonContiguous}" -> "${f.unescaped.nonContiguous}"`, () => {
const result = replaceAllEscapedWithUnescaped(f.mixed.nonContiguous);
expect(result).toBe(f.unescaped.nonContiguous);
});
});
});
});
describe("replaceAllUnescapedWithEscaped", () => {
describe("contiguous", () => {
describe("escaped", () => {
test(`"${f.escaped.contiguous}" -> "${f.escaped.contiguous}"`, () => {
const result = replaceAllUnescapedWithEscaped(f.escaped.contiguous);
expect(result).toBe(f.escaped.contiguous);
});
});
describe("unescaped", () => {
test(`"${f.unescaped.contiguous}" -> "${f.escaped.contiguous}"`, () => {
const result = replaceAllUnescapedWithEscaped(f.unescaped.contiguous);
expect(result).toBe(f.escaped.contiguous);
});
});
describe("mixed", () => {
test(`"${f.mixed.contiguous}" -> "${f.escaped.contiguous}"`, () => {
const result = replaceAllUnescapedWithEscaped(f.mixed.contiguous);
expect(result).toBe(f.escaped.contiguous);
});
});
});
describe("non-contiguous", () => {
describe("escaped", () => {
test(`"${f.escaped.nonContiguous}" -> "${f.escaped.nonContiguous}"`, () => {
const result = replaceAllUnescapedWithEscaped(
f.escaped.nonContiguous
);
expect(result).toBe(f.escaped.nonContiguous);
});
});
describe("unescaped", () => {
test(`"${f.unescaped.nonContiguous}" -> "${f.escaped.nonContiguous}"`, () => {
const result = replaceAllUnescapedWithEscaped(
f.unescaped.nonContiguous
);
expect(result).toBe(f.escaped.nonContiguous);
});
});
describe("mixed", () => {
test(`"${f.mixed.nonContiguous}" -> "${f.escaped.nonContiguous}"`, () => {
const result = replaceAllUnescapedWithEscaped(f.mixed.nonContiguous);
expect(result).toBe(f.escaped.nonContiguous);
});
});
});
});
});

export function createStringVariants(...input: string[]): {
contiguous: string;
nonContiguous: string;
} {
// if count of input is only 1, duplicate it
if (input.length === 1) input.push(input[0]);
const contiguous = input.join("foo");
const nonContiguous = input.join(" foo ");
return { contiguous, nonContiguous };
}
36 changes: 36 additions & 0 deletions src/util/escapeCharacters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,39 @@ export function fromEscaped(escaped: EscapedCharacter): UnescapedCharacter {
* An alias for `fromEscaped`.
*/
export const toUnescaped = fromEscaped;

export function replaceAllEscapedWithUnescaped(input: string): string {
return UnescapedCharacterValues.map((unescaped) => {
const escaped = toEscaped(unescaped);
return [escaped, unescaped];
}, input).reduce(
(prev, [escaped, unescaped]) => prev.split(escaped).join(unescaped),
input
);
}

export function replaceAllUnescapedWithEscaped(input: string): string {
let escapedResult = "";
for (let i = 0; i < input.length; i++) {
const matched: string = EscapedCharacterValues.reduce((prev, escaped) => {
if (prev) return prev;
if (input.slice(i).startsWith(escaped)) {
return escaped;
}
return prev;
}, "");
if (!matched) {
const unescaped = input[i];
if (unescaped in EscapeCharacters) {
const escaped = toEscaped(unescaped as UnescapedCharacter);
escapedResult += escaped;
} else {
escapedResult += unescaped;
}
} else {
escapedResult += matched;
i += matched.length - 1;
}
}
return escapedResult;
}

0 comments on commit f245d8d

Please sign in to comment.