16 releases (4 breaking)
Uses new Rust 2024
| new 0.5.1 | May 13, 2026 |
|---|---|
| 0.5.0 | May 8, 2026 |
| 0.4.4 | May 5, 2026 |
| 0.3.4 | May 1, 2026 |
| 0.1.0 | Apr 17, 2026 |
#284 in Rust patterns
112 downloads per month
Used in openapi-nexus
660KB
15K
SLoC
sigil-stitch
Type-safe, import-aware, width-aware code generation for multiple languages.
sigil-stitch combines JavaPoet's builder + CodeBlock
model with Wadler-Lindig pretty printing
and multi-language support. Reference types with %T in format strings, and the library
tracks every import for you, resolves naming conflicts, and emits width-aware formatted output.
Quick Start
cargo add sigil-stitch
Requires Rust edition 2024, MSRV 1.88.0. Runtime dependencies: pretty (Wadler-Lindig formatting), serde with derive (every spec type implements Serialize/Deserialize out of the box, so you can round-trip specs as JSON or YAML), and snafu (structured errors).
Builder vs Macro
sigil-stitch offers two ways to build code. Both produce the same CodeBlock with
the same import tracking and rendering.
Builder API -- programmatic, good for dynamic code generation:
use sigil_stitch::prelude::*;
use sigil_stitch::code_block::StringLitArg;
let user_type = TypeName::importable_type("./models", "User");
let mut cb = CodeBlock::builder();
cb.add_statement(
"const user: %T = await getUser(%S)",
(user_type.clone(), StringLitArg("id".into())),
);
cb.add_statement("return user", ());
let body = cb.build().unwrap();
let file = FileSpec::builder("user.ts")
.add_code(body)
.build()
.unwrap();
let output = file.render(80).unwrap();
assert!(output.contains("import type { User } from './models'"));
assert!(output.contains("const user: User = await getUser('id');"));
sigil_quote! macro -- inline target-language code, less ceremony:
use sigil_stitch::prelude::*;
use sigil_stitch::lang::typescript::TypeScript;
let user_type = TypeName::importable_type("./models", "User");
let body = sigil_quote!(TypeScript {
const user: $T(user_type) = await getUser($S("id"));
if (!user) {
throw new Error($S("not found"));
}
return user;
}).unwrap();
The macro uses $T/$S/$N/$L/$C/$W interpolation markers that expand to
the equivalent %T/%S/%N/%L format specifiers at compile time. It also
supports $C_each for splicing iterables of code blocks, $if/$else_if/$else
for meta-conditionals, $for for compile-time iteration, $let for Rust-level
variable bindings, $join for separator-joined lists, and $+ for line
continuation in multi-line expressions.
Format Specifiers
| Specifier | Name | Argument Type | Purpose |
|---|---|---|---|
%T |
Type | TypeName |
Emit type reference, track import |
%N |
Name | NameArg |
Emit identifier name, escape reserved words |
%S |
String | StringLitArg |
Emit escaped string literal |
%L |
Literal | &str, number, CodeBlock |
Emit raw value or nested block |
%W |
Wrap | (none) | Soft line break point |
%> |
Indent | (none) | Increase indent level |
%< |
Dedent | (none) | Decrease indent level |
%[ |
Statement begin | (none) | Start of statement |
%] |
Statement end | (none) | End of statement (appends ; if needed) |
Bare &str maps to %L. Use NameArg for %N and StringLitArg for %S.
See the Format Specifiers chapter for the full deep dive.
The Spec Layer
Build structured declarations with the spec builders:
| Spec | Purpose |
|---|---|
| ParameterSpec | Function parameter (name + type + default + variadic) |
| FieldSpec | Struct field / class property (visibility, static, readonly) |
| FunSpec | Function or method (params, return type, body, async, abstract) |
| TypeSpec | Class, struct, interface, trait, enum, type alias, newtype, embedded types |
| PropertySpec | Computed property with getter/setter |
| AnnotationSpec | @Override, #[derive(...)], [[nodiscard]] |
| EnumVariantSpec | Enum variant with optional value, tuple, or struct fields |
| ImportSpec | Explicit imports (aliased, side-effect, wildcard) |
| FileSpec | Top-level file with automatic import resolution |
| ProjectSpec | Multi-file project generation |
| CodeTemplate | Reusable parameterized templates with named parameters |
All specs emit CodeBlocks internally, so import tracking works everywhere.
See Building Functions & Fields, Building Types & Enums, and Files & Projects for examples and the full API.
Supported Languages
| Language | Extension | Semicolons | Import Style |
|---|---|---|---|
| TypeScript | .ts |
yes | ES modules |
| JavaScript | .js |
yes | ES modules |
| Rust | .rs |
yes | use paths |
| Go | .go |
no | package imports |
| Python | .py |
no | import/from |
| Java | .java |
yes | package imports |
| Kotlin | .kt |
no | package imports |
| Swift | .swift |
no | import module |
| Dart | .dart |
yes | package imports |
| Scala | .scala |
no | import paths |
| Haskell | .hs |
no | import module |
| OCaml | .ml |
no | open module |
| C | .c |
yes | #include |
| C++ | .cpp |
yes | #include/using |
| C# | .cs |
yes | using namespace |
| Lua | .lua |
no | require() |
| Bash | .bash |
no | source |
| Zsh | .zsh |
no | source |
Documentation
The sigil-stitch book covers everything in depth:
User Guide:
- Introduction -- what it is and how the pieces fit together
- Getting Started -- first CodeBlock, first FileSpec, first output
- Format Specifiers -- deep dive on
%T,%N,%S,%L,%W, and friends - TypeName -- type references, import tracking, cross-language rendering
- Building Functions & Fields -- ParameterSpec, FieldSpec, FunSpec
- Building Types & Enums -- TypeSpec, PropertySpec, AnnotationSpec, EnumVariantSpec
- Files & Projects -- ImportSpec, FileSpec, ProjectSpec
- sigil_quote! Macro -- inline code with
$T/$S/$N/$L/$C_each/$if/$for/$let/$join/$+interpolation - Code Templates -- reusable
#{name:K}templates - Language Cookbook -- idiomatic recipes per language
Development Guide:
- Architecture -- four layers, three-pass pipeline, import resolution
- Type Presentation -- data-driven cross-language type rendering
- Adding a Language -- implementing the CodeLang trait step by step
MSRV
The minimum supported Rust version is 1.88.0 (edition 2024, let-chains).
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Dependencies
~2–2.7MB
~46K SLoC