Skip to content

【Zig 日报】项目分享:Zsort 类似于 goimport 的导入整理工具 #356

Description

@jiacai2050

zsort 是一个针对 Zig 语言的强主张(opinionated)导入(import)整理工具。它会对 @import 声明进行排序、分组和提升,类似于 Python 的 isort 或 Go 的 goimports

安装

注意:在 Linux 或 macOS 上需要 Zig 0.15.2 或更新版本(包含 0.16)。
在 Windows 上,请使用 WSL2。

Homebrew

brew tap mstdokumaci/zsort
brew install mstdokumaci/zsort/zsort

预编译二进制文件

GitHub Releases 下载,解压,并将其添加到你的 PATH 环境变量中。

Zig 包(构建依赖)

添加到 build.zig.zon

.zsort = .{
    .url = "https://github.com/mstdokumaci/zsort/archive/refs/tags/v0.6.0.tar.gz",
    // .hash
    .lazy = true,
},

build.zig 中配置构建步骤:

const zsort = b.lazyDependency("zsort", .{
    .target = b.graph.host,
    .optimize = .ReleaseFast,
});
if (zsort) |dep| {
    const zsort_exe = dep.artifact("zsort");

    const check_imports = b.addRunArtifact(zsort_exe);
    check_imports.setCwd(b.path("."));
    check_imports.addArgs(&.{ "check", "src", "--ban-prefix", "./", "--ban-prefix", "src/" });
    b.step("check-imports", "Run zsort check on this project").dependOn(&check_imports.step);

    const run_fix = b.addRunArtifact(zsort_exe);
    run_fix.setCwd(b.path("."));
    run_fix.addArgs(&.{ "fix", "src", "--ban-prefix", "./", "--ban-prefix", "src/" });
    b.step("fix-imports", "Fix Zig import ordering in this project").dependOn(&run_fix.step);
}

可参考 test/consumer/ 目录下的完整工作示例。

从源码构建

zig build -Doptimize=ReleaseFast    # → zig-out/bin/zsort

用法

Usage: zsort [check|fix] <dir|file>... [options]

模式:
  check              验证导入顺序(如果需要更改则退出状态码为 1)
  fix                原地重写文件

选项:
  --ban-prefix <p>   拒绝以 <p> 开头的导入(可重复使用)
  -h, --help         显示帮助信息
  --version          打印版本
zsort check src/                                  # 验证某个目录
zsort fix .                                       # 修复所有文件
zsort check src/ build.zig                        # 混合目标
zsort check . --ban-prefix ./ --ban-prefix src/   # 禁止相对路径

check 模式会为需要更改的文件打印统一格式的差异对比(unified diff)。

在文件的任意位置加上 // zsort: skip 可以使其免于被处理。

目录会被递归扫描。.gitignore 中的条目、.git.zig-cachezig-cachezig-out 会被自动跳过。

排序规则

zsort 将导入分为四个区间(band),由空行隔开:

  1. std / builtinstdbuiltin 模块。
  2. 第三方(Third-party) — 其他模块名(httpzsqlite 等),包括 @cImport
  3. 本地(Local) — 包含 / 或以 .zig 结尾的路径,加上 Zig 的包级模块根目录(包自身的根源文件)和 build_root(构建运行器的根模块)。
  4. 别名(Aliases) — 形如 const X = module.Member; 的语句(其中 module 解析为上面的某个导入);const X = @This(); 在此区间中排序最前。

在每个区间内部,普通导入排在成员导入(member imports)之前,然后两者均按路径(按字节)排序。如果两个导入共享相同的路径,则整行代码将用于打破平局(例如:const Foo = @import("x.zig").Foo; 排在 const bar = @import("x.zig").bar; 之前)。无论输入顺序如何,输出都是确定性的。

zsort fix 运行前:

const std = @import("std");
const Config = auth.Config;
const Router = @import("router.zig").Router;
const httpz = @import("httpz");
// Handles request authentication.
const auth = @import("auth.zig");

运行后:

const std = @import("std");

const httpz = @import("httpz");

// Handles request authentication.
const auth = @import("auth.zig");
const Router = @import("router.zig").Router;

const Config = auth.Config;

fix 的作用

  • 对文件顶部的导入进行排序,并将其归入上述区间。
  • 将文件深处游离的导入和别名提升(hoist)到它们正确的区间中。
  • 保持前置注释紧跟其对应的导入。
  • 确保导入块与后续代码之间有一个空行。
  • 保留 //! 文档注释和原始的行尾符(LF / CRLF)。

Pre-commit 钩子

添加到 .pre-commit-config.yaml

repos:
  - repo: https://github.com/mstdokumaci/zsort
    rev: v0.6.0
    hooks:
      - id: zsort        # 检查模式(未排序则失败)
      # - id: zsort-fix  # 修复模式(原地重写)

要求 zsort 存在于 $PATH 中(language: system)。可以通过 args 传递额外参数,例如 args: [--ban-prefix, 'src/']。只会检查 .zig 文件。

另请参阅

  • CONTRIBUTING.md — 开发环境搭建与代码检查门禁
  • CHANGELOG.md — 发布历史

许可证

MIT

加入我们

Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文群体中的使用,有多种方式可以参与进来:

  1. 供稿,分享自己使用 Zig 的心得
  2. 改进 ZigCC 组织下的开源项目
  3. 加入微信群Telegram 群组Google Groups 与更多 Zig 爱好者交流

Metadata

Metadata

Assignees

No one assigned

    Labels

    日报daily report

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions