├── .gitignore ├── pnpm-workspace.yaml ├── .gitmodules ├── .editorconfig ├── package.json ├── biome.json ├── packages └── @tsimports │ ├── cli-win32-x64 │ └── package.json │ ├── cli-darwin-x64 │ └── package.json │ ├── cli-darwin-arm64 │ └── package.json │ ├── cli-win32-arm64 │ └── package.json │ ├── cli-linux-x64 │ └── package.json │ ├── cli-linux-arm64 │ └── package.json │ ├── cli-linux-musl-x64 │ └── package.json │ ├── cli-linux-musl-arm64 │ └── package.json │ └── tsimports │ ├── package.json │ ├── LICENCE.md │ ├── scripts │ ├── postinstall.js │ └── generate-packages.mjs │ ├── README.md │ └── bin │ └── tsimports ├── tests ├── test.rs └── snapshots │ └── test__snapshot_tests.snap ├── Cargo.toml ├── LICENCE.md ├── .github └── workflows │ ├── ci.yml │ └── release-cli.yml ├── src ├── analyze.rs ├── lib.rs ├── import_kind.rs ├── main.rs └── transform.rs ├── README.md ├── pnpm-lock.yaml └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | target/ 3 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/@tsimports/* 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "biome"] 2 | path = biome 3 | url = https://github.com/biomejs/biome.git 4 | branch = main 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | max_line_length = 120 10 | trim_trailing_whitespace = true 11 | 12 | [*.{rs,toml}] 13 | indent_size = 4 14 | 15 | [Cargo.lock] 16 | indent_size = 1 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "@tsimports/root", 4 | "version": "0.1.4", 5 | "description": "Workspace root of the project.", 6 | "author": "Naoki Ikeguchi ", 7 | "license": "MIT", 8 | "packageManager": "pnpm@9.12.2", 9 | "devDependencies": { 10 | "@biomejs/biome": "^1.9.4" 11 | }, 12 | "scripts": { 13 | "check": "biome check", 14 | "fix": "biome check --fix" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", 3 | "vcs": { 4 | "enabled": true, 5 | "clientKind": "git", 6 | "useIgnoreFile": true 7 | }, 8 | "files": { 9 | "ignoreUnknown": true, 10 | "ignore": ["./biome"] 11 | }, 12 | "formatter": { 13 | "enabled": true, 14 | "useEditorconfig": true 15 | }, 16 | "organizeImports": { 17 | "enabled": true 18 | }, 19 | "linter": { 20 | "enabled": true, 21 | "rules": { 22 | "recommended": true 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/@tsimports/cli-win32-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsimports/cli-win32-x64", 3 | "version": "0.1.4", 4 | "author": "Naoki Ikeguchi ", 5 | "license": "MIT", 6 | "homepage": "https://github.com/siketyan/tsimports", 7 | "bugs": "https://github.com/siketyan/tsimports/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/siketyan/tsimports.git", 11 | "directory": "packages/@tsimports/cli-win32-x64" 12 | }, 13 | "engines": { 14 | "node": ">=18" 15 | }, 16 | "os": ["win32"], 17 | "cpu": ["x64"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/@tsimports/cli-darwin-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsimports/cli-darwin-x64", 3 | "version": "0.1.4", 4 | "author": "Naoki Ikeguchi ", 5 | "license": "MIT", 6 | "homepage": "https://github.com/siketyan/tsimports", 7 | "bugs": "https://github.com/siketyan/tsimports/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/siketyan/tsimports.git", 11 | "directory": "packages/@tsimports/cli-darwin-x64" 12 | }, 13 | "engines": { 14 | "node": ">=18" 15 | }, 16 | "os": ["darwin"], 17 | "cpu": ["x64"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/@tsimports/cli-darwin-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsimports/cli-darwin-arm64", 3 | "version": "0.1.4", 4 | "author": "Naoki Ikeguchi ", 5 | "license": "MIT", 6 | "homepage": "https://github.com/siketyan/tsimports", 7 | "bugs": "https://github.com/siketyan/tsimports/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/siketyan/tsimports.git", 11 | "directory": "packages/@tsimports/cli-darwin-arm64" 12 | }, 13 | "engines": { 14 | "node": ">=18" 15 | }, 16 | "os": ["darwin"], 17 | "cpu": ["arm64"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/@tsimports/cli-win32-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsimports/cli-win32-arm64", 3 | "version": "0.1.4", 4 | "author": "Naoki Ikeguchi ", 5 | "license": "MIT", 6 | "homepage": "https://github.com/siketyan/tsimports", 7 | "bugs": "https://github.com/siketyan/tsimports/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/siketyan/tsimports.git", 11 | "directory": "packages/@tsimports/cli-win32-arm64" 12 | }, 13 | "engines": { 14 | "node": ">=18" 15 | }, 16 | "os": ["win32"], 17 | "cpu": ["arm64"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/@tsimports/cli-linux-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsimports/cli-linux-x64", 3 | "version": "0.1.4", 4 | "author": "Naoki Ikeguchi ", 5 | "license": "MIT", 6 | "homepage": "https://github.com/siketyan/tsimports", 7 | "bugs": "https://github.com/siketyan/tsimports/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/siketyan/tsimports.git", 11 | "directory": "packages/@tsimports/cli-linux-x64" 12 | }, 13 | "engines": { 14 | "node": ">=18" 15 | }, 16 | "os": ["linux"], 17 | "cpu": ["x64"], 18 | "libc": ["glibc"] 19 | } 20 | -------------------------------------------------------------------------------- /packages/@tsimports/cli-linux-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsimports/cli-linux-arm64", 3 | "version": "0.1.4", 4 | "author": "Naoki Ikeguchi ", 5 | "license": "MIT", 6 | "homepage": "https://github.com/siketyan/tsimports", 7 | "bugs": "https://github.com/siketyan/tsimports/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/siketyan/tsimports.git", 11 | "directory": "packages/@tsimports/cli-linux-arm64" 12 | }, 13 | "engines": { 14 | "node": ">=18" 15 | }, 16 | "os": ["linux"], 17 | "cpu": ["arm64"], 18 | "libc": ["glibc"] 19 | } 20 | -------------------------------------------------------------------------------- /packages/@tsimports/cli-linux-musl-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsimports/cli-linux-musl-x64", 3 | "version": "0.1.4", 4 | "author": "Naoki Ikeguchi ", 5 | "license": "MIT", 6 | "homepage": "https://github.com/siketyan/tsimports", 7 | "bugs": "https://github.com/siketyan/tsimports/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/siketyan/tsimports.git", 11 | "directory": "packages/@tsimports/cli-linux-musl-x64" 12 | }, 13 | "engines": { 14 | "node": ">=18" 15 | }, 16 | "os": ["linux"], 17 | "cpu": ["x64"], 18 | "libc": ["musl"] 19 | } 20 | -------------------------------------------------------------------------------- /packages/@tsimports/cli-linux-musl-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsimports/cli-linux-musl-arm64", 3 | "version": "0.1.4", 4 | "author": "Naoki Ikeguchi ", 5 | "license": "MIT", 6 | "homepage": "https://github.com/siketyan/tsimports", 7 | "bugs": "https://github.com/siketyan/tsimports/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/siketyan/tsimports.git", 11 | "directory": "packages/@tsimports/cli-linux-musl-arm64" 12 | }, 13 | "engines": { 14 | "node": ">=18" 15 | }, 16 | "os": ["linux"], 17 | "cpu": ["arm64"], 18 | "libc": ["musl"] 19 | } 20 | -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | use biome_js_syntax::JsFileSource; 2 | use insta::assert_snapshot; 3 | use tsimports::tsimports; 4 | 5 | #[test] 6 | fn snapshot_tests() { 7 | assert_snapshot!(tsimports( 8 | "\ 9 | import fs from 'fs' 10 | import path from 'path' 11 | import _ from 'lodash' 12 | import chalk from 'chalk' 13 | import foo from 'src/foo' 14 | import foo from '../foo' 15 | import qux from '../../foo/qux' 16 | import bar from './bar' 17 | import baz from './bar/baz' 18 | import main from './' 19 | import log = console.log 20 | import type { Foo, Bar } from 'foo' 21 | import userEvent from '@testing-library/user-event' 22 | import { foo, type bar } from '@/my/module' 23 | import * as R from 'remeda' 24 | import * as utils from '~/utils' 25 | import {} from '#import' 26 | ", 27 | JsFileSource::ts(), 28 | ) 29 | .unwrap()); 30 | } 31 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tsimports" 3 | description = "A fast and opinionated imports organizer for ECMAScript and TypeScript." 4 | version = "0.1.4" 5 | rust-version = "1.81.0" 6 | edition = "2021" 7 | authors = ["Naoki Ikeguchi "] 8 | license = "MIT" 9 | readme = "README.md" 10 | 11 | [dependencies] 12 | biome_console = { path = "./biome/crates/biome_console" } 13 | biome_diagnostics = { path = "./biome/crates/biome_diagnostics" } 14 | biome_js_factory = { path = "./biome/crates/biome_js_factory" } 15 | biome_js_parser = { path = "./biome/crates/biome_js_parser" } 16 | biome_js_syntax = { path = "./biome/crates/biome_js_syntax" } 17 | biome_parser = { path = "./biome/crates/biome_parser" } 18 | biome_rowan = { path = "./biome/crates/biome_rowan" } 19 | 20 | anyhow = "1.0" 21 | clap = { version = "4.5", features = ["derive"] } 22 | glob = "0.3.1" 23 | itertools = "0.13.0" 24 | thiserror = "1.0" 25 | walkdir = "2.5" 26 | 27 | [dev-dependencies] 28 | insta = "1.40" 29 | -------------------------------------------------------------------------------- /packages/@tsimports/tsimports/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsimports/tsimports", 3 | "version": "0.1.4", 4 | "description": "A fast and opinionated imports organizer for ECMAScript and TypeScript.", 5 | "author": "Naoki Ikeguchi ", 6 | "license": "MIT", 7 | "homepage": "https://github.com/siketyan/tsimports", 8 | "bugs": "https://github.com/siketyan/tsimports/issues", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/siketyan/tsimports.git", 12 | "directory": "packages/tsimports" 13 | }, 14 | "publishConfig": { 15 | "provenance": true 16 | }, 17 | "engines": { 18 | "node": ">=18" 19 | }, 20 | "files": ["bin/tsimports", "scripts/postinstall.js", "README.md", "LICENCE.md"], 21 | "bin": { 22 | "tsimports": "bin/tsimports" 23 | }, 24 | "optionalDependencies": { 25 | "@tsimports/cli-darwin-arm64": "0.1.4", 26 | "@tsimports/cli-darwin-x64": "0.1.4", 27 | "@tsimports/cli-linux-arm64": "0.1.4", 28 | "@tsimports/cli-linux-x64": "0.1.4" 29 | }, 30 | "scripts": { 31 | "postinstall": "node scripts/postinstall.js" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Naoki Ikeguchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/@tsimports/tsimports/LICENCE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Naoki Ikeguchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/snapshots/test__snapshot_tests.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/test.rs 3 | expression: "tsimports(\"\\\nimport fs from 'fs'\nimport path from 'path'\nimport _ from 'lodash'\nimport chalk from 'chalk'\nimport foo from 'src/foo'\nimport foo from '../foo'\nimport qux from '../../foo/qux'\nimport bar from './bar'\nimport baz from './bar/baz'\nimport main from './'\nimport log = console.log\nimport type { Foo, Bar } from 'foo'\nimport userEvent from '@testing-library/user-event'\nimport { foo, type bar } from '@/my/module'\nimport * as R from 'remeda'\nimport * as utils from '~/utils'\nimport {} from '#import'\n\",\nJsFileSource::ts(),).unwrap()" 4 | --- 5 | import fs from 'fs' 6 | import path from 'path' 7 | 8 | import userEvent from '@testing-library/user-event' 9 | import chalk from 'chalk' 10 | import type { Bar, Foo } from 'foo' 11 | import _ from 'lodash' 12 | import * as R from 'remeda' 13 | import foo from 'src/foo' 14 | 15 | import { } from '#import' 16 | import { type bar, foo } from '@/my/module' 17 | import * as utils from '~/utils' 18 | 19 | import qux from '../../foo/qux' 20 | import foo from '../foo' 21 | 22 | import bar from './bar' 23 | import baz from './bar/baz' 24 | 25 | import main from './' 26 | 27 | import log = console.log 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: {} 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | permissions: 13 | checks: write 14 | contents: read 15 | 16 | jobs: 17 | checks: 18 | strategy: 19 | matrix: 20 | os: 21 | - windows-2022 22 | - macos-13 23 | - macos-14 24 | - ubuntu-22.04 25 | - ubuntu-24.04 26 | name: Checks 27 | runs-on: ${{ matrix.os }} 28 | steps: 29 | - uses: actions/checkout@v4 30 | with: 31 | submodules: true 32 | 33 | - uses: actions/cache@v4 34 | with: 35 | path: | 36 | ~/.cargo/registry 37 | ~/.cargo/git 38 | target 39 | key: ${{ runner.os }}-cargo-v1-${{ hashFiles('**/Cargo.lock') }} 40 | 41 | - uses: dtolnay/rust-toolchain@stable 42 | with: 43 | components: rustfmt,clippy 44 | 45 | - name: Run clippy 46 | uses: giraffate/clippy-action@v1 47 | with: 48 | clippy_flags: -- -Dwarnings 49 | reporter: github-pr-check 50 | fail_on_error: true 51 | 52 | - name: Run rustfmt 53 | run: cargo fmt --all --check 54 | 55 | - name: Run tests 56 | run: cargo test 57 | -------------------------------------------------------------------------------- /src/analyze.rs: -------------------------------------------------------------------------------- 1 | use biome_js_syntax::{AnyJsModuleItem, JsImport, JsModule}; 2 | use itertools::Itertools; 3 | 4 | use crate::import_kind::ImportKind; 5 | 6 | pub fn collect_imports(module: &JsModule) -> Vec { 7 | module 8 | .items() 9 | .into_iter() 10 | .filter_map(|item| match item { 11 | AnyJsModuleItem::JsImport(import) => Some(import), 12 | _ => None, 13 | }) 14 | .collect() 15 | } 16 | 17 | #[derive(Clone, Debug)] 18 | pub struct ImportGroup { 19 | kind: ImportKind, 20 | items: Vec, 21 | } 22 | 23 | impl ImportGroup { 24 | fn new(kind: ImportKind, items: Vec) -> Self { 25 | Self { kind, items } 26 | } 27 | 28 | pub fn items(&self) -> impl Iterator { 29 | self.items.iter() 30 | } 31 | 32 | pub fn reorder_in_place(&mut self) { 33 | self.items 34 | .sort_by_key(|import| import.source_text().unwrap().to_string()) 35 | } 36 | } 37 | 38 | pub fn group_imports(imports: impl IntoIterator) -> Vec { 39 | imports 40 | .into_iter() 41 | .into_group_map_by(|import| ImportKind::guess(import.source_text().unwrap().text())) 42 | .into_iter() 43 | .map(|(kind, imports)| ImportGroup::new(kind, imports)) 44 | .collect() 45 | } 46 | 47 | pub fn order_groups(groups: impl IntoIterator) -> Vec { 48 | groups 49 | .into_iter() 50 | .sorted_by_key(|group| group.kind) 51 | .collect() 52 | } 53 | -------------------------------------------------------------------------------- /packages/@tsimports/tsimports/scripts/postinstall.js: -------------------------------------------------------------------------------- 1 | const { platform, arch } = process; 2 | // biome-ignore lint/style/useNodejsImportProtocol: would be a breaking change, consider bumping node version next major version 3 | const { execSync } = require("child_process"); 4 | 5 | function isMusl() { 6 | let stderr; 7 | try { 8 | stderr = execSync("ldd --version", { 9 | stdio: ["pipe", "pipe", "pipe"], 10 | }); 11 | } catch (err) { 12 | stderr = err.stderr; 13 | } 14 | if (stderr.indexOf("musl") > -1) { 15 | return true; 16 | } 17 | return false; 18 | } 19 | 20 | const PLATFORMS = { 21 | win32: { 22 | x64: "@tsimports/cli-win32-x64/tsimports.exe", 23 | arm64: "@tsimports/cli-win32-arm64/tsimports.exe", 24 | }, 25 | darwin: { 26 | x64: "@tsimports/cli-darwin-x64/tsimports", 27 | arm64: "@tsimports/cli-darwin-arm64/tsimports", 28 | }, 29 | linux: { 30 | x64: "@tsimports/cli-linux-x64/tsimports", 31 | arm64: "@tsimports/cli-linux-arm64/tsimports", 32 | }, 33 | "linux-musl": { 34 | x64: "@tsimports/cli-linux-x64-musl/tsimports", 35 | arm64: "@tsimports/cli-linux-arm64-musl/tsimports", 36 | }, 37 | }; 38 | 39 | const binName = platform === "linux" && isMusl() ? PLATFORMS?.["linux-musl"]?.[arch] : PLATFORMS?.[platform]?.[arch]; 40 | 41 | if (binName) { 42 | let binPath; 43 | try { 44 | binPath = require.resolve(binName); 45 | } catch { 46 | console.warn( 47 | `The tsimports CLI postinstall script failed to resolve the binary file "${binName}". Running tsimports from the npm package will probably not work correctly.`, 48 | ); 49 | } 50 | } else { 51 | console.warn( 52 | "The tsimports CLI package doesn't ship with prebuilt binaries for your platform yet. " + 53 | "You can still use the CLI by cloning the tsimports repo from GitHub, " + 54 | "and follow the instructions there to build the CLI for your platform.", 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod analyze; 2 | mod import_kind; 3 | mod transform; 4 | 5 | use biome_js_parser::{parse, JsParserOptions}; 6 | use biome_js_syntax::{AnyJsRoot, JsFileSource}; 7 | use biome_parser::diagnostic::ParseDiagnostic; 8 | use biome_rowan::{AstNode, BatchMutationExt}; 9 | use itertools::Itertools; 10 | 11 | use crate::analyze::{collect_imports, group_imports, order_groups}; 12 | use crate::transform::Remake; 13 | 14 | #[derive(Clone, Debug, thiserror::Error)] 15 | pub enum Error { 16 | #[error("Failed to parse the text as a ECMAScript or TypeScript module.")] 17 | Parser(Vec), 18 | 19 | #[error("Only module files (.mjs) or TypeScript files (.ts) are supported.")] 20 | NotJSModule, 21 | } 22 | 23 | pub fn tsimports<'a>(input: impl Into<&'a str>, source: JsFileSource) -> Result { 24 | let root = parse(input.into(), source, JsParserOptions::default()) 25 | .ok() 26 | .map_err(Error::Parser)?; 27 | 28 | let AnyJsRoot::JsModule(root) = root else { 29 | return Err(Error::NotJSModule); 30 | }; 31 | 32 | let mut groups = order_groups(group_imports(collect_imports(&root))); 33 | 34 | groups.iter_mut().for_each(|group| group.reorder_in_place()); 35 | 36 | let mut mutation = root.begin(); 37 | 38 | for group in &groups { 39 | for item in group.items() { 40 | mutation.remove_node(item.to_owned()); 41 | } 42 | } 43 | 44 | let imports = groups 45 | .into_iter() 46 | .map(|group| { 47 | group 48 | .items() 49 | .map(|item| item.remake().unwrap().text()) 50 | .join("\n") 51 | }) 52 | .join("\n\n"); 53 | 54 | Ok([ 55 | imports, 56 | mutation 57 | .commit() 58 | .trim_leading_trivia() 59 | .unwrap() 60 | .text() 61 | .to_string(), 62 | ] 63 | .join("\n\n")) 64 | } 65 | -------------------------------------------------------------------------------- /packages/@tsimports/tsimports/README.md: -------------------------------------------------------------------------------- 1 | # tsimports 2 | 3 | ✨ A fast and opinionated imports organizer for ECMAScript and TypeScript. 4 | 5 | > [!WARNING] 6 | > This project is in alpha stage. Do not use in production. 7 | 8 | 9 | ## Installation 10 | 11 | ```shell 12 | npm install -g tsimports 13 | ``` 14 | 15 | > [!TIP] 16 | > If you want to manage the version of tsimports, use `-D` instead of `-g`. 17 | 18 | 19 | ## Usage 20 | 21 | ### Basic 22 | 23 | #### Format a file and write the result to stdout 24 | 25 | ```shell 26 | tsimports ./src/foo.ts 27 | ``` 28 | 29 | #### Format a file and write in-place 30 | 31 | ```shell 32 | tsimports --write ./src/foo.ts 33 | ``` 34 | 35 | #### Format all TypeScript files 36 | 37 | ```shell 38 | tsimports --write ./src/**/*.ts 39 | ``` 40 | 41 | ### Advanced 42 | 43 | #### Format a stdin input 44 | 45 | > [!WARNING] 46 | > tsimports infers the language from the file extension. 47 | > As the standard input has no extension, we cannot infer the language. 48 | > Use `--language` to assume the input is JS, JSX, TS, or TSX. 49 | 50 | ```shell 51 | cat ./src/foo.ts | tsimports --language ts 52 | ``` 53 | 54 | 55 | ## The rule 56 | 57 | tsimports groups and sorts import statements in the file in a fixed rule. 58 | As tsimports offers you an opinionated rule, you cannot configure any of the rule. 59 | 60 | 61 | ### Groups 62 | 63 | tsimports splits the imports into several groups in the following order: 64 | 65 | 1. Built-in modules (e.g. `node:assert`, `fs`, or `bun`) 66 | 2. External modules (e.g. `react`, `@testing-library/react`, or `hono/jwt`) 67 | 3. Internal modules (e.g. `~/foo` or `@/foo`, if configured in bundler or somewhere) 68 | 4. Parent modules (e.g. `../foo` or `../../foo`) 69 | 5. Sibling modules (e.g. `./foo` or `./foo/bar`) 70 | 6. Index modules (e.g. `.`, `./`, `./index`, or `./index.js`) 71 | 72 | 73 | ### Ordering 74 | 75 | tsimports sorts imports in each group in alphabetical order (case-sensitive). 76 | 77 | 78 | ### Position 79 | 80 | tsimports collects all imports at the top of the file. 81 | Any other statements are retained at the position and tsimports doesn't modify anything about them. 82 | 83 | 84 | # Acknowledgements 85 | 86 | tsimports is built on top of the [Biome](https://github.com/biomejs/biome) infrastructure, including the JS syntax, parser, and other utils. 87 | If you like tsimports, please consider also supporting the Biome project. 88 | -------------------------------------------------------------------------------- /packages/@tsimports/tsimports/scripts/generate-packages.mjs: -------------------------------------------------------------------------------- 1 | import * as fs from "node:fs"; 2 | import { resolve } from "node:path"; 3 | import { fileURLToPath } from "node:url"; 4 | import { format } from "node:util"; 5 | 6 | const CLI_ROOT = resolve(fileURLToPath(import.meta.url), "../.."); 7 | const PACKAGES_ROOT = resolve(CLI_ROOT, ".."); 8 | const REPO_ROOT = resolve(PACKAGES_ROOT, "../.."); 9 | const MANIFEST_PATH = resolve(CLI_ROOT, "package.json"); 10 | 11 | const rootManifest = JSON.parse(fs.readFileSync(MANIFEST_PATH).toString("utf-8")); 12 | 13 | function getName(platform, arch, prefix = "cli") { 14 | return format(`${prefix}-${platform}`, arch); 15 | } 16 | 17 | function copyBinaryToNativePackage(platform, arch) { 18 | const os = platform.split("-")[0]; 19 | const buildName = getName(platform, arch); 20 | const packageRoot = resolve(PACKAGES_ROOT, buildName); 21 | const packageName = `@tsimports/${buildName}`; 22 | 23 | // Update the package.json manifest 24 | const { version, license, repository, engines, homepage } = rootManifest; 25 | 26 | const manifest = JSON.stringify( 27 | { 28 | name: packageName, 29 | version, 30 | license, 31 | repository, 32 | engines, 33 | homepage, 34 | os: [os], 35 | cpu: [arch], 36 | libc: os === "linux" ? (packageName.endsWith("musl") ? ["musl"] : ["glibc"]) : undefined, 37 | }, 38 | null, 39 | 2, 40 | ); 41 | 42 | const manifestPath = resolve(packageRoot, "package.json"); 43 | console.log(`Update manifest ${manifestPath}`); 44 | fs.writeFileSync(manifestPath, manifest); 45 | 46 | // Copy the CLI binary 47 | const ext = os === "win32" ? ".exe" : ""; 48 | const binarySource = resolve(REPO_ROOT, `${getName(platform, arch, "tsimports")}${ext}`); 49 | const binaryTarget = resolve(packageRoot, `tsimports${ext}`); 50 | 51 | if (!fs.existsSync(binarySource)) { 52 | console.error(`Source for binary for ${buildName} not found at: ${binarySource}`); 53 | process.exit(1); 54 | } 55 | 56 | console.log(`Copy binary ${binaryTarget}`); 57 | fs.copyFileSync(binarySource, binaryTarget); 58 | fs.chmodSync(binaryTarget, 0o755); 59 | } 60 | 61 | const PLATFORMS = ["darwin-%s", "linux-%s"]; 62 | const ARCHITECTURES = ["x64", "arm64"]; 63 | 64 | for (const platform of PLATFORMS) { 65 | for (const arch of ARCHITECTURES) { 66 | copyBinaryToNativePackage(platform, arch); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tsimports 2 | 3 | ✨ A fast and opinionated imports organizer for ECMAScript and TypeScript. 4 | 5 | > [!WARNING] 6 | > This project is in alpha stage. Production use is not recommended. 7 | > If you find some bugs, please feel free to report to [Issues](https://github.com/siketyan/tsimports/issues). 8 | 9 | 10 | ## Installation 11 | 12 | ```shell 13 | npm install -g @tsimports/tsimports 14 | ``` 15 | 16 | > [!TIP] 17 | > If you want to share the version of tsimports in the project, use `-D` instead of `-g`. 18 | 19 | 20 | ## Usage 21 | 22 | ### Basic 23 | 24 | #### Format a file and write the result to stdout 25 | 26 | ```shell 27 | tsimports ./src/foo.ts 28 | ``` 29 | 30 | #### Format a file and write in-place 31 | 32 | ```shell 33 | tsimports --write ./src/foo.ts 34 | ``` 35 | 36 | #### Format all TypeScript files 37 | 38 | ```shell 39 | tsimports --write ./src/**/*.ts 40 | ``` 41 | 42 | ### Advanced 43 | 44 | #### Format a stdin input 45 | 46 | > [!WARNING] 47 | > tsimports infers the language from the file extension. 48 | > As the standard input has no extension, we cannot infer the language. 49 | > Use `--language` to assume the input is JS, JSX, TS, or TSX. 50 | 51 | ```shell 52 | cat ./src/foo.ts | tsimports --language ts 53 | ``` 54 | 55 | 56 | ## The rule 57 | 58 | tsimports groups and sorts import statements in the file in a fixed rule. 59 | As tsimports offers you an opinionated rule, you cannot configure any of the rule. 60 | 61 | 62 | ### Groups 63 | 64 | tsimports splits the imports into several groups in the following order: 65 | 66 | 1. Built-in modules (e.g. `node:assert`, `fs`, or `bun`) 67 | 2. External modules (e.g. `react`, `@testing-library/react`, or `hono/jwt`) 68 | 3. Internal modules (e.g. `~/foo` or `@/foo`, if configured in bundler or somewhere) 69 | 4. Parent modules (e.g. `../foo` or `../../foo`) 70 | 5. Sibling modules (e.g. `./foo` or `./foo/bar`) 71 | 6. Index modules (e.g. `.`, `./`, `./index`, or `./index.js`) 72 | 73 | 74 | ### Ordering 75 | 76 | tsimports sorts imports in each group in alphabetical order (case-sensitive). 77 | 78 | 79 | ### Position 80 | 81 | tsimports collects all imports at the top of the file. 82 | Any other statements are retained at the position and tsimports doesn't modify anything about them. 83 | 84 | 85 | ## Acknowledgements 86 | 87 | tsimports is built on top of the [Biome](https://github.com/biomejs/biome) infrastructure, including the JS syntax, parser, and other utils. 88 | If you like tsimports, please consider also supporting the Biome project. 89 | -------------------------------------------------------------------------------- /src/import_kind.rs: -------------------------------------------------------------------------------- 1 | const NODE_BUILTIN_MODULES: [&str; 53] = [ 2 | "assert", 3 | "assert/strict", 4 | "async_hooks", 5 | "buffer", 6 | "child_process", 7 | "cluster", 8 | "console", 9 | "constants", 10 | "crypto", 11 | "dgram", 12 | "diagnostics_channel", 13 | "dns", 14 | "dns/promises", 15 | "domain", 16 | "events", 17 | "fs", 18 | "fs/promises", 19 | "http", 20 | "http2", 21 | "https", 22 | "inspector", 23 | "inspector/promises", 24 | "module", 25 | "net", 26 | "os", 27 | "path", 28 | "path/posix", 29 | "path/win32", 30 | "perf_hooks", 31 | "process", 32 | "punycode", 33 | "querystring", 34 | "readline", 35 | "readline/promises", 36 | "repl", 37 | "stream", 38 | "stream/consumers", 39 | "stream/promises", 40 | "stream/web", 41 | "string_decoder", 42 | "timers", 43 | "timers/promises", 44 | "tls", 45 | "trace_events", 46 | "tty", 47 | "url", 48 | "util", 49 | "util/types", 50 | "v8", 51 | "vm", 52 | "wasi", 53 | "worker_threads", 54 | "zlib", 55 | ]; 56 | 57 | #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 58 | pub enum ImportKind { 59 | Builtin, 60 | External, 61 | Internal, 62 | Parent, 63 | Sibling, 64 | Index, 65 | } 66 | 67 | impl ImportKind { 68 | pub fn guess(name: &str) -> Self { 69 | if name == "bun" || name.starts_with("node:") { 70 | return Self::Builtin; 71 | } 72 | 73 | if NODE_BUILTIN_MODULES.contains(&name) { 74 | return Self::Builtin; 75 | } 76 | 77 | if name == "." || name == "./" || name == "./index" || name.starts_with("./index.") { 78 | return Self::Index; 79 | } 80 | 81 | if name.starts_with("./") { 82 | return Self::Sibling; 83 | } 84 | 85 | if name.starts_with("../") { 86 | return Self::Parent; 87 | } 88 | 89 | let mut chars = name.chars(); 90 | loop { 91 | let Some(char) = chars.next() else { 92 | break; 93 | }; 94 | 95 | if char == '@' { 96 | continue; 97 | } 98 | 99 | if char.is_ascii_alphabetic() { 100 | return Self::External; 101 | } 102 | 103 | break; 104 | } 105 | 106 | Self::Internal 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /packages/@tsimports/tsimports/bin/tsimports: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const { platform, arch, env, version, release } = process; 3 | const { execSync } = require("child_process"); 4 | 5 | function isMusl() { 6 | let stderr; 7 | try { 8 | stderr = execSync("ldd --version", { 9 | stdio: ["pipe", "pipe", "pipe"], 10 | }); 11 | } catch (err) { 12 | stderr = err.stderr; 13 | } 14 | if (stderr.indexOf("musl") > -1) { 15 | return true; 16 | } 17 | return false; 18 | } 19 | 20 | const PLATFORMS = { 21 | win32: { 22 | x64: "@tsimports/cli-win32-x64/tsimports.exe", 23 | arm64: "@tsimports/cli-win32-arm64/tsimports.exe", 24 | }, 25 | darwin: { 26 | x64: "@tsimports/cli-darwin-x64/tsimports", 27 | arm64: "@tsimports/cli-darwin-arm64/tsimports", 28 | }, 29 | linux: { 30 | x64: "@tsimports/cli-linux-x64/tsimports", 31 | arm64: "@tsimports/cli-linux-arm64/tsimports", 32 | }, 33 | "linux-musl": { 34 | x64: "@tsimports/cli-linux-x64-musl/tsimports", 35 | arm64: "@tsimports/cli-linux-arm64-musl/tsimports", 36 | }, 37 | }; 38 | 39 | const binPath = env.TSIMPORTS_BINARY || 40 | (platform === "linux" && isMusl() 41 | ? PLATFORMS?.["linux-musl"]?.[arch] 42 | : PLATFORMS?.[platform]?.[arch] 43 | ); 44 | 45 | if (binPath) { 46 | const packageManager = detectPackageManager(); 47 | const result = require("child_process").spawnSync( 48 | require.resolve(binPath), 49 | process.argv.slice(2), 50 | { 51 | shell: false, 52 | stdio: "inherit", 53 | env: { 54 | ...env, 55 | JS_RUNTIME_VERSION: version, 56 | JS_RUNTIME_NAME: release.name, 57 | ...(packageManager != null 58 | ? { NODE_PACKAGE_MANAGER: packageManager } 59 | : {}), 60 | }, 61 | }, 62 | ); 63 | 64 | if (result.error) { 65 | throw result.error; 66 | } 67 | 68 | process.exitCode = result.status; 69 | } else { 70 | console.error( 71 | "The tsimports CLI package doesn't ship with prebuilt binaries for your platform yet. " + 72 | "You can still use the CLI by cloning the tsimports repo from GitHub, " + 73 | "and follow the instructions there to build the CLI for your platform.", 74 | ); 75 | process.exitCode = 1; 76 | } 77 | 78 | /** 79 | * NPM, Yarn, and other package manager set the `npm_config_user_agent`. It has the following format: 80 | * 81 | * ``` 82 | * "npm/8.3.0 node/v16.13.2 win32 x64 workspaces/false 83 | * ``` 84 | * 85 | * @returns The package manager string (`npm/8.3.0`) or null if the user agent string isn't set. 86 | */ 87 | function detectPackageManager() { 88 | const userAgent = env.npm_config_user_agent; 89 | 90 | if (userAgent == null) { 91 | return null; 92 | } 93 | 94 | return userAgent.split(" ")[0]; 95 | } 96 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@biomejs/biome': 12 | specifier: ^1.9.4 13 | version: 1.9.4 14 | 15 | packages/@tsimports/cli-darwin-arm64: {} 16 | 17 | packages/@tsimports/cli-darwin-x64: {} 18 | 19 | packages/@tsimports/cli-linux-arm64: {} 20 | 21 | packages/@tsimports/cli-linux-musl-arm64: {} 22 | 23 | packages/@tsimports/cli-linux-musl-x64: {} 24 | 25 | packages/@tsimports/cli-linux-x64: {} 26 | 27 | packages/@tsimports/cli-win32-arm64: {} 28 | 29 | packages/@tsimports/cli-win32-x64: {} 30 | 31 | packages/@tsimports/tsimports: {} 32 | 33 | packages: 34 | 35 | '@biomejs/biome@1.9.4': 36 | resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} 37 | engines: {node: '>=14.21.3'} 38 | hasBin: true 39 | 40 | '@biomejs/cli-darwin-arm64@1.9.4': 41 | resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} 42 | engines: {node: '>=14.21.3'} 43 | cpu: [arm64] 44 | os: [darwin] 45 | 46 | '@biomejs/cli-darwin-x64@1.9.4': 47 | resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} 48 | engines: {node: '>=14.21.3'} 49 | cpu: [x64] 50 | os: [darwin] 51 | 52 | '@biomejs/cli-linux-arm64-musl@1.9.4': 53 | resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} 54 | engines: {node: '>=14.21.3'} 55 | cpu: [arm64] 56 | os: [linux] 57 | 58 | '@biomejs/cli-linux-arm64@1.9.4': 59 | resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} 60 | engines: {node: '>=14.21.3'} 61 | cpu: [arm64] 62 | os: [linux] 63 | 64 | '@biomejs/cli-linux-x64-musl@1.9.4': 65 | resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} 66 | engines: {node: '>=14.21.3'} 67 | cpu: [x64] 68 | os: [linux] 69 | 70 | '@biomejs/cli-linux-x64@1.9.4': 71 | resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} 72 | engines: {node: '>=14.21.3'} 73 | cpu: [x64] 74 | os: [linux] 75 | 76 | '@biomejs/cli-win32-arm64@1.9.4': 77 | resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} 78 | engines: {node: '>=14.21.3'} 79 | cpu: [arm64] 80 | os: [win32] 81 | 82 | '@biomejs/cli-win32-x64@1.9.4': 83 | resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} 84 | engines: {node: '>=14.21.3'} 85 | cpu: [x64] 86 | os: [win32] 87 | 88 | snapshots: 89 | 90 | '@biomejs/biome@1.9.4': 91 | optionalDependencies: 92 | '@biomejs/cli-darwin-arm64': 1.9.4 93 | '@biomejs/cli-darwin-x64': 1.9.4 94 | '@biomejs/cli-linux-arm64': 1.9.4 95 | '@biomejs/cli-linux-arm64-musl': 1.9.4 96 | '@biomejs/cli-linux-x64': 1.9.4 97 | '@biomejs/cli-linux-x64-musl': 1.9.4 98 | '@biomejs/cli-win32-arm64': 1.9.4 99 | '@biomejs/cli-win32-x64': 1.9.4 100 | 101 | '@biomejs/cli-darwin-arm64@1.9.4': 102 | optional: true 103 | 104 | '@biomejs/cli-darwin-x64@1.9.4': 105 | optional: true 106 | 107 | '@biomejs/cli-linux-arm64-musl@1.9.4': 108 | optional: true 109 | 110 | '@biomejs/cli-linux-arm64@1.9.4': 111 | optional: true 112 | 113 | '@biomejs/cli-linux-x64-musl@1.9.4': 114 | optional: true 115 | 116 | '@biomejs/cli-linux-x64@1.9.4': 117 | optional: true 118 | 119 | '@biomejs/cli-win32-arm64@1.9.4': 120 | optional: true 121 | 122 | '@biomejs/cli-win32-x64@1.9.4': 123 | optional: true 124 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs::{read_to_string, write}; 2 | use std::io::{stdin, Read}; 3 | use std::path::{Path, PathBuf}; 4 | 5 | use anyhow::{anyhow, Result}; 6 | use biome_console::{markup, ColorMode, Console, EnvConsole, LogLevel}; 7 | use biome_diagnostics::PrintDiagnostic; 8 | use biome_js_syntax::JsFileSource; 9 | use clap::{Parser, ValueEnum}; 10 | use glob::glob; 11 | use tsimports::{tsimports, Error}; 12 | use walkdir::WalkDir; 13 | 14 | #[derive(Copy, Clone, Debug, Default, ValueEnum)] 15 | enum Language { 16 | #[default] 17 | JS, 18 | JSX, 19 | TS, 20 | TSX, 21 | } 22 | 23 | impl Language { 24 | fn from_extension(ext: &str) -> Option { 25 | match ext { 26 | "js" | "mjs" => Some(Self::JS), 27 | "jsx" => Some(Self::JSX), 28 | "ts" | "cts" | "mts" => Some(Self::TS), 29 | "tsx" => Some(Self::TSX), 30 | _ => None, 31 | } 32 | } 33 | 34 | fn from_path(path: impl AsRef) -> Option { 35 | Self::from_extension(path.as_ref().extension().and_then(|ext| ext.to_str())?) 36 | } 37 | 38 | fn to_file_source(&self) -> JsFileSource { 39 | match self { 40 | Self::JS => JsFileSource::js_module(), 41 | Self::JSX => JsFileSource::jsx(), 42 | Self::TS => JsFileSource::ts(), 43 | Self::TSX => JsFileSource::tsx(), 44 | } 45 | } 46 | } 47 | 48 | #[derive(Debug, Parser)] 49 | #[command(about, version)] 50 | struct Args { 51 | /// Paths or globs of files to organize imports. Defaults to the standard input. 52 | paths: Option>, 53 | 54 | /// Specify the language to parse the input as. Inferred by the file extension by default. 55 | #[clap(short, long)] 56 | language: Option, 57 | 58 | /// Write the formatted result into the file directly, without printing to the standard output. 59 | #[clap(short, long)] 60 | write: bool, 61 | } 62 | 63 | fn main() { 64 | let mut console = EnvConsole::new(ColorMode::Auto); 65 | if let Err(e) = run(&mut console) { 66 | console.println( 67 | LogLevel::Error, 68 | markup! { "\u{2716} "{e.to_string()} }, 69 | ) 70 | } 71 | } 72 | 73 | fn run(console: &mut impl Console) -> Result<()> { 74 | let args = Args::parse(); 75 | 76 | if let Some(paths) = &args.paths { 77 | for path in paths.iter() { 78 | for entry in glob(path)? { 79 | let entry = entry?; 80 | if entry.is_dir() { 81 | WalkDir::new(entry) 82 | .into_iter() 83 | .filter_map(|e| e.ok()) 84 | .filter_map(|e| { 85 | let path = e.path().to_path_buf(); 86 | match Language::from_path(&path) { 87 | Some(lang) => Some((path, lang)), 88 | _ => None, 89 | } 90 | }) 91 | .map(|(path, lang)| { 92 | run_single(Input::File(path, Some(lang)), &args, console) 93 | }) 94 | .collect::>()?; 95 | } else { 96 | let lang = Language::from_path(&entry); 97 | 98 | run_single(Input::File(entry, lang), &args, console)?; 99 | } 100 | } 101 | } 102 | } else { 103 | if args.language.is_none() { 104 | console.println(LogLevel::Error, markup! { 105 | 106 | "\u{26a0} Input language is not specified, assuming as an ECMAScript module. Use " 107 | "--language " 108 | " option to override." 109 | 110 | }); 111 | } 112 | 113 | run_single(Input::Stdin, &args, console)?; 114 | } 115 | 116 | Ok(()) 117 | } 118 | 119 | enum Input { 120 | File(PathBuf, Option), 121 | Stdin, 122 | } 123 | 124 | fn run_single(input: Input, args: &Args, console: &mut impl Console) -> Result<()> { 125 | let mut source = JsFileSource::js_module(); 126 | let buf = match &input { 127 | Input::File(path, lang) => { 128 | if let Some(lang) = lang { 129 | source = lang.to_file_source(); 130 | } 131 | 132 | read_to_string(path)? 133 | } 134 | _ => { 135 | let mut buf = String::new(); 136 | stdin().read_to_string(&mut buf)?; 137 | buf 138 | } 139 | }; 140 | 141 | if let Some(lang) = args.language { 142 | source = lang.to_file_source(); 143 | } 144 | 145 | let output = match tsimports(buf.as_str(), source) { 146 | Ok(o) => o, 147 | Err(e) => match e { 148 | Error::Parser(diags) => { 149 | for diag in diags { 150 | console.println( 151 | LogLevel::Error, 152 | markup! { {PrintDiagnostic::verbose(&diag)} }, 153 | ); 154 | } 155 | 156 | std::process::exit(1); 157 | } 158 | _ => return Err(anyhow!(e)), 159 | }, 160 | }; 161 | 162 | if args.write { 163 | let Input::File(path, _) = input else { 164 | return Err(anyhow!( 165 | "Can't write the result as the input was from the standard input." 166 | )); 167 | }; 168 | 169 | write(path, output)?; 170 | } else { 171 | print!("{}", output); 172 | } 173 | 174 | Ok(()) 175 | } 176 | -------------------------------------------------------------------------------- /.github/workflows/release-cli.yml: -------------------------------------------------------------------------------- 1 | name: Release CLI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - packages/@tsimports/tsimports/package.json 9 | 10 | jobs: 11 | check: 12 | name: Check version 13 | runs-on: ubuntu-latest 14 | outputs: 15 | version: ${{ env.version }} 16 | prerelease: ${{ env.prerelease }} 17 | nightly: ${{ env.nightly }} 18 | version_changed: ${{ steps.version.outputs.changed }} 19 | steps: 20 | - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 21 | 22 | - name: Check version changes 23 | uses: EndBug/version-check@36ff30f37c7deabe56a30caa043d127be658c425 # v2.1.5 24 | if: env.nightly != 'true' 25 | id: version 26 | with: 27 | diff-search: true 28 | file-name: packages/@tsimports/tsimports/package.json 29 | 30 | - name: Set version name 31 | if: steps.version.outputs.changed == 'true' 32 | run: | 33 | echo "Version change found! New version: ${{ steps.version.outputs.version }} (${{ steps.version.outputs.version_type }})" 34 | echo "version=${{ steps.version.outputs.version }}" >> $GITHUB_ENV 35 | 36 | build: 37 | needs: check 38 | strategy: 39 | matrix: 40 | include: 41 | - os: windows-2022 42 | target: x86_64-pc-windows-msvc 43 | code-target: win32-x64 44 | - os: windows-2022 45 | target: aarch64-pc-windows-msvc 46 | code-target: win32-arm64 47 | - os: ubuntu-24.04 48 | target: x86_64-unknown-linux-gnu 49 | code-target: linux-x64 50 | - os: ubuntu-24.04 51 | target: aarch64-unknown-linux-gnu 52 | code-target: linux-arm64 53 | - os: ubuntu-24.04 54 | target: x86_64-unknown-linux-musl 55 | code-target: linux-x64-musl 56 | - os: ubuntu-24.04 57 | target: aarch64-unknown-linux-musl 58 | code-target: linux-arm64-musl 59 | - os: macos-14 60 | target: x86_64-apple-darwin 61 | code-target: darwin-x64 62 | - os: macos-14 63 | target: aarch64-apple-darwin 64 | code-target: darwin-arm64 65 | name: Package ${{ matrix.code-target }} 66 | runs-on: ${{ matrix.os }} 67 | env: 68 | version: ${{ needs.check.outputs.version }} 69 | outputs: 70 | version: ${{ env.version }} 71 | prerelease: ${{ needs.check.outputs.prerelease }} 72 | steps: 73 | - name: Checkout repository 74 | uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 75 | with: 76 | submodules: true 77 | 78 | - name: Install Node.js 79 | uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 80 | with: 81 | node-version: 20 82 | 83 | - name: Install Rust toolchain 84 | run: rustup target add ${{ matrix.target }} 85 | 86 | - name: Install arm64 toolchain 87 | if: matrix.code-target == 'linux-arm64' || matrix.code-target == 'linux-arm64-musl' 88 | run: | 89 | sudo apt-get update 90 | sudo apt-get install -y gcc-aarch64-linux-gnu 91 | 92 | - name: Install musl toolchain 93 | if: matrix.code-target == 'linux-x64-musl' || matrix.code-target == 'linux-arm64-musl' 94 | run: | 95 | sudo apt-get update 96 | sudo apt-get install -y musl-tools 97 | 98 | # - name: Audit crates.io dependencies 99 | # if: matrix.code-target == 'linux-x64' 100 | # run: cargo audit 101 | 102 | - name: Set jemalloc page size for linux-arm64 103 | if: matrix.code-target == 'linux-arm64' 104 | run: | 105 | echo "JEMALLOC_SYS_WITH_LG_PAGE=16" >> $GITHUB_ENV 106 | 107 | # Build the CLI binary 108 | - name: Build binaries 109 | run: cargo build --release --target ${{ matrix.target }} 110 | env: 111 | CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc 112 | CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER: aarch64-linux-gnu-gcc 113 | # Strip all debug symbols from the resulting binaries 114 | RUSTFLAGS: "-C strip=symbols" 115 | 116 | # Copy the CLI binary and rename it to include the name of the target platform 117 | - name: Copy CLI binary 118 | if: matrix.os == 'windows-2022' 119 | run: | 120 | mkdir dist 121 | cp target/${{ matrix.target }}/release/tsimports.exe ./dist/tsimports-${{ matrix.code-target }}.exe 122 | 123 | - name: Copy CLI binary 124 | if: matrix.os != 'windows-2022' 125 | run: | 126 | mkdir dist 127 | cp target/${{ matrix.target }}/release/tsimports ./dist/tsimports-${{ matrix.code-target }} 128 | 129 | # Upload the CLI binary as a build artifact 130 | - name: Upload CLI artifact 131 | uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 132 | with: 133 | name: cli-${{ matrix.target }} 134 | path: ./dist/tsimports-* 135 | if-no-files-found: error 136 | 137 | publish: 138 | name: Publish 139 | runs-on: ubuntu-latest 140 | needs: 141 | - build 142 | environment: npm-publish 143 | permissions: 144 | contents: write 145 | id-token: write 146 | steps: 147 | - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 148 | 149 | - name: Download CLI artifacts 150 | uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 151 | with: 152 | pattern: cli-* 153 | merge-multiple: true 154 | 155 | - name: Install Node.js 156 | uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 157 | with: 158 | node-version: 20 159 | registry-url: 'https://registry.npmjs.org' 160 | 161 | - name: Generate npm packages 162 | run: node packages/@tsimports/tsimports/scripts/generate-packages.mjs 163 | 164 | - name: Publish npm packages as latest 165 | if: needs.build.outputs.prerelease != 'true' 166 | env: 167 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 168 | run: | 169 | for package in packages/@tsimports/*; do 170 | npm publish $package --tag latest --access public --provenance 171 | done 172 | 173 | - name: Create GitHub release and tag 174 | uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 175 | env: 176 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 177 | with: 178 | name: CLI v${{ needs.build.outputs.version }} 179 | tag_name: cli/v${{ needs.build.outputs.version }} 180 | draft: false 181 | prerelease: ${{ needs.build.outputs.prerelease == 'true' }} 182 | files: | 183 | tsimports-* 184 | fail_on_unmatched_files: true 185 | generate_release_notes: true 186 | -------------------------------------------------------------------------------- /src/transform.rs: -------------------------------------------------------------------------------- 1 | use biome_js_factory::make; 2 | use biome_js_syntax::{ 3 | AnyJsBinding, AnyJsCombinedSpecifier, AnyJsImportAssertionEntry, AnyJsImportClause, 4 | AnyJsModuleSource, AnyJsNamedImportSpecifier, JsDefaultImportSpecifier, JsImport, 5 | JsImportAssertion, JsImportAssertionEntryList, JsImportBareClause, JsImportCombinedClause, 6 | JsImportDefaultClause, JsImportNamedClause, JsImportNamespaceClause, JsNamedImportSpecifier, 7 | JsNamedImportSpecifierList, JsNamedImportSpecifiers, JsNamespaceImportSpecifier, 8 | JsShorthandNamedImportSpecifier, JsSyntaxKind, JsSyntaxToken, 9 | }; 10 | use biome_rowan::{AstSeparatedList, SyntaxResult, TriviaPiece}; 11 | 12 | fn make_token_with_l_space(kind: JsSyntaxKind) -> JsSyntaxToken { 13 | if let Some(text) = kind.to_string() { 14 | JsSyntaxToken::new_detached(kind, &format!(" {text}"), [TriviaPiece::whitespace(1)], []) 15 | } else { 16 | panic!("token kind {kind:?} cannot be transformed to text") 17 | } 18 | } 19 | 20 | fn make_token_with_r_space(kind: JsSyntaxKind) -> JsSyntaxToken { 21 | if let Some(text) = kind.to_string() { 22 | JsSyntaxToken::new_detached(kind, &format!("{text} "), [], [TriviaPiece::whitespace(1)]) 23 | } else { 24 | panic!("token kind {kind:?} cannot be transformed to text") 25 | } 26 | } 27 | 28 | pub trait Remake 29 | where 30 | Self: Sized, 31 | { 32 | fn remake(&self) -> SyntaxResult; 33 | } 34 | 35 | impl Remake for AnyJsBinding { 36 | fn remake(&self) -> SyntaxResult { 37 | Ok(match self { 38 | AnyJsBinding::JsBogusBinding(_) => todo!(), 39 | AnyJsBinding::JsIdentifierBinding(binding) => { 40 | make::js_identifier_binding(make::ident(binding.name_token()?.text_trimmed())) 41 | .into() 42 | } 43 | AnyJsBinding::JsMetavariable(binding) => { 44 | make::js_metavariable(make::ident(binding.value_token()?.text_trimmed())).into() 45 | } 46 | }) 47 | } 48 | } 49 | 50 | impl Remake for AnyJsModuleSource { 51 | fn remake(&self) -> SyntaxResult { 52 | Ok(match self { 53 | AnyJsModuleSource::JsMetavariable(source) => { 54 | make::js_metavariable(make::ident(source.value_token()?.text_trimmed())).into() 55 | } 56 | AnyJsModuleSource::JsModuleSource(source) => { 57 | make::js_module_source(make::ident(source.value_token()?.text_trimmed())).into() 58 | } 59 | }) 60 | } 61 | } 62 | 63 | impl Remake for AnyJsImportAssertionEntry { 64 | fn remake(&self) -> SyntaxResult { 65 | match self { 66 | Self::JsBogusImportAssertionEntry(_) => todo!(), 67 | Self::JsImportAssertionEntry(entry) => Ok(make::js_import_assertion_entry( 68 | make::ident(entry.key()?.text_trimmed()), 69 | make_token_with_r_space(JsSyntaxKind::COLON), 70 | make::ident(entry.value_token()?.text_trimmed()), 71 | ) 72 | .into()), 73 | } 74 | } 75 | } 76 | 77 | impl Remake for JsImportAssertionEntryList { 78 | fn remake(&self) -> SyntaxResult { 79 | Ok(make::js_import_assertion_entry_list( 80 | self.iter() 81 | .map(|entry| Ok(entry?.remake()?)) 82 | .collect::, _>>()?, 83 | self.separators() 84 | .map(|_| make_token_with_r_space(JsSyntaxKind::COMMA)) 85 | .collect::>(), 86 | )) 87 | } 88 | } 89 | 90 | impl Remake for JsImportAssertion { 91 | fn remake(&self) -> SyntaxResult { 92 | Ok(make::js_import_assertion( 93 | make::token(self.assertion_kind()?.kind()), 94 | make::token_decorated_with_space(JsSyntaxKind::L_CURLY), 95 | self.assertions().remake()?, 96 | make::token_decorated_with_space(JsSyntaxKind::R_CURLY), 97 | )) 98 | } 99 | } 100 | 101 | impl Remake for JsImportBareClause { 102 | fn remake(&self) -> SyntaxResult { 103 | let mut builder = make::js_import_bare_clause(self.source()?.remake()?); 104 | 105 | if let Some(assertion) = self.assertion() { 106 | builder = builder.with_assertion(assertion.remake()?); 107 | } 108 | 109 | Ok(builder.build()) 110 | } 111 | } 112 | 113 | impl Remake for AnyJsCombinedSpecifier { 114 | fn remake(&self) -> SyntaxResult { 115 | Ok(match self { 116 | Self::JsNamedImportSpecifiers(specifiers) => specifiers.remake()?.into(), 117 | Self::JsNamespaceImportSpecifier(specifier) => specifier.remake()?.into(), 118 | }) 119 | } 120 | } 121 | 122 | impl Remake for JsImportCombinedClause { 123 | fn remake(&self) -> SyntaxResult { 124 | let mut builder = make::js_import_combined_clause( 125 | self.default_specifier()?.remake()?, 126 | make_token_with_r_space(JsSyntaxKind::COMMA), 127 | self.specifier()?.remake()?, 128 | make::token_decorated_with_space(JsSyntaxKind::FROM_KW), 129 | self.source()?.remake()?, 130 | ); 131 | 132 | if let Some(assertion) = self.assertion() { 133 | builder = builder.with_assertion(assertion.remake()?) 134 | } 135 | 136 | Ok(builder.build()) 137 | } 138 | } 139 | 140 | impl Remake for JsDefaultImportSpecifier { 141 | fn remake(&self) -> SyntaxResult { 142 | Ok(make::js_default_import_specifier( 143 | self.local_name()?.remake()?, 144 | )) 145 | } 146 | } 147 | 148 | impl Remake for JsImportDefaultClause { 149 | fn remake(&self) -> SyntaxResult { 150 | let mut builder = make::js_import_default_clause( 151 | self.default_specifier()?.remake()?, 152 | make::token_decorated_with_space(JsSyntaxKind::FROM_KW), 153 | self.source()?.remake()?, 154 | ); 155 | 156 | if self.type_token().is_some() { 157 | builder = builder.with_type_token(make_token_with_r_space(JsSyntaxKind::TYPE_KW)) 158 | } 159 | 160 | if let Some(assertion) = self.assertion() { 161 | builder = builder.with_assertion(assertion.remake()?); 162 | } 163 | 164 | Ok(builder.build()) 165 | } 166 | } 167 | 168 | impl Remake for JsNamedImportSpecifier { 169 | fn remake(&self) -> SyntaxResult { 170 | let mut builder = make::js_named_import_specifier( 171 | make::js_literal_export_name(make::ident(self.name()?.value()?.text_trimmed())), 172 | make::token_decorated_with_space(JsSyntaxKind::AS_KW), 173 | self.local_name()?.remake()?, 174 | ); 175 | 176 | if self.type_token().is_some() { 177 | builder = builder.with_type_token(make_token_with_r_space(JsSyntaxKind::TYPE_KW)); 178 | } 179 | 180 | Ok(builder.build()) 181 | } 182 | } 183 | 184 | impl Remake for JsShorthandNamedImportSpecifier { 185 | fn remake(&self) -> SyntaxResult { 186 | let mut builder = make::js_shorthand_named_import_specifier(self.local_name()?.remake()?); 187 | 188 | if self.type_token().is_some() { 189 | builder = builder.with_type_token(make_token_with_r_space(JsSyntaxKind::TYPE_KW)); 190 | } 191 | 192 | Ok(builder.build()) 193 | } 194 | } 195 | 196 | impl Remake for AnyJsNamedImportSpecifier { 197 | fn remake(&self) -> SyntaxResult { 198 | match self { 199 | Self::JsBogusNamedImportSpecifier(_) => todo!(), 200 | Self::JsNamedImportSpecifier(specifier) => Ok(specifier.remake()?.into()), 201 | Self::JsShorthandNamedImportSpecifier(specifier) => Ok(specifier.remake()?.into()), 202 | } 203 | } 204 | } 205 | 206 | impl Remake for JsNamedImportSpecifierList { 207 | fn remake(&self) -> SyntaxResult { 208 | Ok(make::js_named_import_specifier_list( 209 | { 210 | let mut items = self 211 | .iter() 212 | .map(|specifier| specifier?.remake()) 213 | .collect::, _>>()?; 214 | 215 | items.sort_by_key(|item| item.imported_name().unwrap().text_trimmed().to_string()); 216 | items 217 | }, 218 | self.separators() 219 | .map(|_| make_token_with_r_space(JsSyntaxKind::COMMA)) 220 | .collect::>(), 221 | )) 222 | } 223 | } 224 | 225 | impl Remake for JsNamedImportSpecifiers { 226 | fn remake(&self) -> SyntaxResult { 227 | Ok(make::js_named_import_specifiers( 228 | make_token_with_r_space(JsSyntaxKind::L_CURLY), 229 | self.specifiers().remake()?, 230 | make_token_with_l_space(JsSyntaxKind::R_CURLY), 231 | )) 232 | } 233 | } 234 | 235 | impl Remake for JsImportNamedClause { 236 | fn remake(&self) -> SyntaxResult { 237 | let mut builder = make::js_import_named_clause( 238 | self.named_specifiers()?.remake()?, 239 | make::token_decorated_with_space(JsSyntaxKind::FROM_KW), 240 | self.source()?.remake()?, 241 | ); 242 | 243 | if self.type_token().is_some() { 244 | builder = builder.with_type_token(make_token_with_r_space(JsSyntaxKind::TYPE_KW)); 245 | } 246 | 247 | Ok(builder.build()) 248 | } 249 | } 250 | 251 | impl Remake for JsNamespaceImportSpecifier { 252 | fn remake(&self) -> SyntaxResult { 253 | Ok(make::js_namespace_import_specifier( 254 | make::token(JsSyntaxKind::STAR), 255 | make::token_decorated_with_space(JsSyntaxKind::AS_KW), 256 | self.local_name()?.remake()?, 257 | )) 258 | } 259 | } 260 | 261 | impl Remake for JsImportNamespaceClause { 262 | fn remake(&self) -> SyntaxResult { 263 | let mut builder = make::js_import_namespace_clause( 264 | self.namespace_specifier()?.remake()?, 265 | make::token_decorated_with_space(JsSyntaxKind::FROM_KW), 266 | self.source()?.remake()?, 267 | ); 268 | 269 | if self.type_token().is_some() { 270 | builder = builder.with_type_token(make_token_with_r_space(JsSyntaxKind::TYPE_KW)); 271 | } 272 | 273 | if let Some(assertion) = self.assertion() { 274 | builder = builder.with_assertion(assertion.remake()?); 275 | } 276 | 277 | Ok(builder.build()) 278 | } 279 | } 280 | 281 | impl Remake for JsImport { 282 | fn remake(&self) -> SyntaxResult { 283 | let clause = match self.import_clause()? { 284 | AnyJsImportClause::JsImportBareClause(clause) => clause.remake()?.into(), 285 | AnyJsImportClause::JsImportCombinedClause(clause) => clause.remake()?.into(), 286 | AnyJsImportClause::JsImportDefaultClause(clause) => clause.remake()?.into(), 287 | AnyJsImportClause::JsImportNamedClause(clause) => clause.remake()?.into(), 288 | AnyJsImportClause::JsImportNamespaceClause(clause) => clause.remake()?.into(), 289 | }; 290 | 291 | let mut builder = make::js_import(make_token_with_r_space(JsSyntaxKind::IMPORT_KW), clause); 292 | 293 | if self.semicolon_token().is_some() { 294 | builder = builder.with_semicolon_token(make::token(JsSyntaxKind::SEMICOLON)); 295 | } 296 | 297 | Ok(builder.build()) 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "anstream" 22 | version = "0.6.17" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" 25 | dependencies = [ 26 | "anstyle", 27 | "anstyle-parse", 28 | "anstyle-query", 29 | "anstyle-wincon", 30 | "colorchoice", 31 | "is_terminal_polyfill", 32 | "utf8parse", 33 | ] 34 | 35 | [[package]] 36 | name = "anstyle" 37 | version = "1.0.9" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" 40 | 41 | [[package]] 42 | name = "anstyle-parse" 43 | version = "0.2.6" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 46 | dependencies = [ 47 | "utf8parse", 48 | ] 49 | 50 | [[package]] 51 | name = "anstyle-query" 52 | version = "1.1.2" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 55 | dependencies = [ 56 | "windows-sys 0.59.0", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle-wincon" 61 | version = "3.0.6" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" 64 | dependencies = [ 65 | "anstyle", 66 | "windows-sys 0.59.0", 67 | ] 68 | 69 | [[package]] 70 | name = "anyhow" 71 | version = "1.0.91" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" 74 | 75 | [[package]] 76 | name = "autocfg" 77 | version = "1.4.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 80 | 81 | [[package]] 82 | name = "backtrace" 83 | version = "0.3.74" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 86 | dependencies = [ 87 | "addr2line", 88 | "cfg-if", 89 | "libc", 90 | "miniz_oxide", 91 | "object", 92 | "rustc-demangle", 93 | "windows-targets", 94 | ] 95 | 96 | [[package]] 97 | name = "biome_console" 98 | version = "0.5.7" 99 | dependencies = [ 100 | "biome_markup", 101 | "biome_text_size", 102 | "schemars", 103 | "serde", 104 | "termcolor", 105 | "unicode-segmentation", 106 | "unicode-width", 107 | ] 108 | 109 | [[package]] 110 | name = "biome_diagnostics" 111 | version = "0.5.7" 112 | dependencies = [ 113 | "backtrace", 114 | "biome_console", 115 | "biome_diagnostics_categories", 116 | "biome_diagnostics_macros", 117 | "biome_rowan", 118 | "biome_text_edit", 119 | "biome_text_size", 120 | "bpaf", 121 | "enumflags2", 122 | "oxc_resolver", 123 | "serde", 124 | "serde_ini", 125 | "serde_json", 126 | "termcolor", 127 | "unicode-width", 128 | ] 129 | 130 | [[package]] 131 | name = "biome_diagnostics_categories" 132 | version = "0.5.7" 133 | dependencies = [ 134 | "quote", 135 | "serde", 136 | ] 137 | 138 | [[package]] 139 | name = "biome_diagnostics_macros" 140 | version = "0.5.7" 141 | dependencies = [ 142 | "proc-macro-error", 143 | "proc-macro2", 144 | "quote", 145 | "syn 1.0.109", 146 | ] 147 | 148 | [[package]] 149 | name = "biome_js_factory" 150 | version = "0.5.7" 151 | dependencies = [ 152 | "biome_js_syntax", 153 | "biome_rowan", 154 | ] 155 | 156 | [[package]] 157 | name = "biome_js_parser" 158 | version = "0.5.7" 159 | dependencies = [ 160 | "biome_console", 161 | "biome_diagnostics", 162 | "biome_js_factory", 163 | "biome_js_syntax", 164 | "biome_parser", 165 | "biome_rowan", 166 | "biome_unicode_table", 167 | "drop_bomb", 168 | "enumflags2", 169 | "indexmap", 170 | "rustc-hash 1.1.0", 171 | "serde", 172 | "serde_json", 173 | "smallvec", 174 | "tracing", 175 | ] 176 | 177 | [[package]] 178 | name = "biome_js_syntax" 179 | version = "0.5.7" 180 | dependencies = [ 181 | "biome_rowan", 182 | "biome_string_case", 183 | "enumflags2", 184 | "serde", 185 | ] 186 | 187 | [[package]] 188 | name = "biome_markup" 189 | version = "0.5.7" 190 | dependencies = [ 191 | "proc-macro-error", 192 | "proc-macro2", 193 | "quote", 194 | ] 195 | 196 | [[package]] 197 | name = "biome_parser" 198 | version = "0.5.7" 199 | dependencies = [ 200 | "biome_console", 201 | "biome_diagnostics", 202 | "biome_rowan", 203 | "biome_unicode_table", 204 | "drop_bomb", 205 | "enumflags2", 206 | "unicode-bom", 207 | ] 208 | 209 | [[package]] 210 | name = "biome_rowan" 211 | version = "0.5.7" 212 | dependencies = [ 213 | "biome_text_edit", 214 | "biome_text_size", 215 | "countme", 216 | "hashbrown 0.14.5", 217 | "rustc-hash 1.1.0", 218 | "serde", 219 | "tracing", 220 | ] 221 | 222 | [[package]] 223 | name = "biome_string_case" 224 | version = "0.5.7" 225 | 226 | [[package]] 227 | name = "biome_text_edit" 228 | version = "0.5.7" 229 | dependencies = [ 230 | "biome_text_size", 231 | "serde", 232 | "similar", 233 | ] 234 | 235 | [[package]] 236 | name = "biome_text_size" 237 | version = "0.5.7" 238 | dependencies = [ 239 | "schemars", 240 | "serde", 241 | ] 242 | 243 | [[package]] 244 | name = "biome_unicode_table" 245 | version = "0.5.7" 246 | 247 | [[package]] 248 | name = "bitflags" 249 | version = "2.6.0" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 252 | 253 | [[package]] 254 | name = "bpaf" 255 | version = "0.9.15" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "50fd5174866dc2fa2ddc96e8fb800852d37f064f32a45c7b7c2f8fa2c64c77fa" 258 | dependencies = [ 259 | "bpaf_derive", 260 | ] 261 | 262 | [[package]] 263 | name = "bpaf_derive" 264 | version = "0.5.13" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "cf95d9c7e6aba67f8fc07761091e93254677f4db9e27197adecebc7039a58722" 267 | dependencies = [ 268 | "proc-macro2", 269 | "quote", 270 | "syn 2.0.85", 271 | ] 272 | 273 | [[package]] 274 | name = "bstr" 275 | version = "1.10.0" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" 278 | dependencies = [ 279 | "memchr", 280 | "regex-automata", 281 | "serde", 282 | ] 283 | 284 | [[package]] 285 | name = "cfg-if" 286 | version = "1.0.0" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 289 | 290 | [[package]] 291 | name = "clap" 292 | version = "4.5.20" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" 295 | dependencies = [ 296 | "clap_builder", 297 | "clap_derive", 298 | ] 299 | 300 | [[package]] 301 | name = "clap_builder" 302 | version = "4.5.20" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" 305 | dependencies = [ 306 | "anstream", 307 | "anstyle", 308 | "clap_lex", 309 | "strsim", 310 | ] 311 | 312 | [[package]] 313 | name = "clap_derive" 314 | version = "4.5.18" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" 317 | dependencies = [ 318 | "heck", 319 | "proc-macro2", 320 | "quote", 321 | "syn 2.0.85", 322 | ] 323 | 324 | [[package]] 325 | name = "clap_lex" 326 | version = "0.7.2" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" 329 | 330 | [[package]] 331 | name = "colorchoice" 332 | version = "1.0.3" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 335 | 336 | [[package]] 337 | name = "console" 338 | version = "0.15.8" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" 341 | dependencies = [ 342 | "encode_unicode", 343 | "lazy_static", 344 | "libc", 345 | "windows-sys 0.52.0", 346 | ] 347 | 348 | [[package]] 349 | name = "countme" 350 | version = "3.0.1" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" 353 | 354 | [[package]] 355 | name = "crossbeam-utils" 356 | version = "0.8.20" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 359 | 360 | [[package]] 361 | name = "dashmap" 362 | version = "6.1.0" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" 365 | dependencies = [ 366 | "cfg-if", 367 | "crossbeam-utils", 368 | "hashbrown 0.14.5", 369 | "lock_api", 370 | "once_cell", 371 | "parking_lot_core", 372 | ] 373 | 374 | [[package]] 375 | name = "drop_bomb" 376 | version = "0.1.5" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" 379 | 380 | [[package]] 381 | name = "dunce" 382 | version = "1.0.5" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" 385 | 386 | [[package]] 387 | name = "dyn-clone" 388 | version = "1.0.17" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" 391 | 392 | [[package]] 393 | name = "either" 394 | version = "1.13.0" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 397 | 398 | [[package]] 399 | name = "encode_unicode" 400 | version = "0.3.6" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 403 | 404 | [[package]] 405 | name = "enumflags2" 406 | version = "0.7.10" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" 409 | dependencies = [ 410 | "enumflags2_derive", 411 | ] 412 | 413 | [[package]] 414 | name = "enumflags2_derive" 415 | version = "0.7.10" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" 418 | dependencies = [ 419 | "proc-macro2", 420 | "quote", 421 | "syn 2.0.85", 422 | ] 423 | 424 | [[package]] 425 | name = "equivalent" 426 | version = "1.0.1" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 429 | 430 | [[package]] 431 | name = "gimli" 432 | version = "0.31.1" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 435 | 436 | [[package]] 437 | name = "glob" 438 | version = "0.3.1" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 441 | 442 | [[package]] 443 | name = "hashbrown" 444 | version = "0.14.5" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 447 | 448 | [[package]] 449 | name = "hashbrown" 450 | version = "0.15.0" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" 453 | 454 | [[package]] 455 | name = "heck" 456 | version = "0.5.0" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 459 | 460 | [[package]] 461 | name = "indexmap" 462 | version = "2.6.0" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 465 | dependencies = [ 466 | "equivalent", 467 | "hashbrown 0.15.0", 468 | "serde", 469 | ] 470 | 471 | [[package]] 472 | name = "insta" 473 | version = "1.40.0" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "6593a41c7a73841868772495db7dc1e8ecab43bb5c0b6da2059246c4b506ab60" 476 | dependencies = [ 477 | "console", 478 | "lazy_static", 479 | "linked-hash-map", 480 | "similar", 481 | ] 482 | 483 | [[package]] 484 | name = "is_terminal_polyfill" 485 | version = "1.70.1" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 488 | 489 | [[package]] 490 | name = "itertools" 491 | version = "0.13.0" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 494 | dependencies = [ 495 | "either", 496 | ] 497 | 498 | [[package]] 499 | name = "itoa" 500 | version = "1.0.11" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 503 | 504 | [[package]] 505 | name = "json-strip-comments" 506 | version = "1.0.4" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "b271732a960335e715b6b2ae66a086f115c74eb97360e996d2bd809bfc063bba" 509 | dependencies = [ 510 | "memchr", 511 | ] 512 | 513 | [[package]] 514 | name = "lazy_static" 515 | version = "1.5.0" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 518 | 519 | [[package]] 520 | name = "libc" 521 | version = "0.2.161" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" 524 | 525 | [[package]] 526 | name = "linked-hash-map" 527 | version = "0.5.6" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 530 | 531 | [[package]] 532 | name = "lock_api" 533 | version = "0.4.12" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 536 | dependencies = [ 537 | "autocfg", 538 | "scopeguard", 539 | ] 540 | 541 | [[package]] 542 | name = "memchr" 543 | version = "2.7.4" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 546 | 547 | [[package]] 548 | name = "miniz_oxide" 549 | version = "0.8.0" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 552 | dependencies = [ 553 | "adler2", 554 | ] 555 | 556 | [[package]] 557 | name = "object" 558 | version = "0.36.5" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 561 | dependencies = [ 562 | "memchr", 563 | ] 564 | 565 | [[package]] 566 | name = "once_cell" 567 | version = "1.20.2" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 570 | 571 | [[package]] 572 | name = "oxc_resolver" 573 | version = "1.12.0" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "6c20bb345f290c46058ba650fef7ca2b579612cf2786b927ebad7b8bec0845a7" 576 | dependencies = [ 577 | "cfg-if", 578 | "dashmap", 579 | "dunce", 580 | "indexmap", 581 | "json-strip-comments", 582 | "once_cell", 583 | "rustc-hash 2.0.0", 584 | "serde", 585 | "serde_json", 586 | "simdutf8", 587 | "thiserror", 588 | "tracing", 589 | ] 590 | 591 | [[package]] 592 | name = "parking_lot_core" 593 | version = "0.9.10" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 596 | dependencies = [ 597 | "cfg-if", 598 | "libc", 599 | "redox_syscall", 600 | "smallvec", 601 | "windows-targets", 602 | ] 603 | 604 | [[package]] 605 | name = "pin-project-lite" 606 | version = "0.2.15" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 609 | 610 | [[package]] 611 | name = "proc-macro-error" 612 | version = "1.0.4" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 615 | dependencies = [ 616 | "proc-macro-error-attr", 617 | "proc-macro2", 618 | "quote", 619 | "version_check", 620 | ] 621 | 622 | [[package]] 623 | name = "proc-macro-error-attr" 624 | version = "1.0.4" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 627 | dependencies = [ 628 | "proc-macro2", 629 | "quote", 630 | "version_check", 631 | ] 632 | 633 | [[package]] 634 | name = "proc-macro2" 635 | version = "1.0.89" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" 638 | dependencies = [ 639 | "unicode-ident", 640 | ] 641 | 642 | [[package]] 643 | name = "quote" 644 | version = "1.0.37" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 647 | dependencies = [ 648 | "proc-macro2", 649 | ] 650 | 651 | [[package]] 652 | name = "redox_syscall" 653 | version = "0.5.7" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" 656 | dependencies = [ 657 | "bitflags", 658 | ] 659 | 660 | [[package]] 661 | name = "regex-automata" 662 | version = "0.4.8" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" 665 | 666 | [[package]] 667 | name = "result" 668 | version = "1.0.0" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560" 671 | 672 | [[package]] 673 | name = "rustc-demangle" 674 | version = "0.1.24" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 677 | 678 | [[package]] 679 | name = "rustc-hash" 680 | version = "1.1.0" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 683 | 684 | [[package]] 685 | name = "rustc-hash" 686 | version = "2.0.0" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" 689 | 690 | [[package]] 691 | name = "ryu" 692 | version = "1.0.18" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 695 | 696 | [[package]] 697 | name = "same-file" 698 | version = "1.0.6" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 701 | dependencies = [ 702 | "winapi-util", 703 | ] 704 | 705 | [[package]] 706 | name = "schemars" 707 | version = "0.8.21" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" 710 | dependencies = [ 711 | "dyn-clone", 712 | "indexmap", 713 | "schemars_derive", 714 | "serde", 715 | "serde_json", 716 | "smallvec", 717 | ] 718 | 719 | [[package]] 720 | name = "schemars_derive" 721 | version = "0.8.21" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" 724 | dependencies = [ 725 | "proc-macro2", 726 | "quote", 727 | "serde_derive_internals", 728 | "syn 2.0.85", 729 | ] 730 | 731 | [[package]] 732 | name = "scopeguard" 733 | version = "1.2.0" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 736 | 737 | [[package]] 738 | name = "serde" 739 | version = "1.0.213" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" 742 | dependencies = [ 743 | "serde_derive", 744 | ] 745 | 746 | [[package]] 747 | name = "serde_derive" 748 | version = "1.0.213" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" 751 | dependencies = [ 752 | "proc-macro2", 753 | "quote", 754 | "syn 2.0.85", 755 | ] 756 | 757 | [[package]] 758 | name = "serde_derive_internals" 759 | version = "0.29.1" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" 762 | dependencies = [ 763 | "proc-macro2", 764 | "quote", 765 | "syn 2.0.85", 766 | ] 767 | 768 | [[package]] 769 | name = "serde_ini" 770 | version = "0.2.0" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "eb236687e2bb073a7521c021949be944641e671b8505a94069ca37b656c81139" 773 | dependencies = [ 774 | "result", 775 | "serde", 776 | "void", 777 | ] 778 | 779 | [[package]] 780 | name = "serde_json" 781 | version = "1.0.132" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" 784 | dependencies = [ 785 | "indexmap", 786 | "itoa", 787 | "memchr", 788 | "ryu", 789 | "serde", 790 | ] 791 | 792 | [[package]] 793 | name = "simdutf8" 794 | version = "0.1.5" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" 797 | 798 | [[package]] 799 | name = "similar" 800 | version = "2.6.0" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" 803 | dependencies = [ 804 | "bstr", 805 | "unicode-segmentation", 806 | ] 807 | 808 | [[package]] 809 | name = "smallvec" 810 | version = "1.13.2" 811 | source = "registry+https://github.com/rust-lang/crates.io-index" 812 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 813 | dependencies = [ 814 | "serde", 815 | ] 816 | 817 | [[package]] 818 | name = "strsim" 819 | version = "0.11.1" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 822 | 823 | [[package]] 824 | name = "syn" 825 | version = "1.0.109" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 828 | dependencies = [ 829 | "proc-macro2", 830 | "quote", 831 | "unicode-ident", 832 | ] 833 | 834 | [[package]] 835 | name = "syn" 836 | version = "2.0.85" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" 839 | dependencies = [ 840 | "proc-macro2", 841 | "quote", 842 | "unicode-ident", 843 | ] 844 | 845 | [[package]] 846 | name = "termcolor" 847 | version = "1.4.1" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 850 | dependencies = [ 851 | "winapi-util", 852 | ] 853 | 854 | [[package]] 855 | name = "thiserror" 856 | version = "1.0.65" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" 859 | dependencies = [ 860 | "thiserror-impl", 861 | ] 862 | 863 | [[package]] 864 | name = "thiserror-impl" 865 | version = "1.0.65" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" 868 | dependencies = [ 869 | "proc-macro2", 870 | "quote", 871 | "syn 2.0.85", 872 | ] 873 | 874 | [[package]] 875 | name = "tracing" 876 | version = "0.1.40" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 879 | dependencies = [ 880 | "pin-project-lite", 881 | "tracing-attributes", 882 | "tracing-core", 883 | ] 884 | 885 | [[package]] 886 | name = "tracing-attributes" 887 | version = "0.1.27" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 890 | dependencies = [ 891 | "proc-macro2", 892 | "quote", 893 | "syn 2.0.85", 894 | ] 895 | 896 | [[package]] 897 | name = "tracing-core" 898 | version = "0.1.32" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 901 | dependencies = [ 902 | "once_cell", 903 | ] 904 | 905 | [[package]] 906 | name = "tsimports" 907 | version = "0.1.4" 908 | dependencies = [ 909 | "anyhow", 910 | "biome_console", 911 | "biome_diagnostics", 912 | "biome_js_factory", 913 | "biome_js_parser", 914 | "biome_js_syntax", 915 | "biome_parser", 916 | "biome_rowan", 917 | "clap", 918 | "glob", 919 | "insta", 920 | "itertools", 921 | "thiserror", 922 | "walkdir", 923 | ] 924 | 925 | [[package]] 926 | name = "unicode-bom" 927 | version = "2.0.3" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" 930 | 931 | [[package]] 932 | name = "unicode-ident" 933 | version = "1.0.13" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 936 | 937 | [[package]] 938 | name = "unicode-segmentation" 939 | version = "1.12.0" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 942 | 943 | [[package]] 944 | name = "unicode-width" 945 | version = "0.1.14" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 948 | 949 | [[package]] 950 | name = "utf8parse" 951 | version = "0.2.2" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 954 | 955 | [[package]] 956 | name = "version_check" 957 | version = "0.9.5" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 960 | 961 | [[package]] 962 | name = "void" 963 | version = "1.0.2" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 966 | 967 | [[package]] 968 | name = "walkdir" 969 | version = "2.5.0" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 972 | dependencies = [ 973 | "same-file", 974 | "winapi-util", 975 | ] 976 | 977 | [[package]] 978 | name = "winapi-util" 979 | version = "0.1.9" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 982 | dependencies = [ 983 | "windows-sys 0.59.0", 984 | ] 985 | 986 | [[package]] 987 | name = "windows-sys" 988 | version = "0.52.0" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 991 | dependencies = [ 992 | "windows-targets", 993 | ] 994 | 995 | [[package]] 996 | name = "windows-sys" 997 | version = "0.59.0" 998 | source = "registry+https://github.com/rust-lang/crates.io-index" 999 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1000 | dependencies = [ 1001 | "windows-targets", 1002 | ] 1003 | 1004 | [[package]] 1005 | name = "windows-targets" 1006 | version = "0.52.6" 1007 | source = "registry+https://github.com/rust-lang/crates.io-index" 1008 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1009 | dependencies = [ 1010 | "windows_aarch64_gnullvm", 1011 | "windows_aarch64_msvc", 1012 | "windows_i686_gnu", 1013 | "windows_i686_gnullvm", 1014 | "windows_i686_msvc", 1015 | "windows_x86_64_gnu", 1016 | "windows_x86_64_gnullvm", 1017 | "windows_x86_64_msvc", 1018 | ] 1019 | 1020 | [[package]] 1021 | name = "windows_aarch64_gnullvm" 1022 | version = "0.52.6" 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" 1024 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1025 | 1026 | [[package]] 1027 | name = "windows_aarch64_msvc" 1028 | version = "0.52.6" 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" 1030 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1031 | 1032 | [[package]] 1033 | name = "windows_i686_gnu" 1034 | version = "0.52.6" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1037 | 1038 | [[package]] 1039 | name = "windows_i686_gnullvm" 1040 | version = "0.52.6" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1043 | 1044 | [[package]] 1045 | name = "windows_i686_msvc" 1046 | version = "0.52.6" 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" 1048 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1049 | 1050 | [[package]] 1051 | name = "windows_x86_64_gnu" 1052 | version = "0.52.6" 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" 1054 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1055 | 1056 | [[package]] 1057 | name = "windows_x86_64_gnullvm" 1058 | version = "0.52.6" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1061 | 1062 | [[package]] 1063 | name = "windows_x86_64_msvc" 1064 | version = "0.52.6" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1067 | --------------------------------------------------------------------------------