Skip to content
This repository has been archived by the owner on Oct 17, 2024. It is now read-only.

Commit

Permalink
Do not delete array tables (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaborbernat authored May 14, 2024
1 parent 0faccdb commit 02d7f34
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 66 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyproject-fmt-rust"
version = "1.0.6"
version = "1.0.7"
description = "Format pyproject.toml files"
repository = "https://github.com/tox-dev/pyproject-fmt"
readme = "README.md"
Expand Down
61 changes: 28 additions & 33 deletions rust/src/build_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub fn fix(tables: &mut Tables, keep_full_version: bool) {
if table_element.is_none() {
return;
}
let table = &mut table_element.unwrap().borrow_mut();
let table = &mut table_element.unwrap().first().unwrap().borrow_mut();
for_entries(table, &mut |key, entry| match key.as_str() {
"requires" => {
transform(entry, &|s| format_requirement(s, keep_full_version));
Expand Down Expand Up @@ -84,38 +84,33 @@ mod tests {
"#},
true
)]
// #[case::build_system_order(
// indoc ! {r#"
// [build-system]
// # more
// more = true # more post
// # extra
// extra = 1 # extra post
// # path
// backend-path = ['A'] # path post
// # requires
// requires = ["B"] # requires post
// # backend
// build-backend = "hatchling.build" # backend post
// # post
// "#},
// indoc ! {r#"
// [build-system]
// # more
// build-backend = "hatchling.build" # backend post
// # post
// requires = ["b"] # requires post
// # backend
// backend-path = ['A'] # path post
// # requires
// more = true # more post
// # extra
// extra = 1 # extra post
// # path
// "#},
// true
// )]
fn test_normalize_requirement(#[case] start: &str, #[case] expected: &str, #[case] keep_full_version: bool) {
#[case::join(
indoc ! {r#"
[build-system]
requires=["a"]
[build-system]
build-backend = "hatchling.build"
[[build-system.a]]
name = "Hammer"
[[build-system.a]] # empty table within the array
[[build-system.a]]
name = "Nail"
"#},
indoc ! {r#"
[build-system]
build-backend = "hatchling.build"
requires = [
"a",
]
[[build-system.a]]
name = "Hammer"
[[build-system.a]] # empty table within the array
[[build-system.a]]
name = "Nail"
"#},
false
)]
fn test_format_build_systems(#[case] start: &str, #[case] expected: &str, #[case] keep_full_version: bool) {
assert_eq!(evaluate(start, keep_full_version), expected);
}
}
93 changes: 64 additions & 29 deletions rust/src/helpers/table.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::iter::zip;
use std::ops::Index;

use taplo::syntax::SyntaxKind::{TABLE_ARRAY_HEADER, TABLE_HEADER};
use taplo::syntax::{SyntaxElement, SyntaxKind, SyntaxNode};
Expand All @@ -11,39 +12,57 @@ use crate::helpers::string::load_text;

#[derive(Debug)]
pub struct Tables {
pub header_to_pos: HashMap<String, usize>,
pub header_to_pos: HashMap<String, Vec<usize>>,
pub table_set: Vec<RefCell<Vec<SyntaxElement>>>,
}

impl Tables {
pub(crate) fn get(&mut self, key: &str) -> Option<&RefCell<Vec<SyntaxElement>>> {
pub(crate) fn get(&mut self, key: &str) -> Option<Vec<&RefCell<Vec<SyntaxElement>>>> {
if self.header_to_pos.contains_key(key) {
Some(&self.table_set[self.header_to_pos[key]])
let mut res = Vec::<&RefCell<Vec<SyntaxElement>>>::new();
for pos in &self.header_to_pos[key] {
res.push(&self.table_set[*pos]);
}
Some(res)
} else {
None
}
}

pub fn from_ast(root_ast: &SyntaxNode) -> Self {
let mut header_to_pos = HashMap::<String, usize>::new();
let mut header_to_pos = HashMap::<String, Vec<usize>>::new();
let mut table_set = Vec::<RefCell<Vec<SyntaxElement>>>::new();
let entry_set = RefCell::new(Vec::<SyntaxElement>::new());
let mut add_to_table_set = || {
let mut table_kind = TABLE_HEADER;
let mut add_to_table_set = |kind| {
let mut entry_set_borrow = entry_set.borrow_mut();
if !entry_set_borrow.is_empty() {
header_to_pos.insert(get_table_name(&entry_set_borrow[0]), table_set.len());
table_set.push(RefCell::new(entry_set_borrow.clone()));
let table_name = get_table_name(&entry_set_borrow[0]);
let indexes = header_to_pos.entry(table_name).or_default();
if kind == TABLE_ARRAY_HEADER || (kind == TABLE_HEADER && indexes.is_empty()) {
indexes.push(table_set.len());
table_set.push(RefCell::new(entry_set_borrow.clone()));
} else if kind == TABLE_HEADER && !indexes.is_empty() {
// join tables
let pos = indexes.first().unwrap();
let mut res = table_set.index(*pos).borrow_mut();
for element in entry_set_borrow.clone() {
if element.kind() != TABLE_HEADER {
res.push(element);
}
}
}
entry_set_borrow.clear();
}
};
for c in root_ast.children_with_tokens() {
if [TABLE_ARRAY_HEADER, TABLE_HEADER].contains(&c.kind()) {
add_to_table_set();
add_to_table_set(table_kind);
table_kind = c.kind();
}
entry_set.borrow_mut().push(c);
}
add_to_table_set();

add_to_table_set(table_kind);
Self {
header_to_pos,
table_set,
Expand All @@ -61,37 +80,43 @@ impl Tables {
}
next.push(String::new());
for (name, next_name) in zip(order.iter(), next.iter()) {
let entries = self.get(name).unwrap().borrow();
if !entries.is_empty() {
entry_count += entries.len();
let last = entries.last().unwrap();
if name.is_empty() && last.kind() == SyntaxKind::NEWLINE && entries.len() == 1 {
continue;
}
let mut add = entries.clone();
if get_key(name) != get_key(next_name) {
if last.kind() == SyntaxKind::NEWLINE {
// replace existing newline to ensure single newline
add.pop();
for entries in self.get(name).unwrap() {
let got = entries.borrow_mut();
if !got.is_empty() {
entry_count += got.len();
let last = got.last().unwrap();
if name.is_empty() && last.kind() == SyntaxKind::NEWLINE && got.len() == 1 {
continue;
}
add.push(make_empty_newline());
let mut add = got.clone();
if get_key(name) != get_key(next_name) {
if last.kind() == SyntaxKind::NEWLINE {
// replace existing newline to ensure single newline
add.pop();
}
add.push(make_empty_newline());
}
to_insert.extend(add);
}
to_insert.extend(add);
}
}
root_ast.splice_children(0..entry_count, to_insert);
}
}

fn calculate_order(header_to_pos: &HashMap<String, usize>, ordering: &[&str]) -> Vec<String> {
fn calculate_order(header_to_pos: &HashMap<String, Vec<usize>>, ordering: &[&str]) -> Vec<String> {
let max_ordering = ordering.len() * 2;
let key_to_pos = ordering
.iter()
.enumerate()
.map(|(k, v)| (v, k * 2))
.collect::<HashMap<&&str, usize>>();

let mut header_pos: Vec<(String, usize)> = header_to_pos.clone().into_iter().collect();
let mut header_pos: Vec<(String, usize)> = header_to_pos
.clone()
.into_iter()
.map(|(k, v)| (k, *v.iter().min().unwrap()))
.collect();

header_pos.sort_by_cached_key(|(k, file_pos)| -> (usize, usize) {
let key = get_key(k);
Expand Down Expand Up @@ -220,12 +245,22 @@ pub fn collapse_sub_tables(tables: &mut Tables, name: &str) {
return;
}
if !tables.header_to_pos.contains_key(name) {
tables.header_to_pos.insert(String::from(name), tables.table_set.len());
tables
.header_to_pos
.insert(String::from(name), vec![tables.table_set.len()]);
tables.table_set.push(RefCell::new(make_table_entry(name)));
}
let mut main = tables.table_set[tables.header_to_pos[name]].borrow_mut();
let main_positions = tables.header_to_pos[name].clone();
if main_positions.len() != 1 {
return;
}
let mut main = tables.table_set[*main_positions.first().unwrap()].borrow_mut();
for key in sub_table_keys {
let mut sub = tables.table_set[tables.header_to_pos[key]].borrow_mut();
let sub_positions = tables.header_to_pos[key].clone();
if sub_positions.len() != 1 {
continue;
}
let mut sub = tables.table_set[*sub_positions.first().unwrap()].borrow_mut();
let sub_name = key.strip_prefix(sub_name_prefix.as_str()).unwrap();
let mut header = false;
for child in sub.iter() {
Expand Down
30 changes: 30 additions & 0 deletions rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,36 @@ mod tests {
true,
(3, 8)
)]
#[case::array_of_tables(
indoc ! {r#"
[tool.commitizen]
name = "cz_customize"
[tool.commitizen.customize]
message_template = ""
[[tool.commitizen.customize.questions]]
type = "list"
[[tool.commitizen.customize.questions]]
type = "input"
"#},
indoc ! {r#"
[tool.commitizen]
name = "cz_customize"
[tool.commitizen.customize]
message_template = ""
[[tool.commitizen.customize.questions]]
type = "list"
[[tool.commitizen.customize.questions]]
type = "input"
"#},
2,
true,
(3, 8)
)]
fn test_format_toml(
#[case] start: &str,
#[case] expected: &str,
Expand Down
2 changes: 1 addition & 1 deletion rust/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn fix(
if table_element.is_none() {
return;
}
let table = &mut table_element.unwrap().borrow_mut();
let table = &mut table_element.unwrap().first().unwrap().borrow_mut();
expand_entry_points_inline_tables(table);
for_entries(table, &mut |key, entry| match key.split('.').next().unwrap() {
"name" => {
Expand Down
2 changes: 1 addition & 1 deletion rust/src/ruff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn fix(tables: &mut Tables) {
if table_element.is_none() {
return;
}
let table = &mut table_element.unwrap().borrow_mut();
let table = &mut table_element.unwrap().first().unwrap().borrow_mut();
for_entries(table, &mut |key, entry| match key.as_str() {
"target-version"
| "cache-dir"
Expand Down

0 comments on commit 02d7f34

Please sign in to comment.