Skip to content

Commit 3b97eff

Browse files
committed
feat: absolute module specifiers are now sorted alphabetically instead of based on folder path like relative specifiers
Closes #270
1 parent 75ce598 commit 3b97eff

File tree

2 files changed

+84
-48
lines changed

2 files changed

+84
-48
lines changed

src/parsing/sorting/module_specifiers.rs

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,70 @@ pub fn cmp_module_specifiers(a: &str, b: &str, cmp_text: impl Fn(&str, &str) ->
44
let a_info = get_module_specifier_info(a);
55
let b_info = get_module_specifier_info(b);
66

7-
return match a_info.kind {
8-
ModuleSpecifierKind::Absolute => {
9-
match b_info.kind {
10-
ModuleSpecifierKind::Absolute => compare_folder_items(&a_info, &b_info, cmp_text),
11-
ModuleSpecifierKind::Relative(_) => Ordering::Less,
7+
return match &a_info {
8+
ModuleSpecifierInfo::Absolute {
9+
text: a_text,
10+
} => {
11+
match b_info {
12+
ModuleSpecifierInfo::Absolute { text: b_text } => cmp_text(a_text, b_text),
13+
ModuleSpecifierInfo::Relative { .. } => Ordering::Less,
1214
}
1315
},
14-
ModuleSpecifierKind::Relative(a_relative_count) => {
15-
match b_info.kind {
16-
ModuleSpecifierKind::Absolute => Ordering::Greater,
17-
ModuleSpecifierKind::Relative(b_relative_count) => {
16+
ModuleSpecifierInfo::Relative {
17+
relative_count: a_relative_count,
18+
folder_items: a_folder_items,
19+
} => {
20+
match &b_info {
21+
ModuleSpecifierInfo::Absolute { .. } => Ordering::Greater,
22+
ModuleSpecifierInfo::Relative {
23+
relative_count: b_relative_count,
24+
folder_items: b_folder_items,
25+
} => {
1826
match a_relative_count.cmp(&b_relative_count) {
1927
Ordering::Greater => Ordering::Less,
2028
Ordering::Less => Ordering::Greater,
21-
Ordering::Equal => compare_folder_items(&a_info, &b_info, cmp_text),
29+
Ordering::Equal => compare_folder_items(a_folder_items, b_folder_items, cmp_text),
2230
}
2331
},
2432
}
2533
}
2634
};
2735

28-
fn compare_folder_items(a_info: &ModuleSpecifierInfo, b_info: &ModuleSpecifierInfo, cmp_text: impl Fn(&str, &str) -> Ordering) -> Ordering {
29-
let max_len = std::cmp::min(a_info.folder_items.len(), b_info.folder_items.len());
36+
fn compare_folder_items(a_folder_items: &Vec<&'_ str>, b_folder_items: &Vec<&'_ str>, cmp_text: impl Fn(&str, &str) -> Ordering) -> Ordering {
37+
let max_len = std::cmp::min(a_folder_items.len(), b_folder_items.len());
3038
// compare the common items except for the potential file name at the end
3139
for i in 0..max_len - 1 {
32-
let a_text = a_info.folder_items[i];
33-
let b_text = b_info.folder_items[i];
40+
let a_text = a_folder_items[i];
41+
let b_text = b_folder_items[i];
3442
let ordering = cmp_text(a_text, b_text);
3543
if ordering != Ordering::Equal {
3644
return ordering;
3745
}
3846
}
3947

40-
if a_info.folder_items.len() != b_info.folder_items.len() {
48+
if a_folder_items.len() != b_folder_items.len() {
4149
// the import that has a folder name should appear before the one with a file name
42-
if a_info.folder_items.len() > b_info.folder_items.len() {
50+
if a_folder_items.len() > b_folder_items.len() {
4351
Ordering::Less
4452
} else {
4553
Ordering::Greater
4654
}
4755
} else {
4856
// compare the file names
49-
cmp_text(a_info.folder_items.last().unwrap(), b_info.folder_items.last().unwrap())
57+
cmp_text(a_folder_items.last().unwrap(), b_folder_items.last().unwrap())
5058
}
5159
}
5260
}
5361

54-
struct ModuleSpecifierInfo<'a> {
55-
kind: ModuleSpecifierKind,
56-
folder_items: Vec<&'a str>,
57-
}
58-
5962
#[derive(Debug, PartialEq)]
60-
enum ModuleSpecifierKind {
61-
Absolute,
62-
Relative(usize),
63+
enum ModuleSpecifierInfo<'a> {
64+
Absolute {
65+
text: &'a str,
66+
},
67+
Relative {
68+
relative_count: usize,
69+
folder_items: Vec<&'a str>,
70+
},
6371
}
6472

6573
fn get_module_specifier_info<'a>(text: &'a str) -> ModuleSpecifierInfo<'a> {
@@ -81,14 +89,13 @@ fn get_module_specifier_info<'a>(text: &'a str) -> ModuleSpecifierInfo<'a> {
8189
start_index += part.len() + next_slash_width;
8290
}
8391

84-
ModuleSpecifierInfo {
92+
ModuleSpecifierInfo::Relative {
93+
relative_count,
8594
folder_items: no_quotes_text[start_index..].split('/').collect(),
86-
kind: ModuleSpecifierKind::Relative(relative_count),
8795
}
8896
} else {
89-
ModuleSpecifierInfo {
90-
folder_items: no_quotes_text.split('/').collect(),
91-
kind: ModuleSpecifierKind::Absolute,
97+
ModuleSpecifierInfo::Absolute {
98+
text: no_quotes_text,
9299
}
93100
}
94101
}
@@ -116,39 +123,50 @@ mod test {
116123
#[test]
117124
fn it_should_get_module_specifier_info_when_empty() {
118125
let result = get_module_specifier_info("''");
119-
assert_eq!(result.folder_items, vec![""]);
120-
assert_eq!(result.kind, ModuleSpecifierKind::Absolute);
126+
assert_eq!(result, ModuleSpecifierInfo::Absolute {
127+
text: "",
128+
});
121129
}
122130

123131
#[test]
124132
fn it_should_get_module_specifier_info_for_absolute() {
125133
// double quotes
126134
let result = get_module_specifier_info(r#""testing/asdf""#);
127-
assert_eq!(result.folder_items, vec!["testing", "asdf"]);
128-
assert_eq!(result.kind, ModuleSpecifierKind::Absolute);
135+
assert_eq!(result, ModuleSpecifierInfo::Absolute {
136+
text: "testing/asdf",
137+
});
129138

130139
// single quotes
131140
let result = get_module_specifier_info("'testing'");
132-
assert_eq!(result.folder_items, vec!["testing"]);
133-
assert_eq!(result.kind, ModuleSpecifierKind::Absolute);
141+
assert_eq!(result, ModuleSpecifierInfo::Absolute {
142+
text: "testing",
143+
});
134144
}
135145

136146
#[test]
137147
fn it_should_get_module_specifier_info_for_relative() {
138148
let result = get_module_specifier_info("'./a'");
139-
assert_eq!(result.folder_items, vec!["a"]);
140-
assert_eq!(result.kind, ModuleSpecifierKind::Relative(0));
149+
assert_eq!(result, ModuleSpecifierInfo::Relative {
150+
relative_count: 0,
151+
folder_items: vec!["a"],
152+
});
141153

142154
let result = get_module_specifier_info("'./../testing-test/t'");
143-
assert_eq!(result.folder_items, vec!["testing-test", "t"]);
144-
assert_eq!(result.kind, ModuleSpecifierKind::Relative(1));
155+
assert_eq!(result, ModuleSpecifierInfo::Relative {
156+
relative_count: 1,
157+
folder_items: vec!["testing-test", "t"],
158+
});
145159

146160
let result = get_module_specifier_info("'../asdf'");
147-
assert_eq!(result.folder_items, vec!["asdf"]);
148-
assert_eq!(result.kind, ModuleSpecifierKind::Relative(1));
161+
assert_eq!(result, ModuleSpecifierInfo::Relative {
162+
relative_count: 1,
163+
folder_items: vec!["asdf"],
164+
});
149165

150166
let result = get_module_specifier_info("'../../../test'");
151-
assert_eq!(result.folder_items, vec!["test"]);
152-
assert_eq!(result.kind, ModuleSpecifierKind::Relative(3));
167+
assert_eq!(result, ModuleSpecifierInfo::Relative {
168+
relative_count: 3,
169+
folder_items: vec!["test"],
170+
});
153171
}
154172
}

tests/specs/file/sorting/Statements_SortOrder.txt

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,30 @@ import { a } from "test";
9494

9595
import { a } from "test";
9696

97-
== should put folders above files ==
97+
== should sort straight alphabetical for absolute paths or import map/package names ==
9898
import * as t from "https://deno.land/x/a.ts";
9999
import * as u from "https://deno.land/x/sub-dir/a.ts";
100-
import * as u from "https://deno.land/x/sub-dir/other/a.ts";
100+
import * as v from "https://deno.land/x/sub-dir/other/a.ts";
101+
102+
import "package";
103+
import "package/other";
104+
import "package/abc/xyz";
101105

102106
[expect]
103-
import * as u from "https://deno.land/x/sub-dir/other/a.ts";
104-
import * as u from "https://deno.land/x/sub-dir/a.ts";
105107
import * as t from "https://deno.land/x/a.ts";
108+
import * as u from "https://deno.land/x/sub-dir/a.ts";
109+
import * as v from "https://deno.land/x/sub-dir/other/a.ts";
110+
111+
import "package";
112+
import "package/abc/xyz";
113+
import "package/other";
114+
115+
== should put package names in alphabetical order regardless of directories ==
116+
import "package";
117+
import "package/asdf/test";
118+
import "package/other";
119+
120+
[expect]
121+
import "package";
122+
import "package/asdf/test";
123+
import "package/other";

0 commit comments

Comments
 (0)