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 htmlWhitespace from "../../utilities/html-whitespace.js";
|
||||||
import { getOrderedListItemInfo, mapAst, splitText } from "../utilities.js";
|
import { getOrderedListItemInfo, mapAst, splitText } from "../utilities.js";
|
||||||
|
import { getBlockquoteRawText } from "../utilities/get-blockquote-raw-text.js";
|
||||||
|
|
||||||
// 0x0 ~ 0x10ffff
|
// 0x0 ~ 0x10ffff
|
||||||
const isSingleCharRegex = /^\\?.$/su;
|
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) {
|
function transformIndentedCodeblock(ast, options) {
|
||||||
return mapAst(ast, (node) => {
|
return mapAst(ast, (node) => {
|
||||||
if (node.type !== "code") {
|
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