Skip to content

Commit

Permalink
feat(organize_imports): support bun:, #, absolute imports (#503)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conaclos authored Oct 9, 2023
1 parent 3df5f43 commit 1e3fc94
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom

- Import sorting is safe to apply now, and it will be applied when running `check --apply` instead of `check --apply-unsafe`.

- Import sorting now handles Bun imports `bun:<name>`, absolute path imports `/<path>`, and [Node's subpath imports `#<name>`](https://nodejs.org/api/packages.html#subpath-imports). See [our documentation](https://biomejs.dev/analyzer/) for more details. Contributed by @Conaclos

### CLI

#### Bug fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,8 @@ impl PartialEq for ImportKey {
/// are listed before imports closer to the source file.
#[derive(Eq, Ord, PartialEq, PartialOrd)]
enum ImportCategory {
/// Anything with an explicit `bun:` prefix.
Bun,
/// Anything with an explicit `node:` prefix, or one of the recognized
/// Node built-ins, such `"fs"`, `"child_process"`, etc..
NodeBuiltin,
Expand All @@ -601,6 +603,12 @@ enum ImportCategory {
/// may (incorrectly) include source imports through custom import mappings
/// as well.
Library,
/// Absolute file imports `/<path>`.
Absolute,
/// Node allows specifying an import map with name prefixed with `#`.
/// See https://nodejs.org/api/packages.html#subpath-imports
SharpImport,
/// Relative file imports `./<path>`.
Relative,
/// Any unrecognized protocols are grouped here. These may include custom
/// protocols such as supported by bundlers.
Expand All @@ -613,11 +621,16 @@ impl From<&str> for ImportCategory {
Self::Relative
} else if let Some((protocol, _)) = value.split_once(':') {
match protocol {
"bun" => Self::Bun,
"http" | "https" => Self::Url,
"node" => Self::NodeBuiltin,
"npm" => Self::Npm,
_ => Self::Other,
}
} else if value.starts_with('#') {
Self::SharpImport
} else if value.starts_with('/') {
Self::Absolute
} else if NODE_BUILTINS.binary_search(&value).is_ok() {
Self::NodeBuiltin
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ import assert from "node:assert";
import aunt from "../aunt";
import { VERSION } from "https://deno.land/std/version.ts";
import { mock, test } from "node:test";
import { expect } from "bun:test";
import { internal } from "#internal";
import { secret } from "/absolute/path";
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,35 @@ import assert from "node:assert";
import aunt from "../aunt";
import { VERSION } from "https://deno.land/std/version.ts";
import { mock, test } from "node:test";

import { expect } from "bun:test";
import { internal } from "#internal";
import { secret } from "/absolute/path";
```

# Actions
```diff
@@ -1,8 +1,8 @@
@@ -1,11 +1,11 @@
-import uncle from "../uncle";
-import sibling from "./sibling";
+import { expect } from "bun:test";
+import assert from "node:assert";
+import { mock, test } from "node:test";
+import express from "npm:express";
+import { VERSION } from "https://deno.land/std/version.ts";
+import aunt from "../aunt";
import uncle from "../uncle";
import sibling from "./sibling";
-import express from "npm:express";
import imageUrl from "url:./image.png";
import express from "npm:express";
-import imageUrl from "url:./image.png";
-import assert from "node:assert";
-import aunt from "../aunt";
-import { VERSION } from "https://deno.land/std/version.ts";
import { VERSION } from "https://deno.land/std/version.ts";
-import { mock, test } from "node:test";
-import { expect } from "bun:test";
+import { secret } from "/absolute/path";
import { internal } from "#internal";
-import { secret } from "/absolute/path";
\ No newline at end of file
+import aunt from "../aunt";
+import uncle from "../uncle";
+import sibling from "./sibling";
+import imageUrl from "url:./image.png";
\ No newline at end of file

```

Expand Down
23 changes: 17 additions & 6 deletions website/src/content/docs/analyzer/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ This feature is enabled by default but can be opted-in/out via configuration:

Import statements are sorted by "distance". Modules that are "farther" from the user are put on the top, modules "closer" to the user are put on the bottom:

1. built-in Node.js modules that are explicitly imported using the `node:` protocol;
2. modules imported via `npm:` protocol. This is a valid syntax when writing code run by Deno, for example;
3. modules imported via URL;
4. modules imported from libraries;
5. modules imported via relative imports;
6. modules that couldn't be identified by the previous criteria;
1. modules imported via `bun:` protocol. This is applicable when writing code run by Bun;
2. built-in Node.js modules that are explicitly imported using the `node:` protocol and common Node built-ins such as `assert`;
3. modules imported via `npm:` protocol. This is applicable when writing code run by Deno;
4. modules imported via URL;
5. modules imported from libraries;
6. modules imported via absolute imports;
7. modules imported from a name prefixed by `#`. This is applicable when using [Node's subpath imports](https://nodejs.org/api/packages.html#subpath-imports);
8. modules imported via relative imports;
9. modules that couldn't be identified by the previous criteria;

For example, given the following code:

Expand All @@ -41,15 +44,23 @@ import assert from "node:assert";
import aunt from "../aunt";
import { VERSION } from "https://deno.land/std/version.ts";
import { mock, test } from "node:test";
import { expect } from "bun:test";
import { internal } from "#internal";
import { secret } from "/absolute/path";
import React from "react";
```

They will be sorted like this:

```ts
import { expect } from "bun:test";
import assert from "node:assert";
import { mock, test } from "node:test";
import express from "npm:express";
import { VERSION } from "https://deno.land/std/version.ts";
import React from "react";
import { secret } from "/absolute/path";
import { internal } from "#internal";
import aunt from "../aunt";
import uncle from "../uncle";
import sibling from "./sibling";
Expand Down
2 changes: 2 additions & 0 deletions website/src/content/docs/internals/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom

- Import sorting is safe to apply now, and it will be applied when running `check --apply` instead of `check --apply-unsafe`.

- Import sorting now handles Bun imports `bun:<name>`, absolute path imports `/<path>`, and [Node's subpath imports `#<name>`](https://nodejs.org/api/packages.html#subpath-imports). See [our documentation](https://biomejs.dev/analyzer/) for more details. Contributed by @Conaclos

### CLI

#### Bug fixes
Expand Down

0 comments on commit 1e3fc94

Please sign in to comment.