diff --git a/apps/oxfmt/src-js/index.ts b/apps/oxfmt/src-js/index.ts index 03d84aa4f8463..128bb00aba2bd 100644 --- a/apps/oxfmt/src-js/index.ts +++ b/apps/oxfmt/src-js/index.ts @@ -125,11 +125,13 @@ export type SortImportsOptions = { /** Glob patterns to identify internal imports. */ internalPattern?: string[]; /** - * Custom groups configuration for organizing imports. + * Groups configuration for organizing imports. * Each array element represents a group, and multiple group names in the same array are treated as one. * Accepts both `string` and `string[]` as group elements. */ groups?: (string | string[])[]; + /** Define custom groups for matching specific imports. */ + customGroups?: { groupName: string; elementNamePattern: string[] }[]; }; /** diff --git a/apps/oxfmt/src/core/oxfmtrc.rs b/apps/oxfmt/src/core/oxfmtrc.rs index dea4ebf537fe6..25751212857bf 100644 --- a/apps/oxfmt/src/core/oxfmtrc.rs +++ b/apps/oxfmt/src/core/oxfmtrc.rs @@ -397,6 +397,15 @@ impl FormatConfig { if let Some(v) = config.groups { sort_imports.groups = v.into_iter().map(SortGroupItemConfig::into_vec).collect(); } + if let Some(v) = config.custom_groups { + sort_imports.custom_groups = v + .into_iter() + .map(|c| CustomGroupDefinition { + group_name: c.group_name, + element_name_pattern: c.element_name_pattern, + }) + .collect(); + } // `partition_by_newline: true` and `newlines_between: true` cannot be used together if sort_imports.partition_by_newline && sort_imports.newlines_between { diff --git a/apps/oxfmt/test/api/api.test.ts b/apps/oxfmt/test/api/api.test.ts index ebbd2207a71b7..bc31d99fe7082 100644 --- a/apps/oxfmt/test/api/api.test.ts +++ b/apps/oxfmt/test/api/api.test.ts @@ -72,4 +72,28 @@ describe("API Tests", () => { ); expect(result3.errors).toStrictEqual([]); }); + + test("should sort imports with customGroups", async () => { + const input = `import { foo } from "./foo"; +import { util } from "~/utils/util"; +import { store } from "~/stores/store"; +`; + const result = await format("a.ts", input, { + experimentalSortImports: { + customGroups: [ + { elementNamePattern: ["~/stores/"], groupName: "stores" }, + { elementNamePattern: ["~/utils/"], groupName: "utils" }, + ], + groups: ["stores", "utils", "sibling"], + }, + }); + + expect(result.code).toBe(`import { store } from "~/stores/store"; + +import { util } from "~/utils/util"; + +import { foo } from "./foo"; +`); + expect(result.errors).toStrictEqual([]); + }); }); diff --git a/apps/oxfmt/test/cli/sort_imports/fixtures/custom_groups/.oxfmtrc.json b/apps/oxfmt/test/cli/sort_imports/fixtures/custom_groups/.oxfmtrc.json new file mode 100644 index 0000000000000..5b34e60d4538b --- /dev/null +++ b/apps/oxfmt/test/cli/sort_imports/fixtures/custom_groups/.oxfmtrc.json @@ -0,0 +1,9 @@ +{ + "experimentalSortImports": { + "customGroups": [ + { "elementNamePattern": ["~/stores/"], "groupName": "stores" }, + { "elementNamePattern": ["~/utils/"], "groupName": "utils" } + ], + "groups": ["stores", "utils", "sibling"] + } +} diff --git a/apps/oxfmt/test/cli/sort_imports/fixtures/custom_groups/input.ts b/apps/oxfmt/test/cli/sort_imports/fixtures/custom_groups/input.ts new file mode 100644 index 0000000000000..770a37cae9368 --- /dev/null +++ b/apps/oxfmt/test/cli/sort_imports/fixtures/custom_groups/input.ts @@ -0,0 +1,5 @@ +import { store } from "~/stores/store"; + +import { util } from "~/utils/util"; + +import { foo } from "./foo"; diff --git a/apps/oxfmt/test/cli/sort_imports/sort_imports.test.ts b/apps/oxfmt/test/cli/sort_imports/sort_imports.test.ts new file mode 100644 index 0000000000000..32e39fced54a7 --- /dev/null +++ b/apps/oxfmt/test/cli/sort_imports/sort_imports.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, it } from "vitest"; +import { join } from "node:path"; +import { runCli } from "../utils"; + +const fixturesDir = join(import.meta.dirname, "fixtures"); + +describe("sort_imports", () => { + it("should sort imports with customGroups", async () => { + const cwd = join(fixturesDir, "custom_groups"); + const result = await runCli(cwd, ["--check", "input.ts"]); + + expect(result.exitCode).toBe(0); + }); +});