Restore approved state (tree of 4effcc7 "Added LICENSE")
Roll the working tree back to the last approved shape, before the post-LICENSE span that false-greened the AFI parity matrix with symbol-presence probes and smuggled an unauthorized SQLAlchemy dependency into FastAPI's Shapes binding.
Forward commit, not a history rewrite — the six commits since 4effcc7 stay in the log as the record of what happened.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -165,7 +165,6 @@ fn ts_type_expression(shape: &TypeShape) -> String {
|
||||
.map(ts_type_expression)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" | "),
|
||||
TypeShape::Upload(_) => "File".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,9 +118,6 @@ fn py_type_expression(shape: &TypeShape) -> String {
|
||||
.map(py_type_expression)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" | "),
|
||||
// The Python (PyO3) client is a consumer, not an upload origin; a file
|
||||
// input surfaces as raw bytes on this target.
|
||||
TypeShape::Upload(_) => "bytes".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -440,8 +440,5 @@ fn rust_type_from_shape(shape: &TypeShape, ctx: &mut EnumCtx) -> String {
|
||||
// Value so the consumer can match on the runtime variant.
|
||||
"serde_json::Value".to_string()
|
||||
}
|
||||
// The Rust adapter does not yet wire multipart; a file input surfaces
|
||||
// as raw bytes until upload dispatch lands on this target.
|
||||
TypeShape::Upload(_) => "Vec<u8>".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,6 +296,5 @@ fn ts_type_expression(shape: &TypeShape) -> String {
|
||||
.map(ts_type_expression)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" | "),
|
||||
TypeShape::Upload(_) => "File".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,15 +46,6 @@ pub enum TypeShape {
|
||||
Enum(Vec<String>),
|
||||
/// Multi-arm union with two or more non-null branches.
|
||||
Union(Vec<TypeShape>),
|
||||
/// Binary file input. Carries the declarative `File(...)` constraints.
|
||||
Upload(UploadConstraints),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct UploadConstraints {
|
||||
pub max_size: Option<u64>,
|
||||
pub content_types: Vec<String>,
|
||||
}
|
||||
|
||||
|
||||
@@ -282,7 +273,6 @@ fn parse_type_shape(node: &KdlNode) -> Result<TypeShape> {
|
||||
"list" => Ok(TypeShape::List(Box::new(type_child_of(node, "list")?))),
|
||||
"optional" => Ok(TypeShape::Optional(Box::new(type_child_of(node, "optional")?))),
|
||||
"enum" => Ok(TypeShape::Enum(parse_string_args(node))),
|
||||
"upload" => Ok(TypeShape::Upload(parse_upload_constraints(node))),
|
||||
"union" => {
|
||||
let children = node.children()
|
||||
.ok_or_else(|| anyhow!("union: missing children"))?;
|
||||
@@ -295,20 +285,6 @@ fn parse_type_shape(node: &KdlNode) -> Result<TypeShape> {
|
||||
}
|
||||
|
||||
|
||||
fn parse_upload_constraints(node: &KdlNode) -> UploadConstraints {
|
||||
let max_size = node.entry("max-size")
|
||||
.and_then(|e| e.value().as_integer())
|
||||
.map(|i| i as u64);
|
||||
let content_types = node.children()
|
||||
.map(|children| children.nodes().iter()
|
||||
.filter(|n| n.name().value() == "content-type")
|
||||
.filter_map(|n| first_string_arg(n).ok())
|
||||
.collect())
|
||||
.unwrap_or_default();
|
||||
UploadConstraints { max_size, content_types }
|
||||
}
|
||||
|
||||
|
||||
fn parse_function(node: &KdlNode) -> Result<MizanFunction> {
|
||||
let name = first_string_arg(node)
|
||||
.context("`function` requires a name as its first argument")?;
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
//! Upload type-shape lowers to TS `File` across cardinalities. Separate from
|
||||
//! the byte-parity baselines (which mustn't carry an upload field — the
|
||||
//! three-way AFI parity gate includes the Rust adapter, which doesn't wire
|
||||
//! uploads yet).
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use mizan_codegen::config::{Config, SourceConfig};
|
||||
use mizan_codegen::emit::stage1::Stage1;
|
||||
use mizan_codegen::emit::CodegenTarget;
|
||||
use mizan_codegen::fetch::parse_ir_from_str;
|
||||
|
||||
|
||||
const UPLOAD_IR: &str = r#"
|
||||
type "SetAvatarInput" {
|
||||
struct {
|
||||
field "user_id" {
|
||||
primitive "integer"
|
||||
}
|
||||
field "avatar" {
|
||||
upload max-size=5242880 {
|
||||
content-type "image/png"
|
||||
content-type "image/jpeg"
|
||||
}
|
||||
}
|
||||
field "photos" {
|
||||
list {
|
||||
upload
|
||||
}
|
||||
}
|
||||
field "thumb" required=#false {
|
||||
optional {
|
||||
upload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
type "setAvatarOutput" {
|
||||
alias {
|
||||
primitive "string"
|
||||
}
|
||||
}
|
||||
function "set_avatar" {
|
||||
camel "setAvatar"
|
||||
has-input #true
|
||||
input "SetAvatarInput"
|
||||
output "setAvatarOutput"
|
||||
transport "http"
|
||||
affects "user"
|
||||
}
|
||||
"#;
|
||||
|
||||
|
||||
fn cfg() -> Config {
|
||||
Config {
|
||||
project_id: None,
|
||||
output: PathBuf::from("/tmp"),
|
||||
targets: vec!["stage1".to_string()],
|
||||
source: SourceConfig { fastapi: None, django: None, rust: None, script: None },
|
||||
rust_kernel: None,
|
||||
rust_crate_name: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn upload_fields_lower_to_file_type() {
|
||||
let ir = parse_ir_from_str(UPLOAD_IR).expect("upload IR parses");
|
||||
let files = Stage1.emit(&ir, &cfg());
|
||||
let types = files
|
||||
.iter()
|
||||
.find(|f| f.rel_path.to_string_lossy().contains("types.ts"))
|
||||
.expect("types.ts emitted");
|
||||
let src = &types.content;
|
||||
|
||||
assert!(src.contains("avatar: File"), "required upload → File:\n{src}");
|
||||
assert!(src.contains("File[]"), "list[upload] → File[]:\n{src}");
|
||||
assert!(src.contains("File | null"), "optional upload → File | null:\n{src}");
|
||||
}
|
||||
Reference in New Issue
Block a user