Improve > handling in blockquote in Markdown (#19802)
Co-authored-by: codex <codex@openai.com> Co-authored-by: fisker Cheung <lionkay@gmail.com> Co-authored-by: fisker <lionkay@gmail.com>
This commit is contained in:
1 parent
b766f660b1
commit
ca76fda52d
10 files changed
+304
-13
No files matched your search
@@ -0,0 +1,13 @@
|
||||
#### Fix Markdown blockquote containing `>` characters (#19802 by @seiyab)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```md
|
||||
<!-- Input -->
|
||||
> **test**\>
|
||||
|
||||
<!-- Prettier stable -->
|
||||
> **test**>\>
|
||||
|
||||
<!-- Prettier main -->
|
||||
> **test**\>
|
||||
```
|
||||
@@ -1,5 +1,6 @@
|
||||
import htmlWhitespace from "../../utilities/html-whitespace.js";
|
||||
import { getOrderedListItemInfo, mapAst, splitText } from "../utilities.js";
|
||||
import { getBlockquoteRawText } from "../utilities/get-blockquote-raw-text.js";
|
||||
|
||||
// 0x0 ~ 0x10ffff
|
||||
const isSingleCharRegex = /^\\?.$/su;
|
||||
@@ -248,19 +249,6 @@ function splitTextIntoSentences(ast) {
|
||||
}
|
||||
}
|
||||
|
||||
function getBlockquoteRawText(text, node) {
|
||||
const angleBracketsRegex = /^([ \t]*>[ \t]*)*/;
|
||||
const rawLines = text.split("\n");
|
||||
const valueLines = node.value.split("\n");
|
||||
const resultLines = rawLines.map((rawLine, index) => {
|
||||
const valueLine = valueLines[index] ?? "";
|
||||
const leadingTextAngleBrackets =
|
||||
valueLine.match(angleBracketsRegex)[0] ?? "";
|
||||
return rawLine.replace(angleBracketsRegex, leadingTextAngleBrackets);
|
||||
});
|
||||
return resultLines.join("\n");
|
||||
}
|
||||
|
||||
function transformIndentedCodeblock(ast, options) {
|
||||
return mapAst(ast, (node) => {
|
||||
if (node.type !== "code") {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @param line {string}
|
||||
* @returns {number}
|
||||
*/
|
||||
function countValueLeadingGreaterThan(line) {
|
||||
let count = 0;
|
||||
|
||||
for (const character of line) {
|
||||
if (character === ">") {
|
||||
count++;
|
||||
} else if (character !== " " && character !== "\t") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param line {string}
|
||||
* @param greaterThanToKeep {number}
|
||||
* @returns {string}
|
||||
*/
|
||||
function removeBlockquoteMarkers(line, greaterThanToKeep) {
|
||||
const rawBlockquoteRegexp =
|
||||
/[ \t]*(?:>|\\>|>|>|�*62;|&#[xX]0*3[eE];)[ \t]*/y;
|
||||
/** @type {Array<number>} */
|
||||
const greaterThanIndexes = [];
|
||||
let { lastIndex } = rawBlockquoteRegexp;
|
||||
|
||||
let match;
|
||||
while ((match = rawBlockquoteRegexp.exec(line))) {
|
||||
greaterThanIndexes.push(match.index);
|
||||
lastIndex = rawBlockquoteRegexp.lastIndex;
|
||||
}
|
||||
|
||||
if (greaterThanToKeep === 0) {
|
||||
return line.slice(lastIndex);
|
||||
}
|
||||
const firstGreaterThanToKeep = greaterThanIndexes.at(-greaterThanToKeep);
|
||||
/* c8 ignore next 3 */
|
||||
if (firstGreaterThanToKeep === null) {
|
||||
return line;
|
||||
}
|
||||
return line.slice(firstGreaterThanToKeep);
|
||||
}
|
||||
|
||||
const newLineRegexp = /(?<!\\)(?:\\\\)*(?:
|�*10;|&#[Xx]0*[Aa];)/g;
|
||||
function getBlockquoteRawText(text, node) {
|
||||
const rawLines = text.split("\n");
|
||||
const valueLines = node.value.split("\n");
|
||||
let valueIndex = 0;
|
||||
const resultLines = rawLines.map((rawLine, index) => {
|
||||
const valueLine = valueLines[valueIndex++];
|
||||
const decodedNewlines = rawLine.matchAll(newLineRegexp);
|
||||
valueIndex += [...decodedNewlines].length;
|
||||
|
||||
if (index === 0) {
|
||||
return rawLine;
|
||||
}
|
||||
const valueMarkerCount = countValueLeadingGreaterThan(valueLine);
|
||||
return removeBlockquoteMarkers(rawLine, valueMarkerCount);
|
||||
});
|
||||
return resultLines.join("\n");
|
||||
}
|
||||
|
||||
export { getBlockquoteRawText };
|
||||
@@ -0,0 +1,162 @@
|
||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`encoded-greater-than.md - {"proseWrap":"always"} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["markdown"]
|
||||
proseWrap: "always"
|
||||
printWidth: 80 (default) |
|
||||
=====================================input======================================
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
|
||||
=====================================output=====================================
|
||||
> > a > b
|
||||
|
||||
> > a > b
|
||||
|
||||
> > a > b
|
||||
|
||||
> > a > b
|
||||
|
||||
> > a > b
|
||||
|
||||
> > a > b
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`encoded-newline.md - {"proseWrap":"always"} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["markdown"]
|
||||
proseWrap: "always"
|
||||
printWidth: 80 (default) |
|
||||
=====================================input======================================
|
||||
> a b
|
||||
> > c
|
||||
|
||||
> a 
 b
|
||||
> > c
|
||||
|
||||
> a 
 b
|
||||
> \\> c
|
||||
|
||||
> a b
|
||||
> c
|
||||
|
||||
> a &newline; b
|
||||
> \\> c
|
||||
|
||||
> a \\
 b
|
||||
> \\> c
|
||||
|
||||
> a \\\\
 b
|
||||
> \\> c
|
||||
|
||||
=====================================output=====================================
|
||||
> a b > c
|
||||
|
||||
> a 
 b > c
|
||||
|
||||
> a 
 b \\> c
|
||||
|
||||
> a b > c
|
||||
|
||||
> a &newline; b \\> c
|
||||
|
||||
> a \\
 b \\> c
|
||||
|
||||
> a \\\\
 b \\> c
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`escaped-greater-than.md - {"proseWrap":"always"} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["markdown"]
|
||||
proseWrap: "always"
|
||||
printWidth: 80 (default) |
|
||||
=====================================input======================================
|
||||
> \\>
|
||||
> \\>
|
||||
|
||||
> *text* > \\>
|
||||
|
||||
> abc
|
||||
> \\> abc
|
||||
|
||||
=====================================output=====================================
|
||||
> \\> \\>
|
||||
|
||||
> _text_ > \\>
|
||||
|
||||
> abc \\> abc
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`indented-greater-than.md - {"proseWrap":"always"} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["markdown"]
|
||||
proseWrap: "always"
|
||||
printWidth: 80 (default) |
|
||||
=====================================input======================================
|
||||
> first
|
||||
> second
|
||||
|
||||
> first
|
||||
> second
|
||||
|
||||
> > first
|
||||
> second
|
||||
|
||||
> first
|
||||
>> second
|
||||
|
||||
=====================================output=====================================
|
||||
> first > second
|
||||
|
||||
> first > second
|
||||
|
||||
> > first > second
|
||||
|
||||
> first >> second
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`issue-19528.md - {"proseWrap":"always"} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["markdown"]
|
||||
proseWrap: "always"
|
||||
printWidth: 80 (default) |
|
||||
=====================================input======================================
|
||||
> test\\>
|
||||
|
||||
> **test**\\>
|
||||
|
||||
> \\>
|
||||
|
||||
=====================================output=====================================
|
||||
> test\\>
|
||||
|
||||
> **test**\\>
|
||||
|
||||
> \\>
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
@@ -0,0 +1,17 @@
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
|
||||
> > a
|
||||
> > b
|
||||
@@ -0,0 +1,20 @@
|
||||
> a b
|
||||
> > c
|
||||
|
||||
> a 
 b
|
||||
> > c
|
||||
|
||||
> a 
 b
|
||||
> \> c
|
||||
|
||||
> a b
|
||||
> c
|
||||
|
||||
> a &newline; b
|
||||
> \> c
|
||||
|
||||
> a \
 b
|
||||
> \> c
|
||||
|
||||
> a \\
 b
|
||||
> \> c
|
||||
@@ -0,0 +1,7 @@
|
||||
> \>
|
||||
> \>
|
||||
|
||||
> *text* > \>
|
||||
|
||||
> abc
|
||||
> \> abc
|
||||
@@ -0,0 +1 @@
|
||||
runFormatTest(import.meta, ["markdown"], { proseWrap: "always" });
|
||||
@@ -0,0 +1,11 @@
|
||||
> first
|
||||
> second
|
||||
|
||||
> first
|
||||
> second
|
||||
|
||||
> > first
|
||||
> second
|
||||
|
||||
> first
|
||||
>> second
|
||||
@@ -0,0 +1,5 @@
|
||||
> test\>
|
||||
|
||||
> **test**\>
|
||||
|
||||
> \>
|
||||
Reference in new issue
Block a user