Skip to main content

pushkin_compiler/
lib.rs

1//! Pushkin compiler: canonical JSON Schema 2020-12 → strict
2//! four-target bindings (TS/Zod, Pydantic v2, Rust serde, SQL DDL), each
3//! stamped with a schema-epoch header (spec §5.2).
4//!
5//! Crate contract: emission is deterministic (same input → byte-identical
6//! output) and total over the constrained authorable subset; anything
7//! outside the subset is a loud `Unrepresentable` rejection with named
8//! alternatives — never a silent drop (spec §5.1).
9
10mod schema;
11mod targets;
12
13use serde::Deserialize;
14use thiserror::Error;
15
16pub use schema::{ContractSchema, Property, PropertyKind};
17
18#[derive(Debug, Error)]
19pub enum CompileError {
20    #[error("contract schema is not valid JSON Schema 2020-12: {message}")]
21    InvalidSchema { message: String },
22    #[error(
23        "construct '{construct}' does not round-trip to all targets; \
24         use one of the supported alternatives: {alternatives}"
25    )]
26    Unrepresentable {
27        construct: String,
28        alternatives: String,
29    },
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
33#[serde(rename_all = "lowercase")]
34pub enum Target {
35    Zod,
36    Pydantic,
37    Rust,
38    Sql,
39}
40
41#[derive(Debug)]
42pub struct CompileRequest {
43    pub contract_name: String,
44    pub schema_json: String,
45    pub target: Target,
46    pub epoch: u32,
47}
48
49#[derive(Debug)]
50pub struct CompiledBinding {
51    pub content: String,
52}
53
54/// Compiles one contract schema to one target binding.
55///
56/// # Errors
57/// Returns `CompileError::InvalidSchema` for malformed input and
58/// `CompileError::Unrepresentable` (with alternatives) for constructs
59/// outside the constrained authorable subset.
60pub fn compile(request: &CompileRequest) -> Result<CompiledBinding, CompileError> {
61    let schema = schema::parse(&request.contract_name, &request.schema_json)?;
62    let content = match request.target {
63        Target::Zod => targets::zod::emit(&schema, request.epoch),
64        Target::Pydantic => targets::pydantic::emit(&schema, request.epoch),
65        Target::Rust => targets::rust::emit(&targets::rust::EmitInput {
66            schema: &schema,
67            raw_schema_json: &request.schema_json,
68            epoch: request.epoch,
69        })?,
70        Target::Sql => targets::sql::emit(&schema, request.epoch),
71    };
72    Ok(CompiledBinding { content })
73}