COOLJAPAN
← All posts

SplitRS 0.3.3 Released — Domain-Aware Module Routing and Recursive Nested-Mod Descent

SplitRS 0.3.3 adds domain-mapping for --target-modules (seeded assignment by reference affinity, unknown-name validation, dry-run attribution), recursive --split-nested-mods descent into inline mod blocks, a --facade style flag, verbatim method extraction, and 565 passing tests. The AST-based Rust refactoring tool for the COOLJAPAN ecosystem.

release splitrs rust refactoring ast developer-tools code-organization

Naming a target module by hand is easy. Knowing which of the other 40 unlisted items belong in it is not — until now.

Today we released SplitRS 0.3.3 — a release focused on making --target-modules genuinely smart about where things belong, and on reaching into nested mod blocks that previously stopped the splitter cold.

SplitRS is the AST-based Rust refactoring tool that splits oversized source files into clean, compilable modules: it parses with syn, clusters methods and types, infers visibility, and writes the imports and mod.rs facades for you. No C, no external formatter shelling out to system tools — it links prettyplease in-process and compiles to a single static binary.

Why 0.3.3 is a meaningful step

Naming target modules by hand used to mean one of two outcomes for everything you didn’t explicitly list:

0.3.3 ends that trade-off with real domain-mapping:

And separately: --split-nested-mods finally lets the splitter descend recursively through inline mod x { ... } bodies that are themselves over budget — through the same analyze → group → generate pipeline, at any depth, with super:: paths depth-adjusted per level.

Technical Deep Dive: domain routing and recursive descent

  1. src/domain_router.rs — the seeded fixpoint. For each named-module rule with pull_dependencies enabled, the router treats already-assigned items as seeds and repeatedly scans unlisted items for references into a seeded module, pulling in the strongest-affinity match each pass, until no more items move.
  2. Unknown-name validation (validate_target_modules()). Before any routing happens, every exact items entry is checked against the file’s actual item names; a name that matches nothing fails fast with a suggestion, and duplicate module names within the same parent scope, empty items lists, and misplaced catch-all * rules are rejected too.
  3. src/nested_mod_splitter.rs — recursive descent. Over-budget inline mod bodies are fed back through the same file-analysis pipeline that handles top-level files, emitting <output>/x/mod.rs recursively; the source map (src/source_map.rs) keeps absolute byte spans correct at every descent level, so verbatim emission — including now individual extracted impl methods — keeps working no matter how deep you go.
  4. Facade control. --facade <glob|named|none> (or [output] facade in .splitrs.toml) chooses how each generated mod.rs re-exports its children: a pub use x::*; glob, explicit named re-exports, or plain mod declarations with nothing re-exported.

Getting Started

Install the latest SplitRS:

cargo install splitrs

Route unlisted items by reference affinity:

# .splitrs.toml
assign_unlisted = "seeded"

[[target_modules]]
name = "geometry"
items = ["Point", "Vector"]
pull_dependencies = true
splitrs --input src/large_file.rs --output src/large_file/ --dry-run
# reports which rule (or seed edge) pulled each unlisted item into `geometry`

Descend into oversized nested mod blocks:

splitrs \
  --input src/large_file.rs \
  --output src/large_file/ \
  --split-nested-mods \
  --max-mod-depth 3 \
  --facade named

What’s New in 0.3.3

Tips

This is the foundation

SplitRS remains the development workhorse behind the COOLJAPAN policy of keeping every file under 2,000 lines — it’s used across the ecosystem’s Rust codebases (OxiZ, NumRS2, SciRS2, and dozens of oxi* crates) whenever a module outgrows its budget. Domain-mapping in 0.3.3 means large, tangled files can now be routed by actual reference structure, not just naming heuristics.

Repository: https://github.com/cool-japan/splitrs

Star the repo if a refactoring tool that understands why an item belongs in a module — not just what you told it — is what your codebase needs. Pure Rust refactoring is here — fast, safe, and now domain-aware.

KitaSan at COOLJAPAN OÜ July 6, 2026

↑ Back to all posts