diff --git a/tests/e2e/compare/output/markdownTable.js b/tests/e2e/compare/output/markdownTable.js
deleted file mode 100644
index 198ae17daba5..000000000000
--- a/tests/e2e/compare/output/markdownTable.js
+++ /dev/null
@@ -1,368 +0,0 @@
-/* eslint-disable */
-// copied from https://raw.githubusercontent.com/wooorm/markdown-table/main/index.js, turned into cmjs
-
-/**
- * @typedef Options
- *   Configuration (optional).
- * @property {string|null|Array<string|null|undefined>} [align]
- *   One style for all columns, or styles for their respective columns.
- *   Each style is either `'l'` (left), `'r'` (right), or `'c'` (center).
- *   Other values are treated as `''`, which doesn’t place the colon in the
- *   alignment row but does align left.
- *   *Only the lowercased first character is used, so `Right` is fine.*
- * @property {boolean} [padding=true]
- *   Whether to add a space of padding between delimiters and cells.
- *
- *   When `true`, there is padding:
- *
- *   ```markdown
- *   | Alpha | B     |
- *   | ----- | ----- |
- *   | C     | Delta |
- *   ```
- *
- *   When `false`, there is no padding:
- *
- *   ```markdown
- *   |Alpha|B    |
- *   |-----|-----|
- *   |C    |Delta|
- *   ```
- * @property {boolean} [delimiterStart=true]
- *   Whether to begin each row with the delimiter.
- *
- *   > 👉 **Note**: please don’t use this: it could create fragile structures
- *   > that aren’t understandable to some markdown parsers.
- *
- *   When `true`, there are starting delimiters:
- *
- *   ```markdown
- *   | Alpha | B     |
- *   | ----- | ----- |
- *   | C     | Delta |
- *   ```
- *
- *   When `false`, there are no starting delimiters:
- *
- *   ```markdown
- *   Alpha | B     |
- *   ----- | ----- |
- *   C     | Delta |
- *   ```
- * @property {boolean} [delimiterEnd=true]
- *   Whether to end each row with the delimiter.
- *
- *   > 👉 **Note**: please don’t use this: it could create fragile structures
- *   > that aren’t understandable to some markdown parsers.
- *
- *   When `true`, there are ending delimiters:
- *
- *   ```markdown
- *   | Alpha | B     |
- *   | ----- | ----- |
- *   | C     | Delta |
- *   ```
- *
- *   When `false`, there are no ending delimiters:
- *
- *   ```markdown
- *   | Alpha | B
- *   | ----- | -----
- *   | C     | Delta
- *   ```
- * @property {boolean} [alignDelimiters=true]
- *   Whether to align the delimiters.
- *   By default, they are aligned:
- *
- *   ```markdown
- *   | Alpha | B     |
- *   | ----- | ----- |
- *   | C     | Delta |
- *   ```
- *
- *   Pass `false` to make them staggered:
- *
- *   ```markdown
- *   | Alpha | B |
- *   | - | - |
- *   | C | Delta |
- *   ```
- * @property {(value: string) => number} [stringLength]
- *   Function to detect the length of table cell content.
- *   This is used when aligning the delimiters (`|`) between table cells.
- *   Full-width characters and emoji mess up delimiter alignment when viewing
- *   the markdown source.
- *   To fix this, you can pass this function, which receives the cell content
- *   and returns its “visible” size.
- *   Note that what is and isn’t visible depends on where the text is displayed.
- *
- *   Without such a function, the following:
- *
- *   ```js
- *   markdownTable([
- *     ['Alpha', 'Bravo'],
- *     ['中文', 'Charlie'],
- *     ['👩‍❤️‍👩', 'Delta']
- *   ])
- *   ```
- *
- *   Yields:
- *
- *   ```markdown
- *   | Alpha | Bravo |
- *   | - | - |
- *   | 中文 | Charlie |
- *   | 👩‍❤️‍👩 | Delta |
- *   ```
- *
- *   With [`string-width`](https://github.com/sindresorhus/string-width):
- *
- *   ```js
- *   import stringWidth from 'string-width'
- *
- *   markdownTable(
- *     [
- *       ['Alpha', 'Bravo'],
- *       ['中文', 'Charlie'],
- *       ['👩‍❤️‍👩', 'Delta']
- *     ],
- *     {stringLength: stringWidth}
- *   )
- *   ```
- *
- *   Yields:
- *
- *   ```markdown
- *   | Alpha | Bravo   |
- *   | ----- | ------- |
- *   | 中文  | Charlie |
- *   | 👩‍❤️‍👩    | Delta   |
- *   ```
- */
-
-/**
- * @typedef {Options} MarkdownTableOptions
- * @todo
- *   Remove next major.
- */
-
-/**
- * Generate a markdown ([GFM](https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/organizing-information-with-tables)) table..
- *
- * @param {Array<Array<string|null|undefined>>} table
- *   Table data (matrix of strings).
- * @param {Options} [options]
- *   Configuration (optional).
- * @returns {string}
- */
-function markdownTable(table, options = {}) {
-    const align = (options.align || []).concat();
-    const stringLength = options.stringLength || defaultStringLength;
-    /** @type {Array<number>} Character codes as symbols for alignment per column. */
-    const alignments = [];
-    /** @type {Array<Array<string>>} Cells per row. */
-    const cellMatrix = [];
-    /** @type {Array<Array<number>>} Sizes of each cell per row. */
-    const sizeMatrix = [];
-    /** @type {Array<number>} */
-    const longestCellByColumn = [];
-    let mostCellsPerRow = 0;
-    let rowIndex = -1;
-
-    // This is a superfluous loop if we don’t align delimiters, but otherwise we’d
-    // do superfluous work when aligning, so optimize for aligning.
-    while (++rowIndex < table.length) {
-        /** @type {Array<string>} */
-        const row = [];
-        /** @type {Array<number>} */
-        const sizes = [];
-        let columnIndex = -1;
-
-        if (table[rowIndex].length > mostCellsPerRow) {
-            mostCellsPerRow = table[rowIndex].length;
-        }
-
-        while (++columnIndex < table[rowIndex].length) {
-            const cell = serialize(table[rowIndex][columnIndex]);
-
-            if (options.alignDelimiters !== false) {
-                const size = stringLength(cell);
-                sizes[columnIndex] = size;
-
-                if (longestCellByColumn[columnIndex] === undefined || size > longestCellByColumn[columnIndex]) {
-                    longestCellByColumn[columnIndex] = size;
-                }
-            }
-
-            row.push(cell);
-        }
-
-        cellMatrix[rowIndex] = row;
-        sizeMatrix[rowIndex] = sizes;
-    }
-
-    // Figure out which alignments to use.
-    let columnIndex = -1;
-
-    if (typeof align === 'object' && 'length' in align) {
-        while (++columnIndex < mostCellsPerRow) {
-            alignments[columnIndex] = toAlignment(align[columnIndex]);
-        }
-    } else {
-        const code = toAlignment(align);
-
-        while (++columnIndex < mostCellsPerRow) {
-            alignments[columnIndex] = code;
-        }
-    }
-
-    // Inject the alignment row.
-    columnIndex = -1;
-    /** @type {Array<string>} */
-    const row = [];
-    /** @type {Array<number>} */
-    const sizes = [];
-
-    while (++columnIndex < mostCellsPerRow) {
-        const code = alignments[columnIndex];
-        let before = '';
-        let after = '';
-
-        if (code === 99 /* `c` */) {
-            before = ':';
-            after = ':';
-        } else if (code === 108 /* `l` */) {
-            before = ':';
-        } else if (code === 114 /* `r` */) {
-            after = ':';
-        }
-
-        // There *must* be at least one hyphen-minus in each alignment cell.
-        let size = options.alignDelimiters === false ? 1 : Math.max(1, longestCellByColumn[columnIndex] - before.length - after.length);
-
-        const cell = before + '-'.repeat(size) + after;
-
-        if (options.alignDelimiters !== false) {
-            size = before.length + size + after.length;
-
-            if (size > longestCellByColumn[columnIndex]) {
-                longestCellByColumn[columnIndex] = size;
-            }
-
-            sizes[columnIndex] = size;
-        }
-
-        row[columnIndex] = cell;
-    }
-
-    // Inject the alignment row.
-    cellMatrix.splice(1, 0, row);
-    sizeMatrix.splice(1, 0, sizes);
-
-    rowIndex = -1;
-    /** @type {Array<string>} */
-    const lines = [];
-
-    while (++rowIndex < cellMatrix.length) {
-        const row = cellMatrix[rowIndex];
-        const sizes = sizeMatrix[rowIndex];
-        columnIndex = -1;
-        /** @type {Array<string>} */
-        const line = [];
-
-        while (++columnIndex < mostCellsPerRow) {
-            const cell = row[columnIndex] || '';
-            let before = '';
-            let after = '';
-
-            if (options.alignDelimiters !== false) {
-                const size = longestCellByColumn[columnIndex] - (sizes[columnIndex] || 0);
-                const code = alignments[columnIndex];
-
-                if (code === 114 /* `r` */) {
-                    before = ' '.repeat(size);
-                } else if (code === 99 /* `c` */) {
-                    if (size % 2) {
-                        before = ' '.repeat(size / 2 + 0.5);
-                        after = ' '.repeat(size / 2 - 0.5);
-                    } else {
-                        before = ' '.repeat(size / 2);
-                        after = before;
-                    }
-                } else {
-                    after = ' '.repeat(size);
-                }
-            }
-
-            if (options.delimiterStart !== false && !columnIndex) {
-                line.push('|');
-            }
-
-            if (
-                options.padding !== false &&
-                // Don’t add the opening space if we’re not aligning and the cell is
-                // empty: there will be a closing space.
-                !(options.alignDelimiters === false && cell === '') &&
-                (options.delimiterStart !== false || columnIndex)
-            ) {
-                line.push(' ');
-            }
-
-            if (options.alignDelimiters !== false) {
-                line.push(before);
-            }
-
-            line.push(cell);
-
-            if (options.alignDelimiters !== false) {
-                line.push(after);
-            }
-
-            if (options.padding !== false) {
-                line.push(' ');
-            }
-
-            if (options.delimiterEnd !== false || columnIndex !== mostCellsPerRow - 1) {
-                line.push('|');
-            }
-        }
-
-        lines.push(options.delimiterEnd === false ? line.join('').replace(/ +$/, '') : line.join(''));
-    }
-
-    return lines.join('\n');
-}
-
-/**
- * @param {string|null|undefined} [value]
- * @returns {string}
- */
-function serialize(value) {
-    return value === null || value === undefined ? '' : String(value);
-}
-
-/**
- * @param {string} value
- * @returns {number}
- */
-function defaultStringLength(value) {
-    return value.length;
-}
-
-/**
- * @param {string|null|undefined} value
- * @returns {number}
- */
-function toAlignment(value) {
-    const code = typeof value === 'string' ? value.codePointAt(0) : 0;
-
-    return code === 67 /* `C` */ || code === 99 /* `c` */
-        ? 99 /* `c` */
-        : code === 76 /* `L` */ || code === 108 /* `l` */
-        ? 108 /* `l` */
-        : code === 82 /* `R` */ || code === 114 /* `r` */
-        ? 114 /* `r` */
-        : 0;
-}
-
-export default markdownTable;
diff --git a/tests/e2e/compare/output/markdownTable.ts b/tests/e2e/compare/output/markdownTable.ts
new file mode 100644
index 000000000000..51f0beeb6979
--- /dev/null
+++ b/tests/e2e/compare/output/markdownTable.ts
@@ -0,0 +1,354 @@
+// copied from https://raw.githubusercontent.com/wooorm/markdown-table/main/index.js, turned into cmjs
+
+type MarkdownTableOptions = {
+    /**
+     *   One style for all columns, or styles for their respective columns.
+     *   Each style is either `'l'` (left), `'r'` (right), or `'c'` (center).
+     *   Other values are treated as `''`, which doesn’t place the colon in the
+     *   alignment row but does align left.
+     *   *Only the lowercased first character is used, so `Right` is fine.*
+     */
+    align?: string | null | Array<string | null | undefined>;
+
+    /**
+     *   Whether to add a space of padding between delimiters and cells.
+     *
+     *   When `true`, there is padding:
+     *
+     *   ```markdown
+     *   | Alpha | B     |
+     *   | ----- | ----- |
+     *   | C     | Delta |
+     *   ```
+     *
+     *   When `false`, there is no padding:
+     *
+     *   ```markdown
+     *   |Alpha|B    |
+     *   |-----|-----|
+     *   |C    |Delta|
+     *   ```
+     */
+    padding?: boolean;
+
+    /**
+     *   Whether to begin each row with the delimiter.
+     *
+     *   > 👉 **Note**: please don’t use this: it could create fragile structures
+     *   > that aren’t understandable to some markdown parsers.
+     *
+     *   When `true`, there are starting delimiters:
+     *
+     *   ```markdown
+     *   | Alpha | B     |
+     *   | ----- | ----- |
+     *   | C     | Delta |
+     *   ```
+     *
+     *   When `false`, there are no starting delimiters:
+     *
+     *   ```markdown
+     *   Alpha | B     |
+     *   ----- | ----- |
+     *   C     | Delta |
+     *   ```
+     */
+    delimiterStart?: boolean;
+    /**
+     *   Whether to end each row with the delimiter.
+     *
+     *   > 👉 **Note**: please don’t use this: it could create fragile structures
+     *   > that aren’t understandable to some markdown parsers.
+     *
+     *   When `true`, there are ending delimiters:
+     *
+     *   ```markdown
+     *   | Alpha | B     |
+     *   | ----- | ----- |
+     *   | C     | Delta |
+     *   ```
+     *
+     *   When `false`, there are no ending delimiters:
+     *
+     *   ```markdown
+     *   | Alpha | B
+     *   | ----- | -----
+     *   | C     | Delta
+     *   ```
+     */
+    delimiterEnd?: boolean;
+
+    /**
+     *   Whether to align the delimiters.
+     *   By default, they are aligned:
+     *
+     *   ```markdown
+     *   | Alpha | B     |
+     *   | ----- | ----- |
+     *   | C     | Delta |
+     *   ```
+     *
+     *   Pass `false` to make them staggered:
+     *
+     *   ```markdown
+     *   | Alpha | B |
+     *   | - | - |
+     *   | C | Delta |
+     *   ```
+     */
+    alignDelimiters?: boolean;
+
+    /**
+     *   Function to detect the length of table cell content.
+     *   This is used when aligning the delimiters (`|`) between table cells.
+     *   Full-width characters and emoji mess up delimiter alignment when viewing
+     *   the markdown source.
+     *   To fix this, you can pass this function, which receives the cell content
+     *   and returns its “visible” size.
+     *   Note that what is and isn’t visible depends on where the text is displayed.
+     *
+     *   Without such a function, the following:
+     *
+     *   ```js
+     *   markdownTable([
+     *     ['Alpha', 'Bravo'],
+     *     ['中文', 'Charlie'],
+     *     ['👩‍❤️‍👩', 'Delta']
+     *   ])
+     *   ```
+     *
+     *   Yields:
+     *
+     *   ```markdown
+     *   | Alpha | Bravo |
+     *   | - | - |
+     *   | 中文 | Charlie |
+     *   | 👩‍❤️‍👩 | Delta |
+     *   ```
+     *
+     *   With [`string-width`](https://github.com/sindresorhus/string-width):
+     *
+     *   ```js
+     *   import stringWidth from 'string-width'
+     *
+     *   markdownTable(
+     *     [
+     *       ['Alpha', 'Bravo'],
+     *       ['中文', 'Charlie'],
+     *       ['👩‍❤️‍👩', 'Delta']
+     *     ],
+     *     {stringLength: stringWidth}
+     *   )
+     *   ```
+     *
+     *   Yields:
+     *
+     *   ```markdown
+     *   | Alpha | Bravo   |
+     *   | ----- | ------- |
+     *   | 中文  | Charlie |
+     *   | 👩‍❤️‍👩    | Delta   |
+     *   ```
+     */
+    stringLength?: (value: string) => number;
+};
+
+function serialize(value: string | null | undefined): string {
+    return value === null || value === undefined ? '' : String(value);
+}
+
+function defaultStringLength(value: string): number {
+    return value.length;
+}
+
+function toAlignment(value: string | null | undefined): number {
+    const code = typeof value === 'string' ? value.codePointAt(0) : 0;
+
+    if (code === 67 /* `C` */ || code === 99 /* `c` */) {
+        return 99; /* `c` */
+    }
+
+    if (code === 76 /* `L` */ || code === 108 /* `l` */) {
+        return 108; /* `l` */
+    }
+
+    if (code === 82 /* `R` */ || code === 114 /* `r` */) {
+        return 114; /* `r` */
+    }
+
+    return 0;
+}
+
+/** Generate a markdown ([GFM](https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/organizing-information-with-tables)) table.. */
+function markdownTable(table: Array<Array<string | null | undefined>>, options: MarkdownTableOptions = {}) {
+    const align = (options.align ?? []).concat();
+    const stringLength = options.stringLength ?? defaultStringLength;
+    /** Character codes as symbols for alignment per column. */
+    const alignments: number[] = [];
+    /** Cells per row. */
+    const cellMatrix: string[][] = [];
+    /** Sizes of each cell per row. */
+    const sizeMatrix: number[][] = [];
+    const longestCellByColumn: number[] = [];
+    let mostCellsPerRow = 0;
+    let rowIndex = -1;
+
+    // This is a superfluous loop if we don’t align delimiters, but otherwise we’d
+    // do superfluous work when aligning, so optimize for aligning.
+    while (++rowIndex < table.length) {
+        const row: string[] = [];
+        const sizes: number[] = [];
+        let columnIndex = -1;
+
+        if (table[rowIndex].length > mostCellsPerRow) {
+            mostCellsPerRow = table[rowIndex].length;
+        }
+
+        while (++columnIndex < table[rowIndex].length) {
+            const cell = serialize(table[rowIndex][columnIndex]);
+
+            if (options.alignDelimiters !== false) {
+                const size = stringLength(cell);
+                sizes[columnIndex] = size;
+
+                if (longestCellByColumn[columnIndex] === undefined || size > longestCellByColumn[columnIndex]) {
+                    longestCellByColumn[columnIndex] = size;
+                }
+            }
+
+            row.push(cell);
+        }
+
+        cellMatrix[rowIndex] = row;
+        sizeMatrix[rowIndex] = sizes;
+    }
+
+    // Figure out which alignments to use.
+    let columnIndex = -1;
+
+    if (typeof align === 'object' && 'length' in align) {
+        while (++columnIndex < mostCellsPerRow) {
+            alignments[columnIndex] = toAlignment(align[columnIndex]);
+        }
+    } else {
+        const code = toAlignment(align);
+
+        while (++columnIndex < mostCellsPerRow) {
+            alignments[columnIndex] = code;
+        }
+    }
+
+    // Inject the alignment row.
+    columnIndex = -1;
+    const row: string[] = [];
+    const sizes: number[] = [];
+
+    while (++columnIndex < mostCellsPerRow) {
+        const code = alignments[columnIndex];
+        let before = '';
+        let after = '';
+
+        if (code === 99 /* `c` */) {
+            before = ':';
+            after = ':';
+        } else if (code === 108 /* `l` */) {
+            before = ':';
+        } else if (code === 114 /* `r` */) {
+            after = ':';
+        }
+
+        // There *must* be at least one hyphen-minus in each alignment cell.
+        let size = options.alignDelimiters === false ? 1 : Math.max(1, longestCellByColumn[columnIndex] - before.length - after.length);
+
+        const cell = before + '-'.repeat(size) + after;
+
+        if (options.alignDelimiters !== false) {
+            size = before.length + size + after.length;
+
+            if (size > longestCellByColumn[columnIndex]) {
+                longestCellByColumn[columnIndex] = size;
+            }
+
+            sizes[columnIndex] = size;
+        }
+
+        row[columnIndex] = cell;
+    }
+
+    // Inject the alignment row.
+    cellMatrix.splice(1, 0, row);
+    sizeMatrix.splice(1, 0, sizes);
+
+    rowIndex = -1;
+    const lines: string[] = [];
+
+    while (++rowIndex < cellMatrix.length) {
+        const matrixRow = cellMatrix[rowIndex];
+        const matrixSizes = sizeMatrix[rowIndex];
+        columnIndex = -1;
+        const line: string[] = [];
+
+        while (++columnIndex < mostCellsPerRow) {
+            const cell = matrixRow[columnIndex] || '';
+            let before = '';
+            let after = '';
+
+            if (options.alignDelimiters !== false) {
+                const size = longestCellByColumn[columnIndex] - (matrixSizes[columnIndex] || 0);
+                const code = alignments[columnIndex];
+
+                if (code === 114 /* `r` */) {
+                    before = ' '.repeat(size);
+                } else if (code === 99 /* `c` */) {
+                    if (size % 2) {
+                        before = ' '.repeat(size / 2 + 0.5);
+                        after = ' '.repeat(size / 2 - 0.5);
+                    } else {
+                        before = ' '.repeat(size / 2);
+                        after = before;
+                    }
+                } else {
+                    after = ' '.repeat(size);
+                }
+            }
+
+            if (options.delimiterStart !== false && !columnIndex) {
+                line.push('|');
+            }
+
+            if (
+                options.padding !== false &&
+                // Don’t add the opening space if we’re not aligning and the cell is
+                // empty: there will be a closing space.
+                !(options.alignDelimiters === false && cell === '') &&
+                (options.delimiterStart !== false || columnIndex)
+            ) {
+                line.push(' ');
+            }
+
+            if (options.alignDelimiters !== false) {
+                line.push(before);
+            }
+
+            line.push(cell);
+
+            if (options.alignDelimiters !== false) {
+                line.push(after);
+            }
+
+            if (options.padding !== false) {
+                line.push(' ');
+            }
+
+            if (options.delimiterEnd !== false || columnIndex !== mostCellsPerRow - 1) {
+                line.push('|');
+            }
+        }
+
+        lines.push(options.delimiterEnd === false ? line.join('').replace(/ +$/, '') : line.join(''));
+    }
+
+    return lines.join('\n');
+}
+
+export default markdownTable;
