mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(formatter_yaml): keep a root plain scalar starting with a document marker verbatim (#27947)
Similar case with #27946, save more cases.
This commit is contained in:
1 parent
529b057811
commit
4d8195c183
5 files changed
+149
-12
No files matched your search
@@ -46,6 +46,7 @@ A line the printer starts at column 0 must not read back as stream-level syntax
|
||||
Column 0 is reached at these sites, each guarded without changing the value:
|
||||
|
||||
- The document's first text (`print/document.rs`): content after `---` stays on its line; a document without `---` whose first text is U+FEFF gets one
|
||||
- A plain scalar starting with a marker on a line of its own stays verbatim from its line start (indentation and continuation lines included)
|
||||
- A root mapping key (`print/mapping_item.rs`): a key starting with a marker keeps its `?`
|
||||
- A flow scalar's continuation line outside block collections (`print/scalar.rs`): a line starting with a marker is indented
|
||||
- This also covers entries of a root flow collection, already indented, where the extra indent is harmless
|
||||
|
||||
@@ -297,7 +297,7 @@ The KEY does count: a long key overflowing on `key: |` alone breaks the pair exa
|
||||
## document-marker-content
|
||||
|
||||
- Why: semantics
|
||||
- Pin: `tests/fixtures/yaml/document-marker-content/document.yaml`, `tests/fixtures/yaml/document-marker-content/key.yaml`, `tests/fixtures/yaml/document-marker-content/scalar.yaml`
|
||||
- Pin: `tests/fixtures/yaml/document-marker-content/document.yaml`, `tests/fixtures/yaml/document-marker-content/indented.yaml`, `tests/fixtures/yaml/document-marker-content/key.yaml`, `tests/fixtures/yaml/document-marker-content/scalar.yaml`
|
||||
|
||||
```yaml
|
||||
# input
|
||||
@@ -306,6 +306,8 @@ The KEY does count: a long key overflowing on `key: |` alone breaks the pair exa
|
||||
: m
|
||||
# (proseWrap: always, printWidth: 10)
|
||||
aaaa bbbb --- cccc
|
||||
...
|
||||
---
|
||||
|
||||
# ours: no line starts with the marker at column 0
|
||||
--- ---
|
||||
@@ -313,6 +315,8 @@ aaaa bbbb --- cccc
|
||||
: m
|
||||
aaaa bbbb
|
||||
--- cccc
|
||||
...
|
||||
---
|
||||
|
||||
# prettier: the content becomes a marker
|
||||
---
|
||||
@@ -320,9 +324,12 @@ aaaa bbbb
|
||||
--- x: m
|
||||
aaaa bbbb
|
||||
--- cccc
|
||||
...
|
||||
---
|
||||
```
|
||||
|
||||
Text starting with `---` or `...` never starts a line at column 0, where it is read as a document marker (`"---"` becomes an empty document, the rest fails to parse).
|
||||
A root plain scalar on a line of its own stays verbatim from its line start: a lenient parser (js-yaml) reads an indented marker as one, so re-indenting it would change the value there.
|
||||
The guarded sites are listed in AGENTS.md "Line starts".
|
||||
|
||||
## bom-content
|
||||
|
||||
@@ -2,6 +2,7 @@ use oxc_formatter_core::{
|
||||
builders::{hard_line_break, space, text},
|
||||
write,
|
||||
};
|
||||
use oxc_span::Span;
|
||||
use oxc_yaml_parser::ast::{Content, Directive, Document, Node, Root};
|
||||
|
||||
use crate::{
|
||||
@@ -13,7 +14,7 @@ use crate::{
|
||||
print::{
|
||||
YamlFormatter,
|
||||
block::{ends_with_keep_chomped_block, item_gap_anchor, last_descendant_block_scalar},
|
||||
source_starts_with_document_marker, to_span, write_node_or_suppressed,
|
||||
column_of, source_starts_with_document_marker, to_span, write_node_or_suppressed,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -138,15 +139,21 @@ fn write_document<'a>(document: &'a Document<'a>, f: &mut YamlFormatter<'_, 'a>)
|
||||
|
||||
if let Some(node) = &document.body.content {
|
||||
let source = f.context().source_text();
|
||||
if let Some(marker) = document.directives_end_marker {
|
||||
// Content starting with `---`/`...` stays on the `---` line: on a line of its own it would become a marker
|
||||
if source.all_bytes_match(marker.end, node.span.start, |b| matches!(b, b' ' | b'\t'))
|
||||
&& source_starts_with_document_marker(node.span.start, f)
|
||||
{
|
||||
needs_line = false;
|
||||
write!(f, space());
|
||||
}
|
||||
} else if source.as_str()[first_key_start(node) as usize..].starts_with('\u{FEFF}') {
|
||||
// A plain scalar starting with `---`/`...` never starts a line at column 0: it would become a marker
|
||||
// (a root mapping key keeps its `?` instead, `print/mapping_item.rs`)
|
||||
let starts_with_marker = matches!(node.content, Content::Plain(_))
|
||||
&& source_starts_with_document_marker(node.span.start, f);
|
||||
let on_marker_line = starts_with_marker
|
||||
&& document.directives_end_marker.is_some_and(|marker| {
|
||||
source.all_bytes_match(marker.end, node.span.start, |b| matches!(b, b' ' | b'\t'))
|
||||
});
|
||||
if on_marker_line {
|
||||
// On the `---` line, it stays there
|
||||
needs_line = false;
|
||||
write!(f, space());
|
||||
} else if document.directives_end_marker.is_none()
|
||||
&& source.as_str()[first_key_start(node) as usize..].starts_with('\u{FEFF}')
|
||||
{
|
||||
// Content starting with U+FEFF needs a `---`: outside a document it would be read as a BOM
|
||||
write!(f, "---");
|
||||
needs_line = true;
|
||||
@@ -156,7 +163,13 @@ fn write_document<'a>(document: &'a Document<'a>, f: &mut YamlFormatter<'_, 'a>)
|
||||
}
|
||||
// Whole-body suppression needs the explicit head form (`# oxfmt-ignore` above `---`);
|
||||
// an ignore right above the body is `write_node_or_suppressed`'s per-node rule.
|
||||
let suppressed = if head_ignores_body {
|
||||
let suppressed = if starts_with_marker && !on_marker_line {
|
||||
// On a line of its own, it stays verbatim from its line start, indentation included:
|
||||
// indented, a lenient parser (js-yaml) may still read it as a marker
|
||||
let line_start = node.span.start - column_of(source.as_str(), node.span.start);
|
||||
write_suppressed_node(Span::new(line_start, node.span.end), f);
|
||||
false
|
||||
} else if head_ignores_body {
|
||||
write_suppressed_node(to_span(node.span), f);
|
||||
true
|
||||
} else {
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
---
|
||||
---
|
||||
... x
|
||||
...
|
||||
# c
|
||||
--- a
|
||||
b
|
||||
...
|
||||
--- y: m
|
||||
...
|
||||
# oxfmt-ignore
|
||||
--- z
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
---
|
||||
source: crates/oxc_formatter_yaml/tests/fixtures/mod.rs
|
||||
---
|
||||
==================== Input ====================
|
||||
---
|
||||
---
|
||||
... x
|
||||
...
|
||||
# c
|
||||
--- a
|
||||
b
|
||||
...
|
||||
--- y: m
|
||||
...
|
||||
# oxfmt-ignore
|
||||
--- z
|
||||
|
||||
==================== Output ====================
|
||||
------------------
|
||||
{ printWidth: 80 }
|
||||
------------------
|
||||
---
|
||||
---
|
||||
... x
|
||||
...
|
||||
# c
|
||||
--- a
|
||||
b
|
||||
...
|
||||
? --- y
|
||||
: m
|
||||
...
|
||||
# oxfmt-ignore
|
||||
--- z
|
||||
|
||||
-------------------
|
||||
{ printWidth: 100 }
|
||||
-------------------
|
||||
---
|
||||
---
|
||||
... x
|
||||
...
|
||||
# c
|
||||
--- a
|
||||
b
|
||||
...
|
||||
? --- y
|
||||
: m
|
||||
...
|
||||
# oxfmt-ignore
|
||||
--- z
|
||||
|
||||
---------------------------------------
|
||||
{ printWidth: 10, proseWrap: "always" }
|
||||
---------------------------------------
|
||||
---
|
||||
---
|
||||
... x
|
||||
...
|
||||
# c
|
||||
--- a
|
||||
b
|
||||
...
|
||||
? --- y
|
||||
: m
|
||||
...
|
||||
# oxfmt-ignore
|
||||
--- z
|
||||
|
||||
---------------------------------------
|
||||
{ printWidth: 80, proseWrap: "always" }
|
||||
---------------------------------------
|
||||
---
|
||||
---
|
||||
... x
|
||||
...
|
||||
# c
|
||||
--- a
|
||||
b
|
||||
...
|
||||
? --- y
|
||||
: m
|
||||
...
|
||||
# oxfmt-ignore
|
||||
--- z
|
||||
|
||||
----------------------------------------
|
||||
{ printWidth: 100, proseWrap: "always" }
|
||||
----------------------------------------
|
||||
---
|
||||
---
|
||||
... x
|
||||
...
|
||||
# c
|
||||
--- a
|
||||
b
|
||||
...
|
||||
? --- y
|
||||
: m
|
||||
...
|
||||
# oxfmt-ignore
|
||||
--- z
|
||||
|
||||
===================== End =====================
|
||||
Reference in new issue
Block a user