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

Commit 02d7f34

Browse files
authored
Do not delete array tables (#17)
1 parent 0faccdb commit 02d7f34

File tree

7 files changed

+126
-66
lines changed

7 files changed

+126
-66
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pyproject-fmt-rust"
3-
version = "1.0.6"
3+
version = "1.0.7"
44
description = "Format pyproject.toml files"
55
repository = "https://github.com/tox-dev/pyproject-fmt"
66
readme = "README.md"

rust/src/build_system.rs

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub fn fix(tables: &mut Tables, keep_full_version: bool) {
77
if table_element.is_none() {
88
return;
99
}
10-
let table = &mut table_element.unwrap().borrow_mut();
10+
let table = &mut table_element.unwrap().first().unwrap().borrow_mut();
1111
for_entries(table, &mut |key, entry| match key.as_str() {
1212
"requires" => {
1313
transform(entry, &|s| format_requirement(s, keep_full_version));
@@ -84,38 +84,33 @@ mod tests {
8484
"#},
8585
true
8686
)]
87-
// #[case::build_system_order(
88-
// indoc ! {r#"
89-
// [build-system]
90-
// # more
91-
// more = true # more post
92-
// # extra
93-
// extra = 1 # extra post
94-
// # path
95-
// backend-path = ['A'] # path post
96-
// # requires
97-
// requires = ["B"] # requires post
98-
// # backend
99-
// build-backend = "hatchling.build" # backend post
100-
// # post
101-
// "#},
102-
// indoc ! {r#"
103-
// [build-system]
104-
// # more
105-
// build-backend = "hatchling.build" # backend post
106-
// # post
107-
// requires = ["b"] # requires post
108-
// # backend
109-
// backend-path = ['A'] # path post
110-
// # requires
111-
// more = true # more post
112-
// # extra
113-
// extra = 1 # extra post
114-
// # path
115-
// "#},
116-
// true
117-
// )]
118-
fn test_normalize_requirement(#[case] start: &str, #[case] expected: &str, #[case] keep_full_version: bool) {
87+
#[case::join(
88+
indoc ! {r#"
89+
[build-system]
90+
requires=["a"]
91+
[build-system]
92+
build-backend = "hatchling.build"
93+
[[build-system.a]]
94+
name = "Hammer"
95+
[[build-system.a]] # empty table within the array
96+
[[build-system.a]]
97+
name = "Nail"
98+
"#},
99+
indoc ! {r#"
100+
[build-system]
101+
build-backend = "hatchling.build"
102+
requires = [
103+
"a",
104+
]
105+
[[build-system.a]]
106+
name = "Hammer"
107+
[[build-system.a]] # empty table within the array
108+
[[build-system.a]]
109+
name = "Nail"
110+
"#},
111+
false
112+
)]
113+
fn test_format_build_systems(#[case] start: &str, #[case] expected: &str, #[case] keep_full_version: bool) {
119114
assert_eq!(evaluate(start, keep_full_version), expected);
120115
}
121116
}

rust/src/helpers/table.rs

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::cell::{RefCell, RefMut};
22
use std::collections::HashMap;
33
use std::iter::zip;
4+
use std::ops::Index;
45

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

1213
#[derive(Debug)]
1314
pub struct Tables {
14-
pub header_to_pos: HashMap<String, usize>,
15+
pub header_to_pos: HashMap<String, Vec<usize>>,
1516
pub table_set: Vec<RefCell<Vec<SyntaxElement>>>,
1617
}
1718

1819
impl Tables {
19-
pub(crate) fn get(&mut self, key: &str) -> Option<&RefCell<Vec<SyntaxElement>>> {
20+
pub(crate) fn get(&mut self, key: &str) -> Option<Vec<&RefCell<Vec<SyntaxElement>>>> {
2021
if self.header_to_pos.contains_key(key) {
21-
Some(&self.table_set[self.header_to_pos[key]])
22+
let mut res = Vec::<&RefCell<Vec<SyntaxElement>>>::new();
23+
for pos in &self.header_to_pos[key] {
24+
res.push(&self.table_set[*pos]);
25+
}
26+
Some(res)
2227
} else {
2328
None
2429
}
2530
}
2631

2732
pub fn from_ast(root_ast: &SyntaxNode) -> Self {
28-
let mut header_to_pos = HashMap::<String, usize>::new();
33+
let mut header_to_pos = HashMap::<String, Vec<usize>>::new();
2934
let mut table_set = Vec::<RefCell<Vec<SyntaxElement>>>::new();
3035
let entry_set = RefCell::new(Vec::<SyntaxElement>::new());
31-
let mut add_to_table_set = || {
36+
let mut table_kind = TABLE_HEADER;
37+
let mut add_to_table_set = |kind| {
3238
let mut entry_set_borrow = entry_set.borrow_mut();
3339
if !entry_set_borrow.is_empty() {
34-
header_to_pos.insert(get_table_name(&entry_set_borrow[0]), table_set.len());
35-
table_set.push(RefCell::new(entry_set_borrow.clone()));
40+
let table_name = get_table_name(&entry_set_borrow[0]);
41+
let indexes = header_to_pos.entry(table_name).or_default();
42+
if kind == TABLE_ARRAY_HEADER || (kind == TABLE_HEADER && indexes.is_empty()) {
43+
indexes.push(table_set.len());
44+
table_set.push(RefCell::new(entry_set_borrow.clone()));
45+
} else if kind == TABLE_HEADER && !indexes.is_empty() {
46+
// join tables
47+
let pos = indexes.first().unwrap();
48+
let mut res = table_set.index(*pos).borrow_mut();
49+
for element in entry_set_borrow.clone() {
50+
if element.kind() != TABLE_HEADER {
51+
res.push(element);
52+
}
53+
}
54+
}
3655
entry_set_borrow.clear();
3756
}
3857
};
3958
for c in root_ast.children_with_tokens() {
4059
if [TABLE_ARRAY_HEADER, TABLE_HEADER].contains(&c.kind()) {
41-
add_to_table_set();
60+
add_to_table_set(table_kind);
61+
table_kind = c.kind();
4262
}
4363
entry_set.borrow_mut().push(c);
4464
}
45-
add_to_table_set();
46-
65+
add_to_table_set(table_kind);
4766
Self {
4867
header_to_pos,
4968
table_set,
@@ -61,37 +80,43 @@ impl Tables {
6180
}
6281
next.push(String::new());
6382
for (name, next_name) in zip(order.iter(), next.iter()) {
64-
let entries = self.get(name).unwrap().borrow();
65-
if !entries.is_empty() {
66-
entry_count += entries.len();
67-
let last = entries.last().unwrap();
68-
if name.is_empty() && last.kind() == SyntaxKind::NEWLINE && entries.len() == 1 {
69-
continue;
70-
}
71-
let mut add = entries.clone();
72-
if get_key(name) != get_key(next_name) {
73-
if last.kind() == SyntaxKind::NEWLINE {
74-
// replace existing newline to ensure single newline
75-
add.pop();
83+
for entries in self.get(name).unwrap() {
84+
let got = entries.borrow_mut();
85+
if !got.is_empty() {
86+
entry_count += got.len();
87+
let last = got.last().unwrap();
88+
if name.is_empty() && last.kind() == SyntaxKind::NEWLINE && got.len() == 1 {
89+
continue;
7690
}
77-
add.push(make_empty_newline());
91+
let mut add = got.clone();
92+
if get_key(name) != get_key(next_name) {
93+
if last.kind() == SyntaxKind::NEWLINE {
94+
// replace existing newline to ensure single newline
95+
add.pop();
96+
}
97+
add.push(make_empty_newline());
98+
}
99+
to_insert.extend(add);
78100
}
79-
to_insert.extend(add);
80101
}
81102
}
82103
root_ast.splice_children(0..entry_count, to_insert);
83104
}
84105
}
85106

86-
fn calculate_order(header_to_pos: &HashMap<String, usize>, ordering: &[&str]) -> Vec<String> {
107+
fn calculate_order(header_to_pos: &HashMap<String, Vec<usize>>, ordering: &[&str]) -> Vec<String> {
87108
let max_ordering = ordering.len() * 2;
88109
let key_to_pos = ordering
89110
.iter()
90111
.enumerate()
91112
.map(|(k, v)| (v, k * 2))
92113
.collect::<HashMap<&&str, usize>>();
93114

94-
let mut header_pos: Vec<(String, usize)> = header_to_pos.clone().into_iter().collect();
115+
let mut header_pos: Vec<(String, usize)> = header_to_pos
116+
.clone()
117+
.into_iter()
118+
.map(|(k, v)| (k, *v.iter().min().unwrap()))
119+
.collect();
95120

96121
header_pos.sort_by_cached_key(|(k, file_pos)| -> (usize, usize) {
97122
let key = get_key(k);
@@ -220,12 +245,22 @@ pub fn collapse_sub_tables(tables: &mut Tables, name: &str) {
220245
return;
221246
}
222247
if !tables.header_to_pos.contains_key(name) {
223-
tables.header_to_pos.insert(String::from(name), tables.table_set.len());
248+
tables
249+
.header_to_pos
250+
.insert(String::from(name), vec![tables.table_set.len()]);
224251
tables.table_set.push(RefCell::new(make_table_entry(name)));
225252
}
226-
let mut main = tables.table_set[tables.header_to_pos[name]].borrow_mut();
253+
let main_positions = tables.header_to_pos[name].clone();
254+
if main_positions.len() != 1 {
255+
return;
256+
}
257+
let mut main = tables.table_set[*main_positions.first().unwrap()].borrow_mut();
227258
for key in sub_table_keys {
228-
let mut sub = tables.table_set[tables.header_to_pos[key]].borrow_mut();
259+
let sub_positions = tables.header_to_pos[key].clone();
260+
if sub_positions.len() != 1 {
261+
continue;
262+
}
263+
let mut sub = tables.table_set[*sub_positions.first().unwrap()].borrow_mut();
229264
let sub_name = key.strip_prefix(sub_name_prefix.as_str()).unwrap();
230265
let mut header = false;
231266
for child in sub.iter() {

rust/src/main.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,36 @@ mod tests {
209209
true,
210210
(3, 8)
211211
)]
212+
#[case::array_of_tables(
213+
indoc ! {r#"
214+
[tool.commitizen]
215+
name = "cz_customize"
216+
217+
[tool.commitizen.customize]
218+
message_template = ""
219+
220+
[[tool.commitizen.customize.questions]]
221+
type = "list"
222+
[[tool.commitizen.customize.questions]]
223+
type = "input"
224+
"#},
225+
indoc ! {r#"
226+
[tool.commitizen]
227+
name = "cz_customize"
228+
229+
[tool.commitizen.customize]
230+
message_template = ""
231+
232+
[[tool.commitizen.customize.questions]]
233+
type = "list"
234+
235+
[[tool.commitizen.customize.questions]]
236+
type = "input"
237+
"#},
238+
2,
239+
true,
240+
(3, 8)
241+
)]
212242
fn test_format_toml(
213243
#[case] start: &str,
214244
#[case] expected: &str,

rust/src/project.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn fix(
2222
if table_element.is_none() {
2323
return;
2424
}
25-
let table = &mut table_element.unwrap().borrow_mut();
25+
let table = &mut table_element.unwrap().first().unwrap().borrow_mut();
2626
expand_entry_points_inline_tables(table);
2727
for_entries(table, &mut |key, entry| match key.split('.').next().unwrap() {
2828
"name" => {

rust/src/ruff.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub fn fix(tables: &mut Tables) {
99
if table_element.is_none() {
1010
return;
1111
}
12-
let table = &mut table_element.unwrap().borrow_mut();
12+
let table = &mut table_element.unwrap().first().unwrap().borrow_mut();
1313
for_entries(table, &mut |key, entry| match key.as_str() {
1414
"target-version"
1515
| "cache-dir"

0 commit comments

Comments
 (0)