Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions napi/playground/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ export interface OxcControlFlowOptions {
verbose?: boolean
}

export interface OxcCustomGroupDefinition {
/** The identifier used in groups representing this custom group */
groupName?: string
/** List of glob patterns to match import sources */
elementNamePattern?: Array<string>
/** Import selector filter (e.g. "type", "external", "builtin") */
selector?: string
/** Import modifier filters - all must match */
modifiers?: Array<string>
}

export interface OxcDefineOptions {
/** Map of variable name to value for replacement */
define: Record<string, string>
Expand Down Expand Up @@ -119,6 +130,10 @@ export interface OxcMangleOptions {
keepNames: boolean
}

export interface OxcNewlinesBetweenMarker {
newlinesBetween?: boolean
}

export interface OxcOptions {
run: OxcRunOptions
parser: OxcParserOptions
Expand Down Expand Up @@ -170,8 +185,14 @@ export interface OxcSortImportsOptions {
newlinesBetween?: boolean
/** Pattern prefixes for internal imports */
internalPattern?: Array<string>
/** Custom groups of imports */
groups?: Array<Array<string>>
/**
* Groups configuration matching oxfmtrc format.
* Each element can be a single group name string, an array of group names,
* or a `{ newlinesBetween: bool }` marker object.
*/
groups?: Array<string | string[] | { newlinesBetween: boolean }> | undefined
/** User-defined custom group definitions */
customGroups?: Array<OxcCustomGroupDefinition>
}

export interface OxcTransformerOptions {
Expand Down
83 changes: 71 additions & 12 deletions napi/playground/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ use oxc::{
transformer::{TransformOptions, Transformer},
};
use oxc_formatter::{
ArrowParentheses, AttributePosition, BracketSameLine, BracketSpacing, Expand, FormatOptions,
Formatter, GroupEntry, IndentStyle, IndentWidth, LineEnding, LineWidth, QuoteProperties,
QuoteStyle, Semicolons, SortImportsOptions, SortOrder, TrailingCommas, default_groups,
default_internal_patterns, get_parse_options,
ArrowParentheses, AttributePosition, BracketSameLine, BracketSpacing, CustomGroupDefinition,
Expand, FormatOptions, Formatter, GroupEntry, ImportModifier, ImportSelector, IndentStyle,
IndentWidth, LineEnding, LineWidth, QuoteProperties, QuoteStyle, Semicolons,
SortImportsOptions, SortOrder, TrailingCommas, default_groups, default_internal_patterns,
get_parse_options,
};
use oxc_linter::{
ConfigStore, ConfigStoreBuilder, ContextSubHost, ExternalPluginStore, LintOptions, Linter,
Expand Down Expand Up @@ -516,6 +517,69 @@ impl Oxc {
.and_then(|o| o.parse::<SortOrder>().ok())
.unwrap_or_default();

let custom_groups = sort_imports_config
.custom_groups
.as_ref()
.map(|cgs| {
cgs.iter()
.filter_map(|cg| {
let group_name = cg.group_name.clone()?;
Some(CustomGroupDefinition {
group_name,
element_name_pattern: cg
.element_name_pattern
.clone()
.unwrap_or_default(),
selector: cg
.selector
.as_ref()
.and_then(|s| ImportSelector::parse(s)),
modifiers: cg.modifiers.as_ref().map_or_else(Vec::new, |mods| {
mods.iter().filter_map(|m| ImportModifier::parse(m)).collect()
}),
})
})
.collect()
})
.unwrap_or_default();

// Parse groups with inline newlinesBetween markers, matching oxfmtrc format
let (groups, newline_boundary_overrides) =
sort_imports_config.groups.as_ref().map_or_else(
|| (default_groups(), vec![]),
|items| {
let mut groups = Vec::new();
let mut newline_boundary_overrides: Vec<Option<bool>> = Vec::new();
let mut pending_override: Option<bool> = None;

for item in items {
if let Either::B(Either::B(marker)) = item {
// { newlinesBetween: bool } marker
if let Some(v) = marker.newlines_between {
pending_override = Some(v);
}
} else {
// String or Vec<String> → group entries
if !groups.is_empty() {
newline_boundary_overrides.push(pending_override.take());
}
let names: Vec<&str> = match item {
Either::A(s) => vec![s.as_str()],
Either::B(Either::A(v)) => {
v.iter().map(String::as_str).collect()
}
Either::B(Either::B(_)) => unreachable!(),
};
groups.push(
names.iter().map(|name| GroupEntry::parse(name)).collect(),
);
}
}

(groups, newline_boundary_overrides)
},
);

format_options.experimental_sort_imports = Some(SortImportsOptions {
partition_by_newline: sort_imports_config.partition_by_newline.unwrap_or(false),
partition_by_comment: sort_imports_config.partition_by_comment.unwrap_or(false),
Expand All @@ -527,14 +591,9 @@ impl Oxc {
.internal_pattern
.clone()
.unwrap_or_else(default_internal_patterns),
groups: sort_imports_config.groups.as_ref().map_or_else(default_groups, |groups| {
groups
.iter()
.map(|group| group.iter().map(|name| GroupEntry::parse(name)).collect())
.collect()
}),
custom_groups: vec![],
newline_boundary_overrides: vec![],
groups,
custom_groups,
newline_boundary_overrides,
});
}

Expand Down
32 changes: 30 additions & 2 deletions napi/playground/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ use napi::Either;
use napi_derive::napi;
use rustc_hash::FxHashMap;

/// A single group item in the sort imports `groups` configuration.
/// Matches oxfmtrc format: `string | string[] | { newlinesBetween: boolean }`
pub type SortGroupItem = Either<String, Either<Vec<String>, OxcNewlinesBetweenMarker>>;

#[napi(object)]
#[derive(Default)]
pub struct OxcOptions {
Expand Down Expand Up @@ -165,6 +169,30 @@ pub struct OxcSortImportsOptions {
pub newlines_between: Option<bool>,
/// Pattern prefixes for internal imports
pub internal_pattern: Option<Vec<String>>,
/// Custom groups of imports
pub groups: Option<Vec<Vec<String>>>,
/// Groups configuration matching oxfmtrc format.
/// Each element can be a single group name string, an array of group names,
/// or a `{ newlinesBetween: bool }` marker object.
#[napi(ts_type = "Array<string | string[] | { newlinesBetween: boolean }> | undefined")]
pub groups: Option<Vec<SortGroupItem>>,
/// User-defined custom group definitions
pub custom_groups: Option<Vec<OxcCustomGroupDefinition>>,
}

#[napi(object)]
#[derive(Default, Clone)]
pub struct OxcNewlinesBetweenMarker {
pub newlines_between: Option<bool>,
}

#[napi(object)]
#[derive(Default, Clone)]
pub struct OxcCustomGroupDefinition {
/// The identifier used in groups representing this custom group
pub group_name: Option<String>,
/// List of glob patterns to match import sources
pub element_name_pattern: Option<Vec<String>>,
/// Import selector filter (e.g. "type", "external", "builtin")
pub selector: Option<String>,
/// Import modifier filters - all must match
pub modifiers: Option<Vec<String>>,
}
Loading