From 9c27a2011f4eb7bfe462d6a1b741db43ab946e42 Mon Sep 17 00:00:00 2001 From: Lina Butler Date: Wed, 15 Apr 2026 18:02:08 -0700 Subject: [PATCH] glow-up: Rebrand from "code generator" to "compiler". [skip ci] --- Cargo.toml | 2 +- README.md | 40 ++++++++++++++++++-------------- ploidy-codegen-rust/Cargo.toml | 4 ++-- ploidy-codegen-rust/README.md | 2 +- ploidy-core/Cargo.toml | 4 ++-- ploidy-core/README.md | 2 +- ploidy-core/src/lib.rs | 6 ++--- ploidy-pointer-derive/Cargo.toml | 2 +- ploidy-pointer/Cargo.toml | 2 +- ploidy-pointer/README.md | 2 +- ploidy-util/Cargo.toml | 2 +- ploidy-util/README.md | 2 +- ploidy/Cargo.toml | 2 +- 13 files changed, 39 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 144d304..193f13b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ version = "0.11.0" license = "Apache-2.0" edition = "2024" repository = "https://github.com/linabutler/ploidy" -keywords = ["codegen", "openapi", "swagger"] +keywords = ["openapi", "codegen", "compiler"] rust-version = "1.89" [workspace.dependencies] diff --git a/README.md b/README.md index eddd26c..a4507e8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Ploidy -**A compiler for polymorphic OpenAPI specs.** +**A polymorphism-aware OpenAPI compiler.** [crates.io](https://crates.io/crates/ploidy) [Build status](https://github.com/linabutler/ploidy/actions?query=branch%3Amain) @@ -9,7 +9,7 @@ [ploidy-pointer Documentation](https://docs.rs/ploidy-pointer) [ploidy-util Documentation](https://docs.rs/ploidy-util) -Many OpenAPI specs use `allOf` to model inheritance, and `oneOf`, `anyOf`, and discriminators to model [polymorphic types](https://swagger.io/docs/specification/v3_0/data-models/inheritance-and-polymorphism/). These patterns are powerful, but can be tricky to support correctly, and most code generators struggle with them. Ploidy was built specifically with inheritance and polymorphism in mind, and aims to generate clean, type-safe, and idiomatic Rust that reads like what you'd write by hand. +Ploidy compiles OpenAPI specs into clean, type-safe Rust that reads like it was written by hand. It's built to handle the thornier features—like inheritance, polymorphism, inline schemas, and recursive types—that trip up most code generators. ## Table of Contents @@ -29,7 +29,7 @@ Many OpenAPI specs use `allOf` to model inheritance, and `oneOf`, `anyOf`, and d - [Per-resource feature gates](#per-resource-feature-gates) * [Under the Hood](#under-the-hood) - [The generation pipeline](#the-generation-pipeline) - - [AST-based generation](#ast-based-generation) + - [AST-based codegen](#ast-based-codegen) - [Smart boxing](#smart-boxing) - [Inline schemas](#inline-schemas) - [Cargo features](#cargo-features) @@ -79,10 +79,10 @@ This produces a ready-to-use crate that includes: | Flag | Description | |------|-------------| -| `-o`, `--output` | The output directory for the generated crate | +| `-o`, `--output` | Set the output directory for the generated crate | | `-c`, `--check` | Verify the generated crate compiles | | `--name ` | Set the crate name. If not passed, and a `Cargo.toml` already exists in the output directory, use its `package.name`; otherwise, use the output directory name | -| `--version ` | Increment the major, minor, or patch component of the existing `package.version`. If not passed, use the existing version, or 0.1.0 for new crates | +| `--version ` | Increment the major, minor, or patch component of the existing `package.version`. If not passed, use the existing version, or 0.1.0 for new crates | #### Advanced options @@ -205,7 +205,7 @@ For example, given a spec with `Customer`, `Order`, and `BillingInfo` schemas, w default = ["billing-info", "customer", "order"] billing-info = [] customer = ["billing-info"] -order = ["billing-info", "customer"] +order = ["customer"] ``` All features are enabled by default, so the generated crate works out of the box. Consumers that only need a subset of the API can pick the specific features they need: @@ -219,21 +219,26 @@ This compiles just the `Customer` type—and its dependency, `BillingInfo`—alo ## Under the Hood -Ploidy takes a somewhat different approach to code generation. If you're curious about how it works, this section is for you! +Ploidy takes a different approach to code generation. If you're curious about how it works, this section is for you! ### The generation pipeline Ploidy processes an OpenAPI spec in three stages: -📝 **Parsing** a JSON or YAML OpenAPI spec into Rust data structures. The parser is intentionally forgiving; Ploidy doesn't rigorously enforce OpenAPI (or JSON Schema) semantics. +📝 **Parsing** a JSON or YAML OpenAPI spec into Rust data structures. The parser is intentionally forgiving; Ploidy accepts malformed specs that stricter validators reject. -🏗️ **Constructing an IR** (intermediate representation). Ploidy constructs a type graph from the spec, which lets it answer questions like "which types can derive `Eq`, `Hash`, and `Default`?" and "which fields need `Box` to break cycles?" +🏗️ **Constructing an IR** (intermediate representation). Ploidy builds a type graph from the spec, which lets it answer questions like "which types can derive `Eq`, `Hash`, and `Default`?" and "which fields need `Box` to break cycles?" -✍️ **Generating code** from the IR. During the final stage, Ploidy builds proper Rust syntax trees from the type graph, prettifies the code, and writes it to disk. +✍️ **Generating code** from the IR. Ploidy creates Rust syntax trees from the type graph, prettifies the code, and writes it to disk. -### AST-based generation +### AST-based codegen -Most code generators use string templates, but Ploidy uses Rust's `syn` and `quote` crates to generate **syntax trees**. This means the generated code is syntactically valid by construction. +Ploidy builds Rust **syntax trees** directly with [`syn`](https://docs.rs/syn) and [`quote`](https://docs.rs/quote), rather than assembling code from string templates. This has two benefits: + +* **Generated code is syntactically valid by construction.** Nodes are typed `syn` values, built with `parse_quote!` and friends. Ploidy can't produce a crate with mismatched delimiters or malformed attributes. +* **Complex types compose cleanly.** Trait bounds, attribute macros, and nested generics combine as tokens, not concatenated strings. The generator never juggles whitespace or escaping, so hard-to-generate constructs are as reliable as simple ones. + +Once the tree is built, [`prettyplease`](https://docs.rs/prettyplease) formats it into the final output. ### Smart boxing @@ -275,7 +280,7 @@ Since `Vec` is already heap-allocated, only the `parent` field needs boxing t OpenAPI specs can define schemas directly at their point of use—in operation parameters, in request and response bodies, or nested within other schemas—rather than in the `/components/schemas` section. These are called **inline schemas**. -Many code generators treat inline schemas as untyped values (`Any` or `serde_json::Value`), but Ploidy generates the same strongly-typed models for inline schemas as it does for named schemas. Inline schemas are named based on where they occur in the spec, and are namespaced in submodules within the parent module. +Ploidy generates the same strongly-typed models for inline schemas as it does for named schemas. Inline schemas are named based on where they occur in the spec, and are namespaced in submodules within the parent module. For example, given an operation with an inline response schema: @@ -296,7 +301,7 @@ For example, given an operation with an inline response schema: application/json: schema: type: object - required: [id, email, name] + required: [id, email] properties: id: type: string @@ -319,7 +324,8 @@ pub mod types { pub struct GetUserResponse { pub id: String, pub email: String, - pub name: String, + #[serde(default, skip_serializing_if = "AbsentOr::is_absent")] + pub name: AbsentOr, } } ``` @@ -366,6 +372,6 @@ Ploidy is inspired by, learns from, and builds on the wonderful work of: * The OpenAPI ecosystem: **openapi-generator**, **Progenitor**, and other code generators. * The Rust ecosystem: Tokio, Reqwest, Serde, `quote`, `syn`, and `winnow`. -* [**Petgraph**](https://crates.io/crates/petgraph), a Rust graph data structure library that's Ploidy's secret sauce. +* [**Petgraph**](https://crates.io/crates/petgraph), a Rust graph data structure library that's the backbone of Ploidy's type graph. -And yes, the name is a biology pun! [Ploidy](https://en.wikipedia.org/wiki/Ploidy) refers to the number of chromosome sets in a cell, and _polyploidy_ is when cells have many chromosome sets...and polymorphic types have many forms through inheritance. +And yes, the name is a biology pun! [Ploidy](https://en.wikipedia.org/wiki/Ploidy) is the number of complete chromosome sets an organism carries—and the types Ploidy generates carry multiple sets of their own. diff --git a/ploidy-codegen-rust/Cargo.toml b/ploidy-codegen-rust/Cargo.toml index 0a596e5..ac31535 100644 --- a/ploidy-codegen-rust/Cargo.toml +++ b/ploidy-codegen-rust/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "ploidy-codegen-rust" -description = "A Ploidy generator that emits Rust code" +description = "Rust codegen for the Ploidy OpenAPI compiler" readme = "README.md" +keywords = ["openapi", "rust", "codegen", "compiler"] version.workspace = true license.workspace = true edition.workspace = true repository.workspace = true -keywords.workspace = true rust-version.workspace = true [dependencies] diff --git a/ploidy-codegen-rust/README.md b/ploidy-codegen-rust/README.md index d214b10..5a07f32 100644 --- a/ploidy-codegen-rust/README.md +++ b/ploidy-codegen-rust/README.md @@ -1,6 +1,6 @@ # ploidy-codegen-rust -This crate is part of the [Ploidy](https://crates.io/crates/ploidy) OpenAPI code generator. It transforms [**ploidy-core**](https://crates.io/crates/ploidy-core) types into Rust syntax trees, pretty-prints them, and saves the output to disk. +This crate is part of the [Ploidy](https://crates.io/crates/ploidy) OpenAPI compiler. It transforms [**ploidy-core**](https://crates.io/crates/ploidy-core) types into Rust syntax trees, pretty-prints them, and saves the output to disk. ⚠️ The **ploidy-codegen-rust** API isn't stable yet. diff --git a/ploidy-core/Cargo.toml b/ploidy-core/Cargo.toml index b3d07c3..b7efe71 100644 --- a/ploidy-core/Cargo.toml +++ b/ploidy-core/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "ploidy-core" -description = "An OpenAPI IR and type graph for Ploidy" +description = "IR and type graph for the Ploidy OpenAPI compiler" readme = "README.md" +keywords = ["openapi", "codegen", "compiler", "ir", "schema"] version.workspace = true license.workspace = true edition.workspace = true repository.workspace = true -keywords.workspace = true rust-version.workspace = true [dependencies] diff --git a/ploidy-core/README.md b/ploidy-core/README.md index df16024..c0279fd 100644 --- a/ploidy-core/README.md +++ b/ploidy-core/README.md @@ -1,5 +1,5 @@ # ploidy-core -This crate is the nucleus (🧬) of the [Ploidy](https://crates.io/crates/ploidy) OpenAPI code generator. It exposes structures for constructing a language-agnostic **intermediate representation** of an OpenAPI spec, which code generators then use to target different languages. +This crate is the core of the [Ploidy](https://crates.io/crates/ploidy) OpenAPI compiler. It exposes structures for constructing a language-agnostic **intermediate representation** of an OpenAPI spec, which codegen backends then use to target different languages. ⚠️ The **ploidy-core** API isn't stable yet. diff --git a/ploidy-core/src/lib.rs b/ploidy-core/src/lib.rs index f2358af..331d99d 100644 --- a/ploidy-core/src/lib.rs +++ b/ploidy-core/src/lib.rs @@ -1,9 +1,9 @@ //! Language-agnostic intermediate representation and type graph -//! for OpenAPI code generation. +//! for the Ploidy OpenAPI compiler. //! //! **ploidy-core** transforms a parsed OpenAPI document into a -//! typed dependency graph that **ploidy-codegen-\*** backends -//! traverse to emit code. +//! typed dependency graph that codegen backends traverse to emit +//! code. //! //! # Pipeline //! diff --git a/ploidy-pointer-derive/Cargo.toml b/ploidy-pointer-derive/Cargo.toml index e484b70..9c3896f 100644 --- a/ploidy-pointer-derive/Cargo.toml +++ b/ploidy-pointer-derive/Cargo.toml @@ -2,7 +2,7 @@ name = "ploidy-pointer-derive" description = "Derive macros for Ploidy JSON Pointers" readme = "README.md" -keywords = ["6901", "json", "json-pointer", "rfc-6901"] +keywords = ["json-pointer", "derive", "proc-macro", "macro"] rust-version = "1.86" version.workspace = true license.workspace = true diff --git a/ploidy-pointer/Cargo.toml b/ploidy-pointer/Cargo.toml index 578fbec..5009ed4 100644 --- a/ploidy-pointer/Cargo.toml +++ b/ploidy-pointer/Cargo.toml @@ -2,7 +2,7 @@ name = "ploidy-pointer" description = "JSON Pointers for strongly-typed data structures" readme = "README.md" -keywords = ["6901", "json", "json-pointer", "rfc-6901"] +keywords = ["json-pointer", "json-schema", "rfc6901", "json", "pointer"] rust-version = "1.86" version.workspace = true license.workspace = true diff --git a/ploidy-pointer/README.md b/ploidy-pointer/README.md index cf82e2e..d4809d6 100644 --- a/ploidy-pointer/README.md +++ b/ploidy-pointer/README.md @@ -2,7 +2,7 @@ This crate provides a way to traverse typed Rust data structures using JSON Pointers ([RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901)). At its heart is the `JsonPointee` trait, which can be implemented on types to make them traversable. -**ploidy-pointer** is part of the [Ploidy](https://crates.io/crates/ploidy) OpenAPI code generator, but can be used standalone. +**ploidy-pointer** is part of the [Ploidy](https://crates.io/crates/ploidy) OpenAPI compiler, but can be used standalone. ## Features diff --git a/ploidy-util/Cargo.toml b/ploidy-util/Cargo.toml index 6d03b30..78cc438 100644 --- a/ploidy-util/Cargo.toml +++ b/ploidy-util/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ploidy-util" -description = "Shared types and functions for crates generated by Ploidy" +description = "Runtime support for crates generated by Ploidy" readme = "README.md" rust-version = "1.86" version.workspace = true diff --git a/ploidy-util/README.md b/ploidy-util/README.md index 38bfcb3..c44c535 100644 --- a/ploidy-util/README.md +++ b/ploidy-util/README.md @@ -1,3 +1,3 @@ # Ploidy -This package contains shared types and functions for crates generated by the [Ploidy](https://crates.io/crates/ploidy) OpenAPI code generator. +Runtime support for crates generated by the [Ploidy](https://crates.io/crates/ploidy) OpenAPI compiler. diff --git a/ploidy/Cargo.toml b/ploidy/Cargo.toml index c01187f..20fe94c 100644 --- a/ploidy/Cargo.toml +++ b/ploidy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ploidy" -description = "A compiler for polymorphic OpenAPI specs" +description = "A polymorphism-aware OpenAPI compiler" readme = "README.md" version.workspace = true license.workspace = true