Skip to content

Commit fda4e93

Browse files
committed
feat(formatter/sort-imports): Add options.order: asc|desc
1 parent ce47ebf commit fda4e93

File tree

4 files changed

+109
-13
lines changed

4 files changed

+109
-13
lines changed

crates/oxc_formatter/examples/sort_imports.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::{fs, path::Path};
44

55
use oxc_allocator::Allocator;
6-
use oxc_formatter::{FormatOptions, Formatter, SortImports};
6+
use oxc_formatter::{FormatOptions, Formatter, SortImports, SortOrder};
77
use oxc_parser::{ParseOptions, Parser};
88
use oxc_span::SourceType;
99
use pico_args::Arguments;
@@ -12,10 +12,15 @@ use pico_args::Arguments;
1212
fn main() -> Result<(), String> {
1313
let mut args = Arguments::from_env();
1414
let show_ir = args.contains("--ir");
15+
let name = args.free_from_str().unwrap_or_else(|_| "test.js".to_string());
16+
1517
let partition_by_newline = args.contains("--partition_by_newline");
1618
let partition_by_comment = args.contains("--partition_by_comment");
1719
let sort_side_effects = args.contains("--sort_side_effects");
18-
let name = args.free_from_str().unwrap_or_else(|_| "test.js".to_string());
20+
let order = args.opt_value_from_str("--order").unwrap_or(None).unwrap_or(SortOrder::Asc);
21+
22+
let sort_imports_options =
23+
SortImports { order, partition_by_newline, partition_by_comment, sort_side_effects };
1924

2025
// Read source file
2126
let path = Path::new(&name);
@@ -44,11 +49,7 @@ fn main() -> Result<(), String> {
4449

4550
// Format the parsed code
4651
let options = FormatOptions {
47-
experimental_sort_imports: Some(SortImports {
48-
partition_by_newline,
49-
partition_by_comment,
50-
sort_side_effects,
51-
}),
52+
experimental_sort_imports: Some(sort_imports_options),
5253
..Default::default()
5354
};
5455

@@ -66,10 +67,7 @@ fn main() -> Result<(), String> {
6667
}
6768

6869
println!("=======================");
69-
println!(
70-
"Formatted with {:#?}",
71-
SortImports { partition_by_newline, partition_by_comment, sort_side_effects }
72-
);
70+
println!("Formatted with {sort_imports_options:#?}",);
7371

7472
Ok(())
7573
}

crates/oxc_formatter/src/ir_transform/sort_imports.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,10 @@ impl SortImportsTransform {
171171
if 1 < import_units.len() {
172172
// TODO: Sort based on `options.groups`, `options.type`, etc...
173173
// TODO: Consider `options.ignore_case`, `special_characters`, removing `?raw`, etc...
174-
import_units.sort_by_key(|unit| unit.get_source(prev_elements));
174+
import_units.sort_by(|a, b| {
175+
let ord = a.get_source(prev_elements).cmp(b.get_source(prev_elements));
176+
if self.options.order.is_desc() { ord.reverse() } else { ord }
177+
});
175178
}
176179

177180
let preserve_empty_line = self.options.partition_by_newline;

crates/oxc_formatter/src/options.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,12 +915,57 @@ impl fmt::Display for OperatorPosition {
915915
}
916916
}
917917

918+
// ---
919+
918920
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
919921
pub struct SortImports {
922+
/// Sort order (asc or desc).
923+
pub order: SortOrder,
920924
/// Partition imports by newlines.
921925
pub partition_by_newline: bool,
922926
/// Partition imports by comments.
923927
pub partition_by_comment: bool,
924928
/// Sort side effects imports.
925929
pub sort_side_effects: bool,
926930
}
931+
932+
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
933+
pub enum SortOrder {
934+
/// Sort in ascending order (A-Z).
935+
#[default]
936+
Asc,
937+
/// Sort in descending order (Z-A).
938+
Desc,
939+
}
940+
941+
impl SortOrder {
942+
pub const fn is_asc(self) -> bool {
943+
matches!(self, Self::Asc)
944+
}
945+
946+
pub const fn is_desc(self) -> bool {
947+
matches!(self, Self::Desc)
948+
}
949+
}
950+
951+
impl FromStr for SortOrder {
952+
type Err = &'static str;
953+
954+
fn from_str(s: &str) -> Result<Self, Self::Err> {
955+
match s {
956+
"asc" => Ok(Self::Asc),
957+
"desc" => Ok(Self::Desc),
958+
_ => Err("Value not supported for SortOrder. Supported values are 'asc' and 'desc'."),
959+
}
960+
}
961+
}
962+
963+
impl fmt::Display for SortOrder {
964+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
965+
let s = match self {
966+
SortOrder::Asc => "ASC",
967+
SortOrder::Desc => "DESC",
968+
};
969+
f.write_str(s)
970+
}
971+
}

crates/oxc_formatter/tests/ir_transform/sort_imports.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::assert_format;
2-
use oxc_formatter::{FormatOptions, QuoteStyle, Semicolons, SortImports};
2+
use oxc_formatter::{FormatOptions, QuoteStyle, Semicolons, SortImports, SortOrder};
33

44
#[test]
55
fn should_not_sort_by_default() {
@@ -657,3 +657,53 @@ import B from "b";
657657
"#,
658658
);
659659
}
660+
661+
// ---
662+
663+
#[test]
664+
fn should_sort_by_order() {
665+
// Z-A
666+
assert_format(
667+
r#"
668+
import { log } from "./log";
669+
import { log10 } from "./log10";
670+
import { log1p } from "./log1p";
671+
import { log2 } from "./log2";
672+
"#,
673+
&FormatOptions {
674+
experimental_sort_imports: Some(SortImports {
675+
order: SortOrder::Desc,
676+
..Default::default()
677+
}),
678+
..Default::default()
679+
},
680+
r#"
681+
import { log2 } from "./log2";
682+
import { log1p } from "./log1p";
683+
import { log10 } from "./log10";
684+
import { log } from "./log";
685+
"#,
686+
);
687+
// A-Z - default
688+
assert_format(
689+
r#"
690+
import { log } from "./log";
691+
import { log10 } from "./log10";
692+
import { log1p } from "./log1p";
693+
import { log2 } from "./log2";
694+
"#,
695+
&FormatOptions {
696+
experimental_sort_imports: Some(SortImports {
697+
order: SortOrder::Asc,
698+
..Default::default()
699+
}),
700+
..Default::default()
701+
},
702+
r#"
703+
import { log } from "./log";
704+
import { log10 } from "./log10";
705+
import { log1p } from "./log1p";
706+
import { log2 } from "./log2";
707+
"#,
708+
);
709+
}

0 commit comments

Comments
 (0)