Skip to content

Commit 7374856

Browse files
committed
feat(formatter/sort-imports): Support options.internalPattern (#16372)
Part of #14253 The original implementation accepts a `RegExp` string, but based on the actual usage, it seems that checking as prefix is sufficient for now. https://github.com/search?q=%22internalPattern%3A+%5B%22&type=code
1 parent dd2cb62 commit 7374856

File tree

10 files changed

+68
-4
lines changed

10 files changed

+68
-4
lines changed

crates/oxc_formatter/examples/sort_imports.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ fn main() -> Result<(), String> {
2828
sort_side_effects,
2929
ignore_case,
3030
newlines_between,
31+
internal_pattern: None,
3132
groups: None,
3233
};
3334

crates/oxc_formatter/src/ir_transform/sort_imports/compute_metadata.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ pub fn compute_import_metadata<'a>(
3030

3131
let source = extract_source_path(source);
3232
let is_style_import = is_style(source);
33+
let path_kind = to_path_kind(source, options);
3334

3435
// Create group matcher from import characteristics
3536
let matcher = ImportGroupMatcher {
3637
is_side_effect: *is_side_effect,
3738
is_type_import: *is_type_import,
3839
is_style_import,
39-
path_kind: to_path_kind(source),
40+
path_kind,
4041
is_subpath: is_subpath(source),
4142
has_default_specifier: *has_default_specifier,
4243
has_namespace_specifier: *has_namespace_specifier,
@@ -346,7 +347,7 @@ enum ImportPathKind {
346347
}
347348

348349
/// Determine the path kind for an import source.
349-
fn to_path_kind(source: &str) -> ImportPathKind {
350+
fn to_path_kind(source: &str, options: &options::SortImports) -> ImportPathKind {
350351
if is_builtin(source) {
351352
return ImportPathKind::Builtin;
352353
}
@@ -364,8 +365,11 @@ fn to_path_kind(source: &str) -> ImportPathKind {
364365
return ImportPathKind::Sibling;
365366
}
366367

367-
// TODO: This can be changed via `options.internalPattern`
368-
if source.starts_with("~/") || source.starts_with("@/") {
368+
// Check if source matches any internal pattern
369+
if match &options.internal_pattern {
370+
Some(patterns) => patterns.iter().any(|p| source.starts_with(p.as_str())),
371+
None => ["~/", "@/"].iter().any(|p| source.starts_with(*p)),
372+
} {
369373
return ImportPathKind::Internal;
370374
}
371375

crates/oxc_formatter/src/options.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,9 @@ pub struct SortImports {
10041004
///
10051005
/// NOTE: Cannot be used together with `partition_by_newline: true`.
10061006
pub newlines_between: bool,
1007+
/// Prefixes for internal imports.
1008+
/// If `None`, uses the default internal patterns.
1009+
pub internal_pattern: Option<Vec<String>>,
10071010
/// Groups configuration for organizing imports.
10081011
/// Each inner `Vec` represents a group, and multiple group names in the same `Vec` are treated as one.
10091012
/// If `None`, uses the default groups.
@@ -1019,6 +1022,7 @@ impl Default for SortImports {
10191022
order: SortOrder::default(),
10201023
ignore_case: true,
10211024
newlines_between: true,
1025+
internal_pattern: None,
10221026
groups: None,
10231027
}
10241028
}

crates/oxc_formatter/src/service/oxfmtrc.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ pub struct SortImportsConfig {
150150
pub ignore_case: bool,
151151
#[serde(default = "default_true")]
152152
pub newlines_between: bool,
153+
#[serde(skip_serializing_if = "Option::is_none")]
154+
pub internal_pattern: Option<Vec<String>>,
153155
/// Custom groups configuration for organizing imports.
154156
/// Each array element represents a group, and multiple group names in the same array are treated as one.
155157
/// Accepts both `string` and `string[]` as group elements.
@@ -378,6 +380,7 @@ impl Oxfmtrc {
378380
}),
379381
ignore_case: sort_imports_config.ignore_case,
380382
newlines_between: sort_imports_config.newlines_between,
383+
internal_pattern: sort_imports_config.internal_pattern,
381384
groups: sort_imports_config.groups,
382385
});
383386
}

crates/oxc_formatter/tests/ir_transform/sort_imports.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,35 @@ import { z } from "z";
876876

877877
// ---
878878

879+
#[test]
880+
fn should_support_internal_pattern_option() {
881+
assert_format(
882+
r##"
883+
import type { T } from "a";
884+
import { a } from "a";
885+
import type { S } from "#b";
886+
import c from "#c";
887+
import { b1, b2 } from "#b";
888+
import { d } from "../d";
889+
"##,
890+
r##"{ "experimentalSortImports": { "internalPattern": ["#"] } }"##,
891+
r##"
892+
import type { T } from "a";
893+
894+
import { a } from "a";
895+
896+
import type { S } from "#b";
897+
898+
import { b1, b2 } from "#b";
899+
import c from "#c";
900+
901+
import { d } from "../d";
902+
"##,
903+
);
904+
}
905+
906+
// ---
907+
879908
#[test]
880909
fn should_groups_and_sorts_by_type_and_source() {
881910
assert_format(

crates/oxc_formatter/tests/snapshots/schema_json.snap

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,15 @@ expression: json
223223
"default": true,
224224
"type": "boolean"
225225
},
226+
"internalPattern": {
227+
"type": [
228+
"array",
229+
"null"
230+
],
231+
"items": {
232+
"type": "string"
233+
}
234+
},
226235
"newlinesBetween": {
227236
"default": true,
228237
"type": "boolean"

napi/playground/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ export interface OxcSortImportsOptions {
168168
ignoreCase?: boolean
169169
/** Add newlines between import groups (default: true) */
170170
newlinesBetween?: boolean
171+
/** Pattern prefixes for internal imports */
172+
internalPattern?: Array<string>
171173
/** Custom groups of imports */
172174
groups?: Array<Array<string>>
173175
}

napi/playground/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ impl Oxc {
510510
order,
511511
ignore_case: sort_imports_config.ignore_case.unwrap_or(true),
512512
newlines_between: sort_imports_config.newlines_between.unwrap_or(true),
513+
internal_pattern: sort_imports_config.internal_pattern.clone(),
513514
groups: sort_imports_config.groups.clone(),
514515
});
515516
}

napi/playground/src/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ pub struct OxcSortImportsOptions {
163163
pub ignore_case: Option<bool>,
164164
/// Add newlines between import groups (default: true)
165165
pub newlines_between: Option<bool>,
166+
/// Pattern prefixes for internal imports
167+
pub internal_pattern: Option<Vec<String>>,
166168
/// Custom groups of imports
167169
pub groups: Option<Vec<Vec<String>>>,
168170
}

npm/oxfmt/configuration_schema.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,15 @@
219219
"default": true,
220220
"type": "boolean"
221221
},
222+
"internalPattern": {
223+
"type": [
224+
"array",
225+
"null"
226+
],
227+
"items": {
228+
"type": "string"
229+
}
230+
},
222231
"newlinesBetween": {
223232
"default": true,
224233
"type": "boolean"

0 commit comments

Comments
 (0)