Skip to content
moonbit-refactoring logo

MoonBit Refactoring Skill

moonbit-refactoring

Refactor MoonBit code to be idiomatic: shrink public APIs, convert functions to methods, use pattern matching with views, add loop invariants, and ensure test coverage without regressions.

SKILL.md

Full skill instructions

MoonBit Refactoring Skill

Intent

  • Preserve behavior and public contracts unless explicitly changed.
  • Minimize the public API to what callers require.
  • Prefer declarative style and pattern matching over incidental mutation.
  • Use view types (ArrayView/​StringView/​BytesView) to avoid copies.
  • Add tests and docs alongside refactors.

Workflow

Start broad, then refine locally:

  1. Architecture first: Review package structure, dependencies, and API boundaries.
  2. Inventory public APIs and call sites (moon doc, moon ide find-references).
  3. Pick one refactor theme (API minimization, package splits, pattern matching, loop style).
  4. Apply the smallest safe change.
  5. Update docs/​tests in the same patch.
  6. Run moon check, then moon test.
  7. Use coverage to target missing branches.

Avoid local cleanups (renaming, pattern matching) until the high-level structure is sound.

Improve Package Architecture

  • Keep packages focused: aim for <10k lines per package.
  • Keep files manageable: aim for <2k lines per file.
  • Keep functions focused: aim for <200 lines per function.

Splitting Files

Files in MoonBit are just organizational—move code freely within a package as long as each file stays focused on one concept.

Splitting Packages

When spinning off package A into A and B:

  1. Create the new package and re-export temporarily:

    // In package B
    using @A { ... }  // re-export A's APIs
    

    Ensure moon check passes before proceeding.

  2. Find and update all call sites:

    moon ide find-references <symbol>
    

    Replace bare f with @B.f.

  3. Remove the use statement once all call sites are updated.

  4. Audit and remove newly-unused pub APIs from both packages.

Guidelines

  • Prefer acyclic dependencies: lower-level packages should not import higher-level ones.
  • Only expose what downstream packages actually need.
  • Consider an internal/ package for helpers that shouldn't leak.

Minimize Public API and Modularize

  • Remove pub from helpers; keep only required exports.
  • Move helpers into internal/ packages to block external imports.
  • Split large files by feature; files do not define modules in MoonBit.

Local refactoring

Convert Free Functions to Methods + Chaining

  • Move behavior onto the owning type for discoverability.
  • Use .. for fluent, mutating chains when it reads clearly.

Example:

// Before
fn reader_next(r : Reader) -> Char? { ... }
let ch = reader_next(r)

// After
fn Reader::next(self : Reader) -> Char? { ... }
let ch = r.next()

Example (chaining):

buf..write_string("#\\")..write_char(ch)

Prefer Explicit Qualification

  • Use @pkg.fn instead of using when clarity matters.
  • Keep call sites explicit during wide refactors.

Example:

let n = @parser.parse_number(token)

Simplify Constructors When Type Is Known

  • Drop TypePath::Constr when the surrounding type is known.

Example:

match tree { // the type of tree is known to be Tree
  Leaf(x) => x // no need for Tree::Leaf
  Node(left~, x, right~) => left.sum() + x + right.sum()
}

Pattern Matching and Views

  • Pattern match arrays directly; the compiler inserts ArrayView implicitly.
  • Use .. in the middle to match prefix and suffix at once.
  • Pattern match strings directly; avoid converting to Array[Char].
  • String/StringView indexing yields UInt16 code units. Use for ch in s for Unicode-aware iteration.

Examples:

match items {
  [] => ()
  [head, ..tail] => handle(head, tail)
  [..prefix, mid, ..suffix] => handle_mid(prefix, mid, suffix)
}
match s {
  "" => ()
  [.."let", ..rest] => handle_let(rest)
  _ => ()
}
Char literal matching

MoonBit allows char literal overloading for Char, UInt16, and Int, so the examples below work. This is handy when matching String indexing results (UInt16) against a char range.

test {
  let a_int : Int = 'b'
  if (a_int is 'a'..<'z') { () } else { () }
  let a_u16 : UInt16 = 'b'
  if (a_u16 is 'a'..<'z') { () } else { () }
  let a_char : Char = 'b'
  if (a_char is 'a'..<'z') { () } else { () }
}
Use Nested Patterns and is
  • Use is patterns inside if/guard to keep branches concise.

Example:

match token {
  Some(Ident([.."@", ..rest])) if process(rest) is Some(x) => handle_at(rest)
  Some(Ident(name)) => handle_ident(name)
  None => ()
}
Prefer Range Loops for Simple Indexing
  • Use for i in start..<end { ... }, for i in start..<=end { ... }, for i in large>..small, or for i in large>=..small for simple index loops.
  • Keep functional-state for loops for algorithms that update state.

Example:

// Before
for i = 0; i < len; {
  items.push(fill)
  continue i + 1
}

// After
for i in 0..<len {
  items.push(fill)
}

Loop Specs (Dafny-Style Comments)

  • Add specs for functional-state loops.
  • Skip invariants for simple for x in xs loops.
  • Add TODO when a decreases clause is unclear (possible bug).

Example:

for i = 0, acc = 0; i < xs.length(); {
  acc = acc + xs[i]
  i = i + 1
} else { acc }
where {
  invariant: 0 <= i <= xs.length(),
  reasoning: (
    #| ... rigorous explanation ...
    #| ...
  )
}

Tests and Docs

  • Prefer black-box tests in *_test.mbt or *.mbt.md.
  • Add docstring tests with mbt check for public APIs.

Example:

///|
/// Return the last element of a non-empty array.
///
/// # Example
/// ```mbt check
/// test {
///   inspect(last([1, 2, 3]), content="3")
/// }
/// ```
pub fn last(xs : Array[Int]) -> Int { ... }

Coverage-Driven Refactors

  • Use coverage to target missing branches through public APIs.
  • Prefer small, focused tests over white-box checks.

Commands:

moon coverage analyze -- -f summary
moon coverage analyze -- -f caret -F path/​to/​file.mbt

Moon IDE Commands

moon doc "<query>"
moon ide outline <dir|file>
moon ide find-references <symbol>
moon ide peek-def <symbol>
moon check
moon test
moon info

These commands are useful for reliable refactoring.

Example: spinning off package_b from package_a.

Temporary import in package_b:

using @package_a { a, type B }

Steps:

  1. Use moon ide find-references <symbol> to find all call sites of a and B.
  2. Replace them with @package_a.a and @package_a.B.
  3. Remove the using statement and run moon check.

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View