mirror of
https://github.com/linabutler/ploidy
synced 2026-08-11 09:28:38 +00:00
chore: Split Rust codegen into ploidy-codegen-rust.
This commit is contained in:
Generated
+21
-3
@@ -626,10 +626,31 @@ dependencies = [
|
||||
"clap",
|
||||
"miette",
|
||||
"mimalloc",
|
||||
"ploidy-codegen-rust",
|
||||
"ploidy-core",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ploidy-codegen-rust"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"cargo_toml",
|
||||
"heck",
|
||||
"itertools",
|
||||
"miette",
|
||||
"ploidy-core",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn",
|
||||
"textwrap",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ploidy-core"
|
||||
version = "0.4.0"
|
||||
@@ -637,7 +658,6 @@ dependencies = [
|
||||
"atomic_refcell",
|
||||
"by_address",
|
||||
"cargo_toml",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"indoc",
|
||||
"itertools",
|
||||
@@ -655,11 +675,9 @@ dependencies = [
|
||||
"serde_path_to_error",
|
||||
"serde_yaml",
|
||||
"syn",
|
||||
"textwrap",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"unicase",
|
||||
"unicode-ident",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"ploidy",
|
||||
"ploidy-codegen-rust",
|
||||
"ploidy-core",
|
||||
"ploidy-pointer",
|
||||
"ploidy-pointer-derive",
|
||||
@@ -16,6 +17,7 @@ repository = "https://github.com/linabutler/ploidy"
|
||||
keywords = ["codegen", "openapi", "swagger"]
|
||||
|
||||
[workspace.dependencies]
|
||||
ploidy-codegen-rust = { path = "ploidy-codegen-rust", version = "0.4.0" }
|
||||
ploidy-core = { path = "ploidy-core", version = "0.4.0" }
|
||||
ploidy-pointer = { path = "ploidy-pointer", version = "0.4.0" }
|
||||
ploidy-pointer-derive = { path = "ploidy-pointer-derive", version = "0.4.0" }
|
||||
|
||||
@@ -63,7 +63,7 @@ This produces a ready-to-use crate that includes:
|
||||
* You'd like to use a custom template for the generated code, or a different HTTP client; or to generate synchronous code. For these cases, consider a template-based generator like **openapi-generator**.
|
||||
* You need to target a language other than Rust. **openapi-generator** supports many more languages; as does [**swagger-codegen**](https://github.com/swagger-api/swagger-codegen), if you don't need OpenAPI 3.1+ support.
|
||||
* Your spec uses OpenAPI (Swagger) 2.0. Ploidy only supports OpenAPI 3.0+, but **openapi-generator** and **swagger-codegen** support older versions.
|
||||
* You need to generate server stubs. Ploidy only generates clients, but **openapi-generator** can produce stubs for different Rust web frameworks. Alternatively, you can define your models and endpoints in Rust, and use [Dropshot](https://github.com/oxidecomputer/dropshot) to generate a Ploidy-compatible OpenAPI spec from those definitions.
|
||||
* You need to generate server stubs. Ploidy only generates clients, but **openapi-generator** can produce stubs for different Rust web frameworks. Alternatively, you can define your models and endpoints in Rust, and use [Dropshot](https://github.com/oxidecomputer/dropshot) to generate a Ploidy- or Progenitor-compatible OpenAPI spec from those definitions.
|
||||
* You'd like a more mature, established tool.
|
||||
|
||||
Here are some of the things that make Ploidy different.
|
||||
@@ -98,18 +98,35 @@ Generated code looks like it was written by an experienced Rust developer:
|
||||
* **Boxing** for recursive types.
|
||||
* **A RESTful client with async endpoints**, using [Reqwest](https://docs.rs/reqwest) with the [Tokio](https://tokio.rs) runtime.
|
||||
|
||||
For example:
|
||||
For example, given this schema:
|
||||
|
||||
```yaml
|
||||
Customer:
|
||||
type: object
|
||||
required: [id, email]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
```
|
||||
|
||||
Ploidy generates:
|
||||
|
||||
```rust
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Customer {
|
||||
pub id: String,
|
||||
pub email: String,
|
||||
#[serde(skip_serializing_if = "Absent::is_absent")]
|
||||
pub name: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "AbsentOr::is_absent")]
|
||||
pub name: AbsentOr<String>,
|
||||
}
|
||||
```
|
||||
|
||||
The optional `name` field uses [`AbsentOr<T>`](https://docs.rs/ploidy-util/latest/ploidy_util/absent/enum.AbsentOr.html), a three-valued type that matches how OpenAPI represents optional fields: either "present with a value", "present and explicitly set to `null`", or "absent from the payload".
|
||||
|
||||
## 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!
|
||||
@@ -136,32 +153,33 @@ For example, given a schema like:
|
||||
|
||||
```yaml
|
||||
Comment:
|
||||
type: object
|
||||
properties:
|
||||
text:
|
||||
type: string
|
||||
required: true
|
||||
parent:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Comment"
|
||||
children:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Comment"
|
||||
type: object
|
||||
required: [text]
|
||||
properties:
|
||||
text:
|
||||
type: string
|
||||
parent:
|
||||
$ref: "#/components/schemas/Comment"
|
||||
children:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Comment"
|
||||
```
|
||||
|
||||
Ploidy generates:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Comment {
|
||||
pub text: String,
|
||||
pub parent: Option<Box<Comment>>,
|
||||
pub children: Vec<Comment>,
|
||||
#[serde(default, skip_serializing_if = "AbsentOr::is_absent")]
|
||||
pub parent: AbsentOr<Box<Comment>>,
|
||||
#[serde(default, skip_serializing_if = "AbsentOr::is_absent")]
|
||||
pub children: AbsentOr<Vec<Comment>>,
|
||||
}
|
||||
```
|
||||
|
||||
(Since `Vec<T>` is already indirect, only the `parent` field needs boxing).
|
||||
Since `Vec<T>` is already heap-allocated, only the `parent` field needs boxing to break the cycle.
|
||||
|
||||
### Inline schemas
|
||||
|
||||
@@ -175,12 +193,20 @@ For example, given an operation with an inline response schema:
|
||||
/users/{id}:
|
||||
get:
|
||||
operationId: getUser
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [id, email, name]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
@@ -193,8 +219,13 @@ For example, given an operation with an inline response schema:
|
||||
Ploidy generates:
|
||||
|
||||
```rust
|
||||
mod types {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
impl Client {
|
||||
pub async fn get_user(&self, id: &str) -> Result<types::GetUserResponse, Error> {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
pub mod types {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct GetUserResponse {
|
||||
pub id: String,
|
||||
pub email: String,
|
||||
@@ -203,21 +234,21 @@ mod types {
|
||||
}
|
||||
```
|
||||
|
||||
The inline schema gets a descriptive name, and the same derives as any named schema. This "just works": inline schemas are first-class types in the generated code.
|
||||
The inline schema gets a descriptive name (in this case, `GetUserResponse`; derived from the `operationId` and its use as a response schema), and the same derives as any named schema. This "just works": inline schemas are first-class types in the generated code.
|
||||
|
||||
## Contributing
|
||||
|
||||
We love contributions: issues, feature requests, discussions, code, documentation, and examples are all welcome!
|
||||
|
||||
If you find a case where Ploidy fails, or generates incorrect or unidiomatic code, please [open an issue](https://github.com/linabutler/ploidy/issues/new) with your OpenAPI spec.
|
||||
If you find a case where Ploidy fails, or generates incorrect or unidiomatic code, please [open an issue](https://github.com/linabutler/ploidy/issues/new) with your OpenAPI spec. For questions, or for planning larger contributions, please [start a discussion](https://github.com/linabutler/ploidy/discussions).
|
||||
|
||||
Other areas where we'd love help are:
|
||||
Some areas where we'd especially love help are:
|
||||
|
||||
* Additional examples, with real-world specs.
|
||||
* Test coverage, especially for edge cases.
|
||||
* Documentation improvements.
|
||||
|
||||
We welcome LLM-assisted contributions, but hold them to the same quality bar: the code should fit in with the existing architecture and style of the project. Please [start a discussion](https://github.com/linabutler/ploidy/discussions) before vibing non-trivial features, as these usually take a bit more up-front design work.
|
||||
🤖 We welcome LLM-assisted contributions, but hold them to the same quality bar: the code should fit in with the existing architecture, approach, and overall style of the project.
|
||||
|
||||
Thanks!
|
||||
|
||||
@@ -225,8 +256,8 @@ Thanks!
|
||||
|
||||
Ploidy only targets Rust now, but its architecture is designed to support other languages. Our philosophy is to only support languages where we can:
|
||||
|
||||
1. Parse the target language properly.
|
||||
2. Generate valid syntax trees that are correct by construction, rather than interpolating string templates.
|
||||
1. Generate code from valid syntax trees that are correct by construction, rather than from string templates.
|
||||
2. Leverage existing tools for those languages, like parsers, linters, and formatters, that are written _in_ Rust.
|
||||
3. Maintain the same correctness guarantees and generated code quality as our Rust pipeline.
|
||||
|
||||
This does mean that Ploidy won't target every language. We'd rather support three languages perfectly, than a dozen languages with gaps.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
[package]
|
||||
name = "ploidy-codegen-rust"
|
||||
description = "A Ploidy generator that emits Rust code"
|
||||
readme = "README.md"
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
repository.workspace = true
|
||||
keywords.workspace = true
|
||||
|
||||
[dependencies]
|
||||
cargo_toml = "0.22"
|
||||
heck = "0.5"
|
||||
itertools = "0.14"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
miette = "7"
|
||||
ploidy-core = { workspace = true, features = ["cargo_toml", "proc-macro2"] }
|
||||
prettyplease = "0.2"
|
||||
proc-macro2 = { version = "1", default-features = false }
|
||||
quote = { version = "1", default-features = false }
|
||||
syn = { version = "2", default-features = false, features = [
|
||||
"parsing",
|
||||
"printing",
|
||||
] }
|
||||
textwrap = { version = "0.16", default-features = false, features = [
|
||||
"unicode-linebreak",
|
||||
"unicode-width",
|
||||
] }
|
||||
thiserror = "2"
|
||||
toml = { version = "0.9", default-features = false, features = [
|
||||
"display",
|
||||
"parse",
|
||||
"serde",
|
||||
] }
|
||||
unicode-ident = "1"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../LICENSE
|
||||
@@ -0,0 +1,7 @@
|
||||
# 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.
|
||||
|
||||
⚠️ The **ploidy-codegen-rust** API isn't stable yet.
|
||||
|
||||
One of the goals of this crate is to support usage from [build scripts](https://doc.rust-lang.org/cargo/reference/build-scripts.html), as an alternative to the `ploidy` CLI. This can be useful if you're generating an OpenAPI client as part of a larger Rust project, and don't need the complete crate that the CLI generates.
|
||||
@@ -2,10 +2,11 @@ use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use cargo_toml::{Edition, Manifest};
|
||||
use itertools::Itertools;
|
||||
use ploidy_core::codegen::IntoCode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use toml::Value as TomlValue;
|
||||
|
||||
use crate::codegen::{IntoCode, rust::CodegenGraph};
|
||||
use super::graph::CodegenGraph;
|
||||
|
||||
type TomlMap = toml::map::Map<String, TomlValue>;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use itertools::Itertools;
|
||||
use ploidy_core::codegen::IntoCode;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use crate::codegen::IntoCode;
|
||||
|
||||
use super::{graph::CodegenGraph, naming::CodegenIdent};
|
||||
|
||||
/// Generates the `client/mod.rs` source file.
|
||||
@@ -1,9 +1,8 @@
|
||||
use ploidy_core::ir::{IrEnumVariant, IrEnumView};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, format_ident, quote};
|
||||
use syn::{Ident, parse_quote};
|
||||
|
||||
use crate::ir::{IrEnumVariant, IrEnumView};
|
||||
|
||||
use super::{
|
||||
doc_attrs,
|
||||
naming::{CodegenIdent, CodegenTypeName},
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::{
|
||||
use ploidy_core::{
|
||||
codegen::UniqueNameSpace,
|
||||
ir::{IrGraph, View},
|
||||
};
|
||||
@@ -4,7 +4,7 @@ use itertools::Itertools;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
use crate::{
|
||||
use ploidy_core::{
|
||||
codegen::{IntoCode, write_to_disk},
|
||||
ir::View,
|
||||
};
|
||||
@@ -1,13 +1,12 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use heck::{ToPascalCase, ToSnakeCase};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{IdentFragment, ToTokens, TokenStreamExt, format_ident};
|
||||
|
||||
use crate::ir::{
|
||||
use ploidy_core::ir::{
|
||||
InlineIrTypePath, InlineIrTypePathSegment, IrStructFieldName, IrStructFieldNameHint,
|
||||
IrUntaggedVariantNameHint, PrimitiveIrType,
|
||||
};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{IdentFragment, ToTokens, TokenStreamExt, format_ident};
|
||||
|
||||
/// A name for a schema type that's guaranteed to be unique through
|
||||
/// different identifier case transformations.
|
||||
@@ -1,16 +1,15 @@
|
||||
use itertools::Itertools;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
use syn::Ident;
|
||||
|
||||
use crate::{
|
||||
codegen::unique::UniqueNameSpace,
|
||||
use ploidy_core::{
|
||||
codegen::UniqueNameSpace,
|
||||
ir::{
|
||||
IrOperationView, IrParameterStyle, IrParameterView, IrPathParameter, IrQueryParameter,
|
||||
IrRequestView, IrResponseView, IrTypeView,
|
||||
},
|
||||
parse::{Method, path::PathFragment},
|
||||
};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
use syn::Ident;
|
||||
|
||||
use super::{doc_attrs, naming::CodegenIdent, ref_::CodegenRef};
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use heck::ToSnakeCase;
|
||||
use ploidy_core::ir::{InlineIrTypePathRoot, IrTypeView, PrimitiveIrType, View};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, format_ident, quote};
|
||||
use syn::parse_quote;
|
||||
|
||||
use crate::ir::{InlineIrTypePathRoot, IrTypeView, PrimitiveIrType, View};
|
||||
|
||||
use super::{
|
||||
naming::CodegenTypeName,
|
||||
naming::{CodegenIdent, SchemaIdent},
|
||||
@@ -1,11 +1,10 @@
|
||||
use heck::ToSnakeCase;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use crate::{
|
||||
use ploidy_core::{
|
||||
codegen::IntoCode,
|
||||
ir::{InlineIrTypePathRoot, InlineIrTypeView, IrOperationView},
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use super::{
|
||||
enum_::CodegenEnum, naming::CodegenTypeName, operation::CodegenOperation,
|
||||
@@ -1,10 +1,9 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use crate::{
|
||||
use ploidy_core::{
|
||||
codegen::IntoCode,
|
||||
ir::{InlineIrTypeView, SchemaIrTypeView, View},
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use super::{
|
||||
enum_::CodegenEnum, naming::CodegenTypeName, struct_::CodegenStruct, tagged::CodegenTagged,
|
||||
@@ -1,8 +1,7 @@
|
||||
use ploidy_core::codegen::IntoCode;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use crate::codegen::IntoCode;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct CodegenLibrary;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use ploidy_core::{
|
||||
codegen::UniqueNameSpace,
|
||||
ir::{IrStructFieldName, IrStructFieldView, IrStructView, IrTypeView, PrimitiveIrType, View},
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
use syn::{Ident, parse_quote};
|
||||
|
||||
use crate::{
|
||||
codegen::unique::UniqueNameSpace,
|
||||
ir::{IrStructFieldName, IrStructFieldView, IrStructView, IrTypeView, PrimitiveIrType, View},
|
||||
};
|
||||
|
||||
use super::{
|
||||
derives::ExtraDerive,
|
||||
doc_attrs,
|
||||
@@ -1,11 +1,10 @@
|
||||
use itertools::Itertools;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use crate::{
|
||||
codegen::unique::UniqueNameSpace,
|
||||
use ploidy_core::{
|
||||
codegen::UniqueNameSpace,
|
||||
ir::{IrTaggedView, IrTypeView, PrimitiveIrType, View},
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use super::{
|
||||
derives::ExtraDerive, doc_attrs, naming::CodegenIdent, naming::CodegenTypeName,
|
||||
@@ -1,10 +1,9 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use ploidy_core::{codegen::IntoCode, ir::View};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use crate::{codegen::IntoCode, ir::View};
|
||||
|
||||
use super::{graph::CodegenGraph, naming::SchemaIdent};
|
||||
|
||||
/// Generates the `types/mod.rs` module.
|
||||
@@ -1,8 +1,7 @@
|
||||
use ploidy_core::ir::{IrTypeView, IrUntaggedView, PrimitiveIrType, SomeIrUntaggedVariant};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt, quote};
|
||||
|
||||
use crate::ir::{IrTypeView, IrUntaggedView, PrimitiveIrType, SomeIrUntaggedVariant};
|
||||
|
||||
use super::{
|
||||
derives::ExtraDerive,
|
||||
doc_attrs,
|
||||
+9
-25
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ploidy-core"
|
||||
description = "OpenAPI type definitions and code generators for Ploidy"
|
||||
description = "An OpenAPI IR and type graph for Ploidy"
|
||||
readme = "README.md"
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
@@ -12,7 +12,6 @@ keywords.workspace = true
|
||||
atomic_refcell = "0.1"
|
||||
by_address = "1"
|
||||
cargo_toml = { version = "0.22", optional = true }
|
||||
heck = "0.5"
|
||||
indexmap = { version = "2", features = ["serde"] }
|
||||
itertools = "0.14"
|
||||
miette = "7"
|
||||
@@ -28,22 +27,10 @@ proc-macro2 = { version = "1", default-features = false, optional = true }
|
||||
quote = { version = "1", default-features = false, optional = true }
|
||||
ref-cast = "1"
|
||||
rustc-hash = "2"
|
||||
syn = { version = "2", default-features = false, features = [
|
||||
"parsing",
|
||||
"printing",
|
||||
], optional = true }
|
||||
textwrap = { version = "0.16", default-features = false, features = [
|
||||
"unicode-linebreak",
|
||||
"unicode-width",
|
||||
], optional = true }
|
||||
syn = { version = "2", default-features = false, optional = true }
|
||||
thiserror = "2"
|
||||
toml = { version = "0.9", default-features = false, features = [
|
||||
"display",
|
||||
"parse",
|
||||
"serde",
|
||||
], optional = true }
|
||||
toml = { version = "0.9", default-features = false, optional = true }
|
||||
unicase = "2"
|
||||
unicode-ident = { version = "1", optional = true }
|
||||
winnow = "0.7"
|
||||
|
||||
[dev-dependencies]
|
||||
@@ -51,15 +38,12 @@ indoc = "2"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
rust = [
|
||||
"cargo_toml",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"textwrap",
|
||||
"toml",
|
||||
"unicode-ident",
|
||||
cargo_toml = ["dep:cargo_toml", "toml/display", "toml/serde"]
|
||||
proc-macro2 = [
|
||||
"dep:prettyplease",
|
||||
"dep:proc-macro2",
|
||||
"dep:quote",
|
||||
"syn/parsing",
|
||||
]
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# ploidy-core
|
||||
|
||||
This crate is the core (or nucleus! 🧬) of the [Ploidy](https://crates.io/crates/ploidy) OpenAPI code generator. It exposes structures for parsing OpenAPI types, and code generators for different languages.
|
||||
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.
|
||||
|
||||
You can use **ploidy-core** as part of a larger project, or from a [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html) if you're targeting Rust.
|
||||
⚠️ The **ploidy-core** API isn't stable yet.
|
||||
|
||||
@@ -2,9 +2,6 @@ use std::path::Path;
|
||||
|
||||
use miette::{Context, IntoDiagnostic};
|
||||
|
||||
#[cfg(feature = "rust")]
|
||||
pub mod rust;
|
||||
|
||||
mod unique;
|
||||
|
||||
pub use unique::{UniqueNameSpace, WordSegments};
|
||||
@@ -29,7 +26,7 @@ pub trait Code {
|
||||
fn into_string(self) -> miette::Result<String>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "rust")]
|
||||
#[cfg(feature = "proc-macro2")]
|
||||
impl<T: AsRef<str>> Code for (T, proc_macro2::TokenStream) {
|
||||
fn path(&self) -> &str {
|
||||
self.0.as_ref()
|
||||
@@ -45,7 +42,7 @@ impl<T: AsRef<str>> Code for (T, proc_macro2::TokenStream) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rust")]
|
||||
#[cfg(feature = "cargo_toml")]
|
||||
impl<T: serde::Serialize> Code for (&'static str, cargo_toml::Manifest<T>) {
|
||||
fn path(&self) -> &str {
|
||||
self.0
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@ cargo_toml = "0.22"
|
||||
clap = { version = "4", features = ["cargo", "derive"] }
|
||||
miette = { version = "7", features = ["fancy"] }
|
||||
mimalloc = { version = "0.1", optional = true }
|
||||
ploidy-core = { workspace = true, features = ["rust"] }
|
||||
ploidy-codegen-rust = { workspace = true }
|
||||
ploidy-core = { workspace = true }
|
||||
semver = "1"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -5,10 +5,9 @@ use clap::{
|
||||
CommandFactory, FromArgMatches,
|
||||
error::{Error as ClapError, ErrorKind as ClapErrorKind, Result as ClapResult},
|
||||
};
|
||||
use ploidy_codegen_rust::CargoMetadata;
|
||||
use semver::Version;
|
||||
|
||||
use ploidy_core::codegen::rust::CargoMetadata;
|
||||
|
||||
const DEFAULT_VERSION: Version = Version::new(0, 1, 0);
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
+8
-11
@@ -1,9 +1,9 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use miette::{Context, IntoDiagnostic, Result};
|
||||
|
||||
use ploidy_codegen_rust::{CodegenCargoManifest, CodegenErrorModule, CodegenGraph, CodegenLibrary};
|
||||
use ploidy_core::{
|
||||
codegen::{rust, write_to_disk},
|
||||
codegen::write_to_disk,
|
||||
ir::{IrGraph, IrSpec},
|
||||
parse::Document,
|
||||
};
|
||||
@@ -35,24 +35,21 @@ fn main() -> Result<()> {
|
||||
println!("OpenAPI: {} (version {})", doc.info.title, doc.info.version);
|
||||
|
||||
let spec = IrSpec::from_doc(&doc).into_diagnostic()?;
|
||||
let graph = rust::CodegenGraph::new(IrGraph::new(&spec));
|
||||
let graph = CodegenGraph::new(IrGraph::new(&spec));
|
||||
|
||||
println!("Writing generated code to `{}`...", output.display());
|
||||
|
||||
println!("Generating `Cargo.toml`...");
|
||||
write_to_disk(
|
||||
&output,
|
||||
rust::CodegenCargoManifest::new(&graph, &config.manifest),
|
||||
)?;
|
||||
write_to_disk(&output, CodegenCargoManifest::new(&graph, &config.manifest))?;
|
||||
|
||||
println!("Generating `lib.rs`...");
|
||||
write_to_disk(&output, rust::CodegenLibrary)?;
|
||||
write_to_disk(&output, CodegenLibrary)?;
|
||||
|
||||
println!("Generating `error.rs`...");
|
||||
write_to_disk(&output, rust::CodegenErrorModule)?;
|
||||
write_to_disk(&output, CodegenErrorModule)?;
|
||||
|
||||
println!("Generating {} types...", graph.schemas().count());
|
||||
rust::write_types_to_disk(&output, &graph)?;
|
||||
ploidy_codegen_rust::write_types_to_disk(&output, &graph)?;
|
||||
|
||||
let counts =
|
||||
graph
|
||||
@@ -66,7 +63,7 @@ fn main() -> Result<()> {
|
||||
counts.values().copied().sum::<usize>(),
|
||||
counts.keys().count(),
|
||||
);
|
||||
rust::write_client_to_disk(&output, &graph)?;
|
||||
ploidy_codegen_rust::write_client_to_disk(&output, &graph)?;
|
||||
|
||||
println!("Generation complete");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user