pub(super) fn reformat_for_pnpm_parity(yaml: &str) -> String {
let folded = fold_explicit_keys(&yaml.lines().collect::<Vec<_>>());
let lines: Vec<&str> = folded.iter().map(String::as_str).collect();
let mut compact: Vec<String> = Vec::with_capacity(lines.len());
let mut i = 0;
while i < lines.len() {
let line = lines[i];
let stripped = line.trim_start();
let indent = line.len() - stripped.len();
let key = stripped.strip_suffix(':');
let is_flow_candidate = matches!(key, Some("resolution") | Some("engines"));
if is_flow_candidate && i + 1 < lines.len() {
let inner_indent = indent + 2;
let mut entries: Vec<String> = Vec::new();
let mut all_scalar = true;
let mut j = i + 1;
while j < lines.len() {
let next = lines[j];
let n_stripped = next.trim_start();
let n_indent = next.len() - n_stripped.len();
if n_stripped.is_empty() || n_indent < inner_indent {
break;
}
if n_indent > inner_indent {
all_scalar = false;
break;
}
match n_stripped.split_once(": ") {
Some((k, v)) => entries.push(format!("{k}: {v}")),
None => {
all_scalar = false;
break;
}
}
j += 1;
}
let block_form_type = entries
.iter()
.any(|e| e == "type: binary" || e == "type: variations");
if all_scalar && !block_form_type && !entries.is_empty() {
compact.push(format!(
"{}{}: {{{}}}",
" ".repeat(indent),
key.unwrap(),
entries.join(", ")
));
i = j;
continue;
}
}
if let Some(arch_key @ ("cpu" | "os" | "libc")) = key
&& let Some((items, next_i)) = gather_block_seq(&lines, i, indent)
{
compact.push(format!(
"{}{}: [{}]",
" ".repeat(indent),
arch_key,
items.join(", ")
));
i = next_i;
continue;
}
if key.is_some()
&& let Some((items, next_i)) = gather_block_seq(&lines, i, indent)
{
compact.push(line.to_string());
for item in items {
compact.push(format!("{}- {}", " ".repeat(indent + 2), item));
}
i = next_i;
continue;
}
compact.push(line.to_string());
i += 1;
}
const ENTRY_SECTIONS: &[&str] = &["importers:", "packages:", "snapshots:"];
let mut out = String::with_capacity(yaml.len() + 512);
let mut in_entries = false;
for (idx, line) in compact.iter().enumerate() {
let stripped = line.trim_start();
let indent = line.len() - stripped.len();
let is_top = indent == 0 && !stripped.is_empty();
let is_entry_header =
in_entries && indent == 2 && !stripped.starts_with('-') && stripped.contains(':');
if (is_top && idx > 0) || is_entry_header {
out.push('\n');
}
out.push_str(line);
out.push('\n');
if is_top {
in_entries = ENTRY_SECTIONS.contains(&stripped);
}
}
out
}
fn fold_explicit_keys(lines: &[&str]) -> Vec<String> {
let mut out: Vec<String> = Vec::with_capacity(lines.len());
let mut i = 0;
while i < lines.len() {
let line = lines[i];
let stripped = line.trim_start();
let indent = line.len() - stripped.len();
if let Some(key) = stripped.strip_prefix("? ") {
let mut j = i + 1;
while j < lines.len() && lines[j].trim().is_empty() {
j += 1;
}
if let Some(vline) = lines.get(j) {
let v_stripped = vline.trim_start();
let v_indent = vline.len() - v_stripped.len();
let value = v_stripped
.strip_prefix(": ")
.or_else(|| (v_stripped == ":").then_some(""));
if v_indent == indent
&& let Some(rest) = value
{
let pad = " ".repeat(indent);
if rest.is_empty() || rest.ends_with(':') {
out.push(format!("{pad}{key}:"));
if !rest.is_empty() {
out.push(format!("{pad} {rest}"));
}
} else {
out.push(format!("{pad}{key}: {rest}"));
}
i = j + 1;
continue;
}
}
}
out.push(line.to_string());
i += 1;
}
out
}
fn gather_block_seq(
lines: &[&str],
key_idx: usize,
key_indent: usize,
) -> Option<(Vec<String>, usize)> {
let mut items = Vec::new();
let mut j = key_idx + 1;
while j < lines.len() {
let next = lines[j];
let n_stripped = next.trim_start();
let n_indent = next.len() - n_stripped.len();
if n_indent != key_indent || !n_stripped.starts_with("- ") {
break;
}
items.push(n_stripped[2..].to_string());
j += 1;
}
if items.is_empty() {
return None;
}
if let Some(stop) = lines.get(j) {
let s = stop.trim_start();
let stop_indent = stop.len() - s.len();
if !s.is_empty() && stop_indent > key_indent {
return None;
}
}
Some((items, j))
}
#[cfg(test)]
mod tests {
use super::reformat_for_pnpm_parity;
#[test]
fn collapses_cpu_os_libc_into_flow_sequences() {
let input = "packages:\n '@rollup/rollup-darwin-arm64@4.61.0':\n resolution: {integrity: sha512-aaa==}\n cpu:\n - arm64\n os:\n - darwin\n libc:\n - glibc\n";
let out = reformat_for_pnpm_parity(input);
assert!(out.contains(" cpu: [arm64]\n"), "cpu flow:\n{out}");
assert!(out.contains(" os: [darwin]\n"), "os flow:\n{out}");
assert!(out.contains(" libc: [glibc]\n"), "libc flow:\n{out}");
assert!(!out.contains("- arm64"), "no block cpu:\n{out}");
assert!(!out.contains("- darwin"), "no block os:\n{out}");
}
#[test]
fn flow_sequence_keeps_multiple_items_comma_separated() {
let input = "packages:\n pkg@1.0.0:\n os:\n - darwin\n - linux\n";
let out = reformat_for_pnpm_parity(input);
assert!(out.contains(" os: [darwin, linux]\n"), "{out}");
}
#[test]
fn reindents_transitive_peer_dependencies_two_spaces() {
let input = "snapshots:\n rollup@4.61.0:\n dependencies:\n '@types/estree': 1.0.9\n transitivePeerDependencies:\n - supports-color\n";
let out = reformat_for_pnpm_parity(input);
assert!(
out.contains(" transitivePeerDependencies:\n - supports-color\n"),
"tPD reindented:\n{out}"
);
}
#[test]
fn catalogs_block_stays_tight_like_pnpm() {
let input = "settings:\n autoInstallPeers: true\ncatalogs:\n default:\n esbuild:\n specifier: ^0.27.0\n version: 0.27.7\n evens:\n is-even:\n specifier: ^1.0.0\n version: 1.0.0\nimporters:\n .:\n dependencies:\n esbuild:\n specifier: 'catalog:'\n version: 0.27.7\n";
let out = reformat_for_pnpm_parity(input);
assert!(
out.contains("catalogs:\n default:\n"),
"tight header:\n{out}"
);
assert!(
out.contains(" version: 0.27.7\n evens:\n"),
"tight catalog names:\n{out}"
);
assert!(
out.contains("\n\ncatalogs:\n"),
"blank before catalogs:\n{out}"
);
assert!(
out.contains("\n\nimporters:\n"),
"blank before importers:\n{out}"
);
}
#[test]
fn folds_explicit_long_keys_into_inline_form() {
let long = "@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)";
let input = format!(
"snapshots:\n ? '{long}'\n : dependencies:\n '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.6.3)\n optionalDependencies:\n typescript: 5.6.3\n transitivePeerDependencies:\n - supports-color\n"
);
let out = reformat_for_pnpm_parity(&input);
assert!(
out.contains(&format!(" '{long}':\n")),
"inline key:\n{out}"
);
assert!(
out.contains(" dependencies:\n '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.6.3)\n"),
"deps reindented:\n{out}"
);
assert!(
out.contains(" optionalDependencies:\n typescript: 5.6.3\n"),
"optionalDependencies carried over verbatim:\n{out}"
);
assert!(
out.contains(" transitivePeerDependencies:\n - supports-color\n"),
"tPD reindented:\n{out}"
);
assert!(!out.contains("? '"), "no explicit key left:\n{out}");
assert!(!out.contains("\n : "), "no value indicator left:\n{out}");
}
#[test]
fn folds_explicit_long_key_with_empty_map_value() {
let long = "a-very-long-package-name-that-definitely-exceeds-the-yaml-serde-explicit-key-threshold@1.0.0(peer-one@1.0.0)(peer-two@2.0.0)(peer-three@3.0.0)";
let input = format!("snapshots:\n ? '{long}'\n : {{}}\n");
let out = reformat_for_pnpm_parity(&input);
assert!(
out.contains(&format!(" '{long}': {{}}\n")),
"inline empty:\n{out}"
);
assert!(!out.contains("? '"), "no explicit key left:\n{out}");
}
#[test]
fn leaves_map_item_sequences_untouched() {
let input = "packages:\n node@runtime:24.4.1:\n resolution:\n type: variations\n variants:\n - resolution:\n archive: tarball\n type: binary\n targets:\n - cpu: arm64\n os: darwin\n";
let out = reformat_for_pnpm_parity(input);
assert!(
out.contains(" variants:\n - resolution:\n"),
"{out}"
);
assert!(
out.contains(" targets:\n - cpu: arm64\n"),
"{out}"
);
assert!(!out.contains("resolution: {type: variations"), "{out}");
}
}