Adversarial input
Patterns that make a careless parser quadratic, one per way it can go wrong: an opener that
never closes and so scans to the end each time (${, <!--, :span[, `), a structure
nested deeper on every line (>, list items, :::), and a repeat whose bookkeeping grows with
the count (heading ids, attribute lines). Each takes a count and returns input that grows in
proportion to it, so the test can hold the time to the same proportion. Every pattern here once
failed, or guards a scan that would.
export const PATTERNS: Record<string, (n: number) => string> = {
// Openers that never close.
"unclosed ${": (n) => "${a ".repeat(n),
"unclosed ${ in a link": (n) => "[a](${b ".repeat(n),
"unclosed ${ in an attribute": (n) => ":span[a]{x=${ ".repeat(n),
"unclosed string in ${": (n) => "${\\'".repeat(n),
"unclosed comment in ${": (n) => "${/*".repeat(n),
"unclosed template in ${": (n) => "${`".repeat(n),
"unclosed code": (n) => "`a ".repeat(n),
"unclosed code runs": (n) => "a`` `".repeat(n),
"unclosed math": (n) => "$a ".repeat(n),
"dollar runs": (n) =>
Array.from({ length: n }, (_, i) => "$".repeat((i % 50) + 1) + "a").join(""),
"code runs": (n) => Array.from({ length: n }, (_, i) => "`".repeat((i % 50) + 1) + "a").join(""),
"unclosed link": (n) => "[a ".repeat(n),
"unclosed destination": (n) => "[a](b ".repeat(n),
"unclosed angle destination": (n) => "[a](<b ".repeat(n),
"unclosed image": (n) => "![a ".repeat(n),
"unclosed inline comment": (n) => "a <!-- ".repeat(n),
"unclosed processing instruction": (n) => "<? ".repeat(n),
"unclosed declaration": (n) => "<!a ".repeat(n),
"unclosed CDATA": (n) => "<![CDATA[ ".repeat(n),
"unclosed tag": (n) => "<a b ".repeat(n),
"unclosed autolink": (n) => "<http://a ".repeat(n),
"unclosed label": (n) => ":span[a ".repeat(n),
"nested labels": (n) => ":span[".repeat(n),
"unclosed attributes": (n) => ":span[a]{.b ".repeat(n),
"unclosed attribute lines": (n) => "- {.a\n".repeat(n) + "}",
"unclosed block comment": (n) => "<!--\n" + "a\n".repeat(n),
"unclosed fence": (n) => "```\n" + "a\n".repeat(n),
// Emphasis and links.
"emphasis openers": (n) => "_a **b ".repeat(n),
"strikethrough openers": (n) => "~~a ".repeat(n),
"nested emphasis": (n) => "_a ".repeat(n) + "_".repeat(n),
"quotes among markers": (n) => "a_\"'~~*".repeat(n) + "_".repeat(n) + '"'.repeat(n),
"nested brackets": (n) => "[".repeat(n) + "a" + "]".repeat(n),
"links in links": (n) => "[a ".repeat(n) + "](".repeat(n),
"bare URLs": (n) => "www.a ".repeat(n),
// Depth.
"nested blockquotes": (n) => ">".repeat(n) + " a\n",
"nested list items": (n) => "- ".repeat(n) + "a\n",
"blank lines in nested items": (n) => "- ".repeat(n) + "a\n" + "\n".repeat(n),
"continuation of nested items": (n) => "- ".repeat(n) + "a\n" + " ".repeat(2 * n) + "b\n",
"blank quote lines around items": (n) => "> " + "- ".repeat(n) + "a\n" + ">\n".repeat(n),
"unclosed containers": (n) => ":::div\n".repeat(n),
"unclosed containers with blank lines": (n) => ":::div\n\n".repeat(n),
"closing inner containers": (n) => "::::::::::div\n".repeat(n) + ":::div\n:::\n".repeat(n),
// Repeats.
headings: (n) => "# a\n".repeat(n),
"attribute lines": (n) => "{.a}\n".repeat(n),
"orphan attribute lines": (n) => "{.a\n\n".repeat(n),
"table rows": (n) => "| a | b |\n| - | - |\n" + "| c | d |\n".repeat(n),
"wide table": (n) => "|" + " a |".repeat(n) + "\n|" + " - |".repeat(n) + "\n",
"reference definitions": (n) => "[a]: b\n".repeat(n),
"metadata lines": (n) => "---\n" + "a: [b\n".repeat(n),
"CRLF lines": (n) => "a\r\n".repeat(n),
"CR lines": (n) => "a\r".repeat(n),
};