mooncompat

    A MoonBit-native public API compatibility checker for semver-aware package releases.

    moonbit
    api-compatibility
    semver
    developer-tools
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    15 minutes ago
    Downloads
    2

    #MoonCompat

    CI Release License: Apache-2.0

    MoonCompat is a MoonBit-native public API compatibility guard for semver-aware package releases.

    It reads the .mbti interfaces generated by moon info, compares two versions of one or more MoonBit packages, reports public API changes, recommends a SemVer bump, and can fail CI before a breaking release is published.

    中文简介:MoonCompat 用 MoonBit 实现 MoonBit 包的公开 API 兼容性检查。它比较两个版本的 .mbti 接口,识别破坏性变更,给出 SemVer 建议,并能作为 GitHub Actions 的发布门禁。

    #Why this exists

    MoonBit package management uses Semantic Versioning and minimal version selection. A signature, public field, enum variant, trait implementation, or package identifier change can break downstream users even when the implementation still compiles locally.

    MoonCompat makes that risk explicit and machine-checkable. It is deliberately a source-level API checker: it does not claim ABI compatibility or behavioral equivalence.

    #Quick start

    Prerequisites: the current MoonBit toolchain and Git.

    git clone https://github.com/404-32/byc002.git cd byc002 moon run cmd/main -- --help

    Run the included breaking-change demo:

    moon run cmd/main -- check fixtures/demo/base fixtures/demo/head

    The command prints:

    MoonCompat: fixtures/demo/base -> fixtures/demo/head BREAKING: changed public function `parse` before: pub fn parse(String) -> Forecast after: pub fn parse(String, strict? : Bool) -> Forecast raise ... Summary: 3 breaking, 1 compatible, 2 unchanged Recommended bump: major

    It exits with code 1. Add --format json for a machine-readable report or --output report.json to write to a file.

    #Compare real releases

    MoonBit projects can compare any two exported package trees:

    moon info git worktree add /tmp/mooncompat-base v0.1.0 (cd /tmp/mooncompat-base && moon info) moon run cmd/main -- check /tmp/mooncompat-base . \ --format json \ --output mooncompat-report.json

    Each input may be:

    • one .mbti file;
    • a package directory;
    • or a source tree containing multiple package interfaces.

    Directory scans recurse by default and skip .git, .mooncakes, _build, and target. Dependency caches are therefore not confused with the project's own API.

    #CLI

    mooncompat check <base-path> <head-path> [options] mooncompat snapshot <path> [--output report.json] mooncompat rules mooncompat version

    Options:

    --format text|json Report format (default: text) -o, --output FILE Write the report to FILE --fail-on breaking|never Exit 1 on breaking changes (default: breaking) -q, --quiet Hide before/after signatures in text output

    Exit codes:

    CodeMeaning
    0No breaking changes, or --fail-on never
    1Breaking changes detected
    2Invalid input, unsupported .mbti syntax, parse failure, or I/O error

    #What is checked

    MoonCompat treats these as breaking:

    • removing or renaming a public declaration;
    • changing a function or method signature, including optional parameters, return types, error behavior, async, and generic constraints;
    • changing public struct fields, enum variants, traits, public errors, or type aliases;
    • removing a public trait implementation;
    • changing the package identifier.

    Adding a new public declaration or trait implementation is compatible. Field, variant, trait-member, and declaration order is ignored. Derived traits are normalized into equivalent explicit pub impl entries, so compiler-generated interface formatting does not create false positives. Int/UInt aliases are normalized to Int32/UInt32.

    The complete policy is in docs/compatibility-rules.md.

    #GitHub Actions gate

    name: API compatibility on: [pull_request] jobs: api-compat: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 with: fetch-depth: 0 - name: Set up MoonBit run: | curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash echo "$HOME/.moon/bin" >> "$GITHUB_PATH" - name: Generate interfaces run: | git worktree add /tmp/base "${{ github.event.pull_request.base.sha }}" (cd /tmp/base && moon info) moon info - name: Check public API run: moon run cmd/main -- check /tmp/base . --format json --output api-report.json - uses: actions/upload-artifact@v4 if: always() with: name: mooncompat-report path: api-report.json

    Projects can also download the mooncompat-wasm32-wasi.wasm release asset and run it with moonrun.

    #Design

    .mbti files | v line-aware parser -> normalized declaration IR | v package matcher -> compatibility comparator -> SemVer recommendation | +--> deterministic JSON +--> human-readable text +--> CI exit status

    The parser and comparison engine are in the public MoonBit library package. Filesystem traversal and process exit status live in the CLI package. See docs/architecture.md.

    #Validation

    • 33 library tests pass on wasm, wasm-gc, js, and native where the toolchain supports the target.
    • CLI end-to-end tests cover breaking, compatible, unchanged, JSON, file-output, and parse-error paths.
    • Smoke-tested against real releases of moonbitlang/x (v0.5.6 → v0.5.7) and moonbitlang/async (v0.21.3 → v0.22.7).
    • Unknown public .mbti syntax fails closed instead of being silently omitted.

    See docs/validation.md for reproducible commands and the last observed results.

    #Scope and limitations

    MoonCompat checks source-level public interface compatibility based on moon info. It is conservative: any changed signature is treated as breaking. It does not check ABI, runtime behavior, performance, documentation quality, or protocol compatibility.

    The parser targets the generated .mbti format represented by mbti-v1 and fails explicitly on unsupported public syntax. See docs/limitations.md before adopting it in a release process.

    #Development

    moon check --deny-warn moon test --deny-warn moon fmt

    Run the CLI integration suite:

    bash scripts/test-cli.sh

    Run the real-package regression:

    bash scripts/check-real-packages.sh

    MoonCompat also checks its own public API against the checked-in v0.1.0 baseline:

    bash scripts/check-self-api.sh

    #License

    Apache-2.0. See LICENSE and THIRD_PARTY_NOTICES.md.

    ApiSnapshot

    pub struct ApiSnapshot {
    package_id : String
    declarations : Array[Declaration]
    source : String
    }

    Change

    pub struct Change {
    package_id : String
    name : String
    declaration_kind : String
    kind : ChangeKind
    severity : ChangeSeverity
    before : String
    after : String
    message : String
    }

    ChangeKind

    pub enum ChangeKind {
    PackageRenamed
    Removed
    Added
    DeclarationChanged
    }

    ChangeKind::label

    fn ChangeKind::label(self : ChangeKind) -> String

    ChangeSeverity

    pub enum ChangeSeverity {
    Breaking
    Compatible
    }

    ChangeSeverity::label

    fn ChangeSeverity::label(self : ChangeSeverity) -> String

    CompatibilityReport

    pub struct CompatibilityReport {
    base_package : String
    head_package : String
    changes : Array[Change]
    breaking_count : Int
    compatible_count : Int
    unchanged_count : Int
    }

    CompatibilityReport::has_breaking_changes

    fn CompatibilityReport::has_breaking_changes(self : CompatibilityReport) -> Bool

    CompatibilityReport::recommended_bump

    fn CompatibilityReport::recommended_bump(self : CompatibilityReport) -> VersionBump

    CompatibilityReport::result

    fn CompatibilityReport::result(self : CompatibilityReport) -> String

    Declaration

    pub struct Declaration {
    kind : DeclarationKind
    name : String
    canonical : String
    line : Int
    }

    Declaration::key

    fn Declaration::key(self : Declaration) -> String

    DeclarationKind

    pub enum DeclarationKind {
    Function
    Struct
    Enum
    Type
    Error
    Trait
    Impl
    Value
    Other
    }

    DeclarationKind::label

    fn DeclarationKind::label(self : DeclarationKind) -> String

    VersionBump

    pub enum VersionBump {
    Major
    Minor
    Patch
    }

    VersionBump::label

    fn VersionBump::label(self : VersionBump) -> String

    compare_api_sets

    fn compare_api_sets(base : Array[ApiSnapshot], head : Array[ApiSnapshot], base_label~ : String, head_label~ : String) -> CompatibilityReport

    compare_snapshots

    fn compare_snapshots(base : ApiSnapshot, head : ApiSnapshot) -> CompatibilityReport

    parse_api

    fn parse_api(source : String, source_name? : String) -> ApiSnapshot raise

    parser_version

    fn parser_version() -> String

    render_report_json

    fn render_report_json(report : CompatibilityReport) -> String

    render_report_text

    fn render_report_text(report : CompatibilityReport, verbose? : Bool) -> String

    render_snapshot_json

    fn render_snapshot_json(snapshot : ApiSnapshot) -> String

    report_to_json

    snapshot_to_json

    fn snapshot_to_json(snapshot : ApiSnapshot) ->
    Json