mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(formatter_markdown): treat link destinations and footnote references as opaque to code span fences (#27948)
Fixes #27844, closes #27943. Also fixed potential bugs with footnote.
This commit is contained in:
1 parent
4d8195c183
commit
2645d2c76c
3 files changed
+128
-18
No files matched your search
@@ -10,7 +10,7 @@ use cow_utils::CowUtils;
|
||||
use oxc_formatter_core::arena_cow_str;
|
||||
use oxc_markdown_parser::{
|
||||
Constructs, Span,
|
||||
ast::{CodeSpan, Emphasis, HardBreakKind, Inline, LinkKind, Strong},
|
||||
ast::{CodeSpan, Emphasis, HardBreakKind, Inline, LinkKind, ReferenceKind, Strong},
|
||||
escapes_next, lexical, unicode,
|
||||
};
|
||||
|
||||
@@ -106,7 +106,7 @@ pub fn collect_phrasing<'a>(
|
||||
|
||||
/// For every code span, the backtick run lengths (bit `n - 1` for a run of `n`) that occur
|
||||
/// before it in the content as literal text
|
||||
/// (outside code spans, HTML, autolinks, math, liquid, whose backticks never delimit):
|
||||
/// (outside the spans of `collect_opaque_spans`, whose backticks never delimit):
|
||||
/// a printed fence of such a length would pair with the run and move the span.
|
||||
fn code_span_literal_runs<'a>(
|
||||
children: &'a [Inline<'a>],
|
||||
@@ -144,11 +144,13 @@ fn collect_opaque_spans<'a>(children: &'a [Inline<'a>], out: &mut Vec<(Span, boo
|
||||
| Inline::AutolinkLiteral(_)
|
||||
| Inline::MathSpan(_)
|
||||
| Inline::Liquid(_)
|
||||
| Inline::WikiLink(_) => out.push((child.span(), false)),
|
||||
| Inline::WikiLink(_)
|
||||
| Inline::FootnoteReference(_) => out.push((child.span(), false)),
|
||||
Inline::Emphasis(e) => collect_opaque_spans(&e.children, out),
|
||||
Inline::Strong(s) => collect_opaque_spans(&s.children, out),
|
||||
Inline::Strikethrough(s) => collect_opaque_spans(&s.children, out),
|
||||
// Link text is inline content; a reference label or a title is not
|
||||
// Link text is inline content; a destination, a title or a full reference's label is not
|
||||
// (a collapsed / shortcut one is the text itself)
|
||||
Inline::Link(l) => {
|
||||
collect_opaque_spans(&l.children, out);
|
||||
collect_link_kind_spans(&l.kind, out);
|
||||
@@ -163,12 +165,16 @@ fn collect_opaque_spans<'a>(children: &'a [Inline<'a>], out: &mut Vec<(Span, boo
|
||||
}
|
||||
|
||||
fn collect_link_kind_spans(kind: &LinkKind<'_>, out: &mut Vec<(Span, bool)>) {
|
||||
let pieces = match kind {
|
||||
LinkKind::Reference { label, .. } => label,
|
||||
LinkKind::Inline { title: Some(title), .. } => title,
|
||||
LinkKind::Inline { title: None, .. } => return,
|
||||
};
|
||||
out.extend(pieces.iter().map(|piece| (piece.span, false)));
|
||||
match kind {
|
||||
LinkKind::Reference { kind: ReferenceKind::Full, label } => {
|
||||
out.extend(label.iter().map(|piece| (piece.span, false)));
|
||||
}
|
||||
LinkKind::Reference { .. } => {}
|
||||
LinkKind::Inline { destination, title } => {
|
||||
out.push((destination.span, false));
|
||||
out.extend(title.iter().flatten().map(|piece| (piece.span, false)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The emphasis marker as printed: `_` unless a word touches it (`1*2*3` is emphasis, `1_2_3` is not),
|
||||
|
||||
+14
-1
@@ -1,4 +1,5 @@
|
||||
<!-- A code span fence never equals a literal backtick run before it.
|
||||
<!-- A code span fence never equals a literal backtick run before it
|
||||
(one in a link target or a footnote reference is none, one in a reference's text is).
|
||||
Emphasis markers normalize only when the printed text pairs as the source did;
|
||||
otherwise they stay as written -->
|
||||
|
||||
@@ -14,6 +15,18 @@ No stray run here, so ``code`` shrinks and __strong__ and *emphasis* normalize.
|
||||
|
||||
*a**b* keeps its inner run escaped, and _a\_\_b_ its normalized marker.
|
||||
|
||||
Link targets keep `code`: [a](<x.md#`b` c>), [a](x`y "t`"), .
|
||||
|
||||
A footnote reference [^a`b] keeps `code`.
|
||||
|
||||
A shortcut reference [a`b] keeps ``code``.
|
||||
|
||||
A collapsed reference [a`b][] keeps ``code``.
|
||||
|
||||
[a`b]: /u
|
||||
|
||||
[^a`b]: note
|
||||
|
||||
A backslash \ before a line break stays on its line, never a hard break \
|
||||
when the next word arrives.
|
||||
|
||||
|
||||
+98
-7
@@ -2,7 +2,8 @@
|
||||
source: crates/oxc_formatter_markdown/tests/fixtures/mod.rs
|
||||
---
|
||||
==================== Input ====================
|
||||
<!-- A code span fence never equals a literal backtick run before it.
|
||||
<!-- A code span fence never equals a literal backtick run before it
|
||||
(one in a link target or a footnote reference is none, one in a reference's text is).
|
||||
Emphasis markers normalize only when the printed text pairs as the source did;
|
||||
otherwise they stay as written -->
|
||||
|
||||
@@ -18,6 +19,18 @@ No stray run here, so ``code`` shrinks and __strong__ and *emphasis* normalize.
|
||||
|
||||
*a**b* keeps its inner run escaped, and _a\_\_b_ its normalized marker.
|
||||
|
||||
Link targets keep `code`: [a](<x.md#`b` c>), [a](x`y "t`"), .
|
||||
|
||||
A footnote reference [^a`b] keeps `code`.
|
||||
|
||||
A shortcut reference [a`b] keeps ``code``.
|
||||
|
||||
A collapsed reference [a`b][] keeps ``code``.
|
||||
|
||||
[a`b]: /u
|
||||
|
||||
[^a`b]: note
|
||||
|
||||
A backslash \ before a line break stays on its line, never a hard break \
|
||||
when the next word arrives.
|
||||
|
||||
@@ -31,7 +44,8 @@ text\
|
||||
---------------------------------------
|
||||
{ printWidth: 80, proseWrap: "always" }
|
||||
---------------------------------------
|
||||
<!-- A code span fence never equals a literal backtick run before it.
|
||||
<!-- A code span fence never equals a literal backtick run before it
|
||||
(one in a link target or a footnote reference is none, one in a reference's text is).
|
||||
Emphasis markers normalize only when the printed text pairs as the source did;
|
||||
otherwise they stay as written -->
|
||||
|
||||
@@ -50,6 +64,18 @@ differently.
|
||||
|
||||
_a\*\*b_ keeps its inner run escaped, and _a\_\_b_ its normalized marker.
|
||||
|
||||
Link targets keep `code`: [a](<x.md#`b` c>), [a](x`y "t`"), .
|
||||
|
||||
A footnote reference [^a`b] keeps `code`.
|
||||
|
||||
A shortcut reference [a`b] keeps ``code``.
|
||||
|
||||
A collapsed reference [a`b][] keeps ``code``.
|
||||
|
||||
[a`b]: /u
|
||||
|
||||
[^a`b]: note
|
||||
|
||||
A backslash \ before a line break stays on its line, never a hard break \
|
||||
when the next word arrives.
|
||||
|
||||
@@ -63,7 +89,8 @@ text
|
||||
----------------------------------------
|
||||
{ printWidth: 100, proseWrap: "always" }
|
||||
----------------------------------------
|
||||
<!-- A code span fence never equals a literal backtick run before it.
|
||||
<!-- A code span fence never equals a literal backtick run before it
|
||||
(one in a link target or a footnote reference is none, one in a reference's text is).
|
||||
Emphasis markers normalize only when the printed text pairs as the source did;
|
||||
otherwise they stay as written -->
|
||||
|
||||
@@ -79,6 +106,18 @@ No stray run here, so `code` shrinks and **strong** and _emphasis_ normalize.
|
||||
|
||||
_a\*\*b_ keeps its inner run escaped, and _a\_\_b_ its normalized marker.
|
||||
|
||||
Link targets keep `code`: [a](<x.md#`b` c>), [a](x`y "t`"), .
|
||||
|
||||
A footnote reference [^a`b] keeps `code`.
|
||||
|
||||
A shortcut reference [a`b] keeps ``code``.
|
||||
|
||||
A collapsed reference [a`b][] keeps ``code``.
|
||||
|
||||
[a`b]: /u
|
||||
|
||||
[^a`b]: note
|
||||
|
||||
A backslash \ before a line break stays on its line, never a hard break \
|
||||
when the next word arrives.
|
||||
|
||||
@@ -91,7 +130,8 @@ text\
|
||||
--------------------------------------
|
||||
{ printWidth: 80, proseWrap: "never" }
|
||||
--------------------------------------
|
||||
<!-- A code span fence never equals a literal backtick run before it.
|
||||
<!-- A code span fence never equals a literal backtick run before it
|
||||
(one in a link target or a footnote reference is none, one in a reference's text is).
|
||||
Emphasis markers normalize only when the printed text pairs as the source did;
|
||||
otherwise they stay as written -->
|
||||
|
||||
@@ -107,6 +147,18 @@ No stray run here, so `code` shrinks and **strong** and _emphasis_ normalize.
|
||||
|
||||
_a\*\*b_ keeps its inner run escaped, and _a\_\_b_ its normalized marker.
|
||||
|
||||
Link targets keep `code`: [a](<x.md#`b` c>), [a](x`y "t`"), .
|
||||
|
||||
A footnote reference [^a`b] keeps `code`.
|
||||
|
||||
A shortcut reference [a`b] keeps ``code``.
|
||||
|
||||
A collapsed reference [a`b][] keeps ``code``.
|
||||
|
||||
[a`b]: /u
|
||||
|
||||
[^a`b]: note
|
||||
|
||||
A backslash \ before a line break stays on its line, never a hard break \
|
||||
when the next word arrives.
|
||||
|
||||
@@ -119,7 +171,8 @@ text\
|
||||
---------------------------------------
|
||||
{ printWidth: 100, proseWrap: "never" }
|
||||
---------------------------------------
|
||||
<!-- A code span fence never equals a literal backtick run before it.
|
||||
<!-- A code span fence never equals a literal backtick run before it
|
||||
(one in a link target or a footnote reference is none, one in a reference's text is).
|
||||
Emphasis markers normalize only when the printed text pairs as the source did;
|
||||
otherwise they stay as written -->
|
||||
|
||||
@@ -135,6 +188,18 @@ No stray run here, so `code` shrinks and **strong** and _emphasis_ normalize.
|
||||
|
||||
_a\*\*b_ keeps its inner run escaped, and _a\_\_b_ its normalized marker.
|
||||
|
||||
Link targets keep `code`: [a](<x.md#`b` c>), [a](x`y "t`"), .
|
||||
|
||||
A footnote reference [^a`b] keeps `code`.
|
||||
|
||||
A shortcut reference [a`b] keeps ``code``.
|
||||
|
||||
A collapsed reference [a`b][] keeps ``code``.
|
||||
|
||||
[a`b]: /u
|
||||
|
||||
[^a`b]: note
|
||||
|
||||
A backslash \ before a line break stays on its line, never a hard break \
|
||||
when the next word arrives.
|
||||
|
||||
@@ -147,7 +212,8 @@ text\
|
||||
-----------------------------------------
|
||||
{ printWidth: 80, proseWrap: "preserve" }
|
||||
-----------------------------------------
|
||||
<!-- A code span fence never equals a literal backtick run before it.
|
||||
<!-- A code span fence never equals a literal backtick run before it
|
||||
(one in a link target or a footnote reference is none, one in a reference's text is).
|
||||
Emphasis markers normalize only when the printed text pairs as the source did;
|
||||
otherwise they stay as written -->
|
||||
|
||||
@@ -163,6 +229,18 @@ No stray run here, so `code` shrinks and **strong** and _emphasis_ normalize.
|
||||
|
||||
_a\*\*b_ keeps its inner run escaped, and _a\_\_b_ its normalized marker.
|
||||
|
||||
Link targets keep `code`: [a](<x.md#`b` c>), [a](x`y "t`"), .
|
||||
|
||||
A footnote reference [^a`b] keeps `code`.
|
||||
|
||||
A shortcut reference [a`b] keeps ``code``.
|
||||
|
||||
A collapsed reference [a`b][] keeps ``code``.
|
||||
|
||||
[a`b]: /u
|
||||
|
||||
[^a`b]: note
|
||||
|
||||
A backslash \ before a line break stays on its line, never a hard break \
|
||||
when the next word arrives.
|
||||
|
||||
@@ -175,7 +253,8 @@ text\
|
||||
------------------------------------------
|
||||
{ printWidth: 100, proseWrap: "preserve" }
|
||||
------------------------------------------
|
||||
<!-- A code span fence never equals a literal backtick run before it.
|
||||
<!-- A code span fence never equals a literal backtick run before it
|
||||
(one in a link target or a footnote reference is none, one in a reference's text is).
|
||||
Emphasis markers normalize only when the printed text pairs as the source did;
|
||||
otherwise they stay as written -->
|
||||
|
||||
@@ -191,6 +270,18 @@ No stray run here, so `code` shrinks and **strong** and _emphasis_ normalize.
|
||||
|
||||
_a\*\*b_ keeps its inner run escaped, and _a\_\_b_ its normalized marker.
|
||||
|
||||
Link targets keep `code`: [a](<x.md#`b` c>), [a](x`y "t`"), .
|
||||
|
||||
A footnote reference [^a`b] keeps `code`.
|
||||
|
||||
A shortcut reference [a`b] keeps ``code``.
|
||||
|
||||
A collapsed reference [a`b][] keeps ``code``.
|
||||
|
||||
[a`b]: /u
|
||||
|
||||
[^a`b]: note
|
||||
|
||||
A backslash \ before a line break stays on its line, never a hard break \
|
||||
when the next word arrives.
|
||||
|
||||
|
||||
Reference in new issue
Block a user