diff --git a/crates/oxc_formatter/examples/sort_imports.rs b/crates/oxc_formatter/examples/sort_imports.rs index 8d9f8d436976c..dc7199620ede3 100644 --- a/crates/oxc_formatter/examples/sort_imports.rs +++ b/crates/oxc_formatter/examples/sort_imports.rs @@ -3,7 +3,10 @@ use std::{fs, path::Path}; use oxc_allocator::Allocator; -use oxc_formatter::{FormatOptions, Formatter, SortImportsOptions, SortOrder, get_parse_options}; +use oxc_formatter::{ + FormatOptions, Formatter, SortImportsOptions, SortOrder, default_groups, + default_internal_patterns, get_parse_options, +}; use oxc_parser::Parser; use oxc_span::SourceType; use pico_args::Arguments; @@ -28,8 +31,8 @@ fn main() -> Result<(), String> { sort_side_effects, ignore_case, newlines_between, - internal_pattern: None, - groups: None, + internal_pattern: default_internal_patterns(), + groups: default_groups(), }; // Read source file diff --git a/crates/oxc_formatter/src/ir_transform/sort_imports/compute_metadata.rs b/crates/oxc_formatter/src/ir_transform/sort_imports/compute_metadata.rs index a85d1b292512d..c4b6028015eb3 100644 --- a/crates/oxc_formatter/src/ir_transform/sort_imports/compute_metadata.rs +++ b/crates/oxc_formatter/src/ir_transform/sort_imports/compute_metadata.rs @@ -364,10 +364,7 @@ fn to_path_kind(source: &str, options: &SortImportsOptions) -> ImportPathKind { } // Check if source matches any internal pattern - if match &options.internal_pattern { - Some(patterns) => patterns.iter().any(|p| source.starts_with(p.as_str())), - None => ["~/", "@/"].iter().any(|p| source.starts_with(*p)), - } { + if options.internal_pattern.iter().any(|p| source.starts_with(p.as_str())) { return ImportPathKind::Internal; } diff --git a/crates/oxc_formatter/src/ir_transform/sort_imports/group_config.rs b/crates/oxc_formatter/src/ir_transform/sort_imports/group_config.rs index 4949030979b41..1a3da18c9bed9 100644 --- a/crates/oxc_formatter/src/ir_transform/sort_imports/group_config.rs +++ b/crates/oxc_formatter/src/ir_transform/sort_imports/group_config.rs @@ -1,30 +1,3 @@ -/// Default groups configuration. -pub fn default_groups() -> Vec> { - use ImportModifier as M; - use ImportSelector as S; - - vec![ - vec![GroupName::with_modifier(S::Import, M::Type)], - vec![ - GroupName::with_modifier(S::Builtin, M::Value), - GroupName::with_modifier(S::External, M::Value), - ], - vec![GroupName::with_modifier(S::Internal, M::Type)], - vec![GroupName::with_modifier(S::Internal, M::Value)], - vec![ - GroupName::with_modifier(S::Parent, M::Type), - GroupName::with_modifier(S::Sibling, M::Type), - GroupName::with_modifier(S::Index, M::Type), - ], - vec![ - GroupName::with_modifier(S::Parent, M::Value), - GroupName::with_modifier(S::Sibling, M::Value), - GroupName::with_modifier(S::Index, M::Value), - ], - vec![GroupName::new(S::Unknown)], - ] -} - /// Parse groups from string-based configuration. /// If parsing fails (= undefined), it falls back to `Unknown` selector. pub fn parse_groups_from_strings(string_groups: &Vec>) -> Vec> { diff --git a/crates/oxc_formatter/src/ir_transform/sort_imports/mod.rs b/crates/oxc_formatter/src/ir_transform/sort_imports/mod.rs index d4d68c3adc578..76543a11bc032 100644 --- a/crates/oxc_formatter/src/ir_transform/sort_imports/mod.rs +++ b/crates/oxc_formatter/src/ir_transform/sort_imports/mod.rs @@ -10,7 +10,7 @@ use oxc_allocator::{Allocator, Vec as ArenaVec}; use crate::{ formatter::format_element::{FormatElement, LineMode, document::Document}, ir_transform::sort_imports::{ - group_config::{GroupName, default_groups, parse_groups_from_strings}, + group_config::{GroupName, parse_groups_from_strings}, partitioned_chunk::PartitionedChunk, source_line::SourceLine, }, @@ -27,11 +27,7 @@ pub struct SortImportsTransform { impl SortImportsTransform { pub fn new(options: options::SortImportsOptions) -> Self { // Parse string based groups into our internal representation for performance - let groups = if let Some(groups) = &options.groups { - parse_groups_from_strings(groups) - } else { - default_groups() - }; + let groups = parse_groups_from_strings(&options.groups); Self { options, groups } } diff --git a/crates/oxc_formatter/src/ir_transform/sort_imports/options.rs b/crates/oxc_formatter/src/ir_transform/sort_imports/options.rs index 803edddb0db6c..e293e7b66da7a 100644 --- a/crates/oxc_formatter/src/ir_transform/sort_imports/options.rs +++ b/crates/oxc_formatter/src/ir_transform/sort_imports/options.rs @@ -25,12 +25,11 @@ pub struct SortImportsOptions { /// NOTE: Cannot be used together with `partition_by_newline: true`. pub newlines_between: bool, /// Prefixes for internal imports. - /// If `None`, uses the default internal patterns. - pub internal_pattern: Option>, + /// Defaults to `["~/", "@/"]`. + pub internal_pattern: Vec, /// Groups configuration for organizing imports. /// Each inner `Vec` represents a group, and multiple group names in the same `Vec` are treated as one. - /// If `None`, uses the default groups. - pub groups: Option>>, + pub groups: Vec>, } impl Default for SortImportsOptions { @@ -42,12 +41,14 @@ impl Default for SortImportsOptions { order: SortOrder::default(), ignore_case: true, newlines_between: true, - internal_pattern: None, - groups: None, + internal_pattern: default_internal_patterns(), + groups: default_groups(), } } } +// --- + #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] pub enum SortOrder { /// Sort in ascending order (A-Z). @@ -88,3 +89,21 @@ impl fmt::Display for SortOrder { f.write_str(s) } } + +/// Returns default prefixes for identifying internal imports: `["~/", "@/"]`. +pub fn default_internal_patterns() -> Vec { + ["~/", "@/"].iter().map(|s| (*s).to_string()).collect() +} + +/// Returns default groups configuration for organizing imports. +pub fn default_groups() -> Vec> { + vec![ + vec!["type-import".to_string()], + vec!["value-builtin".to_string(), "value-external".to_string()], + vec!["type-internal".to_string()], + vec!["value-internal".to_string()], + vec!["type-parent".to_string(), "type-sibling".to_string(), "type-index".to_string()], + vec!["value-parent".to_string(), "value-sibling".to_string(), "value-index".to_string()], + vec!["unknown".to_string()], + ] +} diff --git a/crates/oxc_formatter/src/service/oxfmtrc.rs b/crates/oxc_formatter/src/service/oxfmtrc.rs index 6b49d235d26e0..345ed7fbccc25 100644 --- a/crates/oxc_formatter/src/service/oxfmtrc.rs +++ b/crates/oxc_formatter/src/service/oxfmtrc.rs @@ -7,7 +7,7 @@ use crate::{ ArrowParentheses, AttributePosition, BracketSameLine, BracketSpacing, EmbeddedLanguageFormatting, Expand, FormatOptions, IndentStyle, IndentWidth, LineEnding, LineWidth, QuoteProperties, QuoteStyle, Semicolons, SortImportsOptions, SortOrder, - TrailingCommas, + TrailingCommas, default_groups, default_internal_patterns, }; /// Configuration options for the formatter. @@ -375,14 +375,16 @@ impl Oxfmtrc { partition_by_newline: sort_imports_config.partition_by_newline, partition_by_comment: sort_imports_config.partition_by_comment, sort_side_effects: sort_imports_config.sort_side_effects, - order: sort_imports_config.order.map_or(SortOrder::Asc, |o| match o { + order: sort_imports_config.order.map_or(SortOrder::default(), |o| match o { SortOrderConfig::Asc => SortOrder::Asc, SortOrderConfig::Desc => SortOrder::Desc, }), ignore_case: sort_imports_config.ignore_case, newlines_between: sort_imports_config.newlines_between, - internal_pattern: sort_imports_config.internal_pattern, - groups: sort_imports_config.groups, + internal_pattern: sort_imports_config + .internal_pattern + .unwrap_or_else(default_internal_patterns), + groups: sort_imports_config.groups.unwrap_or_else(default_groups), }); } @@ -563,10 +565,9 @@ mod tests { ) .unwrap(); let sort_imports = config.into_format_options().unwrap().experimental_sort_imports.unwrap(); - let groups = sort_imports.groups.as_ref().unwrap(); - assert_eq!(groups.len(), 5); - assert_eq!(groups[0], vec!["builtin".to_string()]); - assert_eq!(groups[1], vec!["external".to_string(), "internal".to_string()]); - assert_eq!(groups[4], vec!["index".to_string()]); + assert_eq!(sort_imports.groups.len(), 5); + assert_eq!(sort_imports.groups[0], vec!["builtin".to_string()]); + assert_eq!(sort_imports.groups[1], vec!["external".to_string(), "internal".to_string()]); + assert_eq!(sort_imports.groups[4], vec!["index".to_string()]); } } diff --git a/napi/playground/src/lib.rs b/napi/playground/src/lib.rs index c25ed32a06651..cd8f849d8303b 100644 --- a/napi/playground/src/lib.rs +++ b/napi/playground/src/lib.rs @@ -31,7 +31,8 @@ use oxc::{ use oxc_formatter::{ ArrowParentheses, AttributePosition, BracketSameLine, BracketSpacing, Expand, FormatOptions, Formatter, IndentStyle, IndentWidth, LineEnding, LineWidth, QuoteProperties, QuoteStyle, - Semicolons, SortImportsOptions, SortOrder, TrailingCommas, get_parse_options, + Semicolons, SortImportsOptions, SortOrder, TrailingCommas, default_groups, + default_internal_patterns, get_parse_options, }; use oxc_linter::{ ConfigStore, ConfigStoreBuilder, ContextSubHost, ExternalPluginStore, LintOptions, Linter, @@ -510,8 +511,11 @@ impl Oxc { order, ignore_case: sort_imports_config.ignore_case.unwrap_or(true), newlines_between: sort_imports_config.newlines_between.unwrap_or(true), - internal_pattern: sort_imports_config.internal_pattern.clone(), - groups: sort_imports_config.groups.clone(), + internal_pattern: sort_imports_config + .internal_pattern + .clone() + .unwrap_or_else(default_internal_patterns), + groups: sort_imports_config.groups.clone().unwrap_or_else(default_groups), }); }