Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
099b38d
wip
oscartbeaumont Dec 8, 2025
f0ca86d
wip
oscartbeaumont Dec 8, 2025
2ffe468
wip
oscartbeaumont Dec 8, 2025
e2a7227
wip
oscartbeaumont Dec 8, 2025
5de55fd
wip
oscartbeaumont Dec 8, 2025
e0f4cc1
prefix?
oscartbeaumont Dec 8, 2025
29a327f
wip
oscartbeaumont Dec 8, 2025
29fbcd9
wip
oscartbeaumont Dec 8, 2025
a493fe5
docs for `typedef`
oscartbeaumont Dec 8, 2025
95e6ca3
seal `JSDoc`
oscartbeaumont Dec 8, 2025
7ed840b
random incomplete jsdoc changes
oscartbeaumont Dec 8, 2025
5a82380
better export header
oscartbeaumont Dec 8, 2025
024eb1c
wip: exporter references + reference overhaul
oscartbeaumont Dec 15, 2025
e02c5dc
rename formats to layouts
oscartbeaumont Dec 15, 2025
fd45263
fix layout tests
oscartbeaumont Dec 15, 2025
adcf3e2
bring back `TypeCollection: Clone`
oscartbeaumont Dec 15, 2025
b5fb1e4
wip
oscartbeaumont Dec 15, 2025
52254b6
remove `NamedType`
oscartbeaumont Dec 15, 2025
b35a11e
wip: remove `SpectaID`
oscartbeaumont Dec 15, 2025
4edb577
wip
oscartbeaumont Dec 15, 2025
f680a43
wip: get back to compiling
oscartbeaumont Dec 15, 2025
cbb9812
wip
oscartbeaumont Dec 16, 2025
b2e415e
drop `DataType::Literal`
oscartbeaumont Dec 16, 2025
e469312
reference overhaul is working?
oscartbeaumont Dec 16, 2025
4745c0b
hookup framework runtime + more fixes
oscartbeaumont Dec 16, 2025
9064e48
bring back namespace exporting
oscartbeaumont Dec 16, 2025
e37fa49
making things compile + uncomment stuff
oscartbeaumont Dec 18, 2025
33a88fa
restore some JSDoc support
oscartbeaumont Dec 18, 2025
d829901
drop references example
oscartbeaumont Dec 18, 2025
b71d6eb
cleanup
oscartbeaumont Dec 18, 2025
e98ddc1
cleanup docs
oscartbeaumont Dec 18, 2025
4e2fe8d
fix `PhantomData`
oscartbeaumont Dec 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions specta-jsonschema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use std::path::Path;

use schemars::schema::{InstanceType, Schema, SingleOrVec};
use specta::{
datatype::{DataType, Enum, EnumVariant, Field, List, Literal, Primitive, Struct},
TypeCollection,
datatype::{DataType, Field, List, Primitive, Struct},
};

#[derive(Debug, Clone)]
Expand All @@ -34,7 +34,7 @@ pub fn to_ast(schema: &Schema) -> Result<DataType, ()> {
let mut types = TypeCollection::default();

match schema {
Schema::Bool(b) => Ok(DataType::Literal((*b).into())),
Schema::Bool(b) => todo!(), // Ok(DataType::Literal((*b).into())),
Schema::Object(obj) => {
// TODO: Implement it all
// /// Properties which annotate the [`SchemaObject`] which typically have no effect when an object is being validated against the schema.
Expand Down Expand Up @@ -160,7 +160,7 @@ pub fn to_ast(schema: &Schema) -> Result<DataType, ()> {

fn from_instance_type(o: &InstanceType) -> DataType {
match o {
InstanceType::Null => DataType::Literal(Literal::None),
InstanceType::Null => todo!(), // DataType::Literal(Literal::None),
InstanceType::Boolean => DataType::Primitive(Primitive::bool),
InstanceType::Object => unreachable!(),
InstanceType::Array => unreachable!(),
Expand Down
13 changes: 7 additions & 6 deletions specta-macros/src/specta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
use std::str::FromStr;

use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse, FnArg, ItemFn, Pat, Visibility};
use quote::{ToTokens, quote};
use syn::{FnArg, ItemFn, Pat, Visibility, parse};

use crate::utils::{format_fn_wrapper, parse_attrs};

Expand Down Expand Up @@ -57,7 +57,7 @@ pub fn attribute(item: proc_macro::TokenStream) -> syn::Result<proc_macro::Token
return Err(syn::Error::new_spanned(
input,
"functions with `#[specta]` cannot take 'self'",
))
));
}
FnArg::Typed(arg) => match &*arg.pat {
Pat::Ident(ident) => ident.ident.to_token_stream(),
Expand All @@ -69,7 +69,7 @@ pub fn attribute(item: proc_macro::TokenStream) -> syn::Result<proc_macro::Token
return Err(syn::Error::new_spanned(
input,
"functions with `#[specta]` must take named arguments",
))
));
}
},
};
Expand All @@ -90,7 +90,7 @@ pub fn attribute(item: proc_macro::TokenStream) -> syn::Result<proc_macro::Token
let mut attrs = parse_attrs(&function.attrs)?;
let common = crate::r#type::attr::CommonAttr::from_attrs(&mut attrs)?;

let deprecated = common.deprecated_as_tokens(&crate_ref);
let deprecated = common.deprecated_as_tokens();
let docs = common.doc;

let no_return_type = match function.sig.output {
Expand All @@ -106,7 +106,8 @@ pub fn attribute(item: proc_macro::TokenStream) -> syn::Result<proc_macro::Token
macro_rules! #wrapper {
// We take in `$function` from the invocation so we have `fn_name::<concrete_generics_types>`
(@export_fn; $function:path) => {{
fn export(types: &mut #crate_ref::TypeCollection) -> #crate_ref::datatype::Function {
use #crate_ref::datatype;
fn export(types: &mut #crate_ref::TypeCollection) -> datatype::Function {
#crate_ref::internal::get_fn_datatype(
$function as fn(#(#arg_signatures),*) -> _,
#function_asyncness,
Expand Down
9 changes: 3 additions & 6 deletions specta-macros/src/type/attr/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,21 +99,18 @@ impl CommonAttr {
Ok(CommonAttr { doc, deprecated })
}

pub fn deprecated_as_tokens(
&self,
crate_ref: &proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
pub fn deprecated_as_tokens(&self) -> proc_macro2::TokenStream {
match &self.deprecated {
Some(DeprecatedType::Deprecated) => {
quote!(Some(#crate_ref::datatype::DeprecatedType::Deprecated))
quote!(Some(datatype::DeprecatedType::Deprecated))
}
Some(DeprecatedType::DeprecatedWithSince { since, note }) => {
let since = since
.as_ref()
.map(|v| quote!(#v.into()))
.unwrap_or(quote!(None));

quote!(Some(#crate_ref::datatype::DeprecatedType::DeprecatedWithSince {
quote!(Some(datatype::DeprecatedType::DeprecatedWithSince {
since: #since,
note: #note.into(),
}))
Expand Down
32 changes: 16 additions & 16 deletions specta-macros/src/type/enum.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use super::{attr::*, r#struct::decode_field_attrs};
use crate::{r#type::field::construct_field, utils::*};
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use syn::{spanned::Spanned, DataEnum, Error, Fields};
use quote::{ToTokens, quote};
use syn::{DataEnum, Error, Fields, spanned::Spanned};

pub fn parse_enum(
enum_attrs: &EnumAttr,
Expand Down Expand Up @@ -59,7 +59,7 @@ pub fn parse_enum(
};

let inner = match &variant.fields {
Fields::Unit => quote!(#crate_ref::internal::construct::fields_unit()),
Fields::Unit => quote!(internal::construct::fields_unit()),
Fields::Unnamed(fields) => {
let fields = fields
.unnamed
Expand All @@ -79,7 +79,7 @@ pub fn parse_enum(
})
.collect::<syn::Result<Vec<TokenStream>>>()?;

quote!(#crate_ref::internal::construct::fields_unnamed(
quote!(internal::construct::fields_unnamed(
vec![#(#fields),*],
))
}
Expand Down Expand Up @@ -115,14 +115,14 @@ pub fn parse_enum(
})
.collect::<syn::Result<Vec<TokenStream>>>()?;

quote!(#crate_ref::internal::construct::fields_named(vec![#(#fields),*], None))
quote!(internal::construct::fields_named(vec![#(#fields),*], None))
}
};

let deprecated = attrs.common.deprecated_as_tokens(crate_ref);
let deprecated = attrs.common.deprecated_as_tokens();
let skip = attrs.skip;
let doc = attrs.common.doc;
Ok(quote!((#variant_name_str.into(), #crate_ref::internal::construct::enum_variant(#skip, #deprecated, #doc.into(), #inner))))
Ok(quote!((#variant_name_str.into(), internal::construct::enum_variant(#skip, #deprecated, #doc.into(), #inner))))
})
.collect::<syn::Result<Vec<_>>>()?;

Expand Down Expand Up @@ -158,7 +158,7 @@ pub fn parse_enum(

(
false, // String enums can't be flattened
quote!(Some(#crate_ref::datatype::EnumRepr::String { rename_all: #rename_all })),
quote!(Some(datatype::EnumRepr::String { rename_all: #rename_all })),
)
} else {
match (enum_attrs.untagged, &enum_attrs.tag, &enum_attrs.content) {
Expand All @@ -178,47 +178,47 @@ pub fn parse_enum(
Fields::Named(_) => true,
_ => false,
}),
quote!(Some(#crate_ref::datatype::EnumRepr::External)),
quote!(Some(datatype::EnumRepr::External)),
),
(Some(false) | None, Some(tag), None) => (
data.variants
.iter()
.any(|v| matches!(&v.fields, Fields::Unit | Fields::Named(_))),
quote!(Some(#crate_ref::datatype::EnumRepr::Internal { tag: #tag.into() })),
quote!(Some(datatype::EnumRepr::Internal { tag: #tag.into() })),
),
(Some(false) | None, Some(tag), Some(content)) => (
true,
quote!(Some(#crate_ref::datatype::EnumRepr::Adjacent { tag: #tag.into(), content: #content.into() })),
quote!(Some(datatype::EnumRepr::Adjacent { tag: #tag.into(), content: #content.into() })),
),
(Some(true), None, None) => (
data.variants
.iter()
.any(|v| matches!(&v.fields, Fields::Unit | Fields::Named(_))),
quote!(Some(#crate_ref::datatype::EnumRepr::Untagged)),
quote!(Some(datatype::EnumRepr::Untagged)),
),
(Some(true), Some(_), None) => {
return Err(Error::new(
Span::call_site(),
"untagged cannot be used with tag",
))
));
}
(Some(true), _, Some(_)) => {
return Err(Error::new(
Span::call_site(),
"untagged cannot be used with content",
))
));
}
(Some(false) | None, None, Some(_)) => {
return Err(Error::new(
Span::call_site(),
"content cannot be used without tag",
))
));
}
}
};

Ok((
quote!(#crate_ref::datatype::DataType::Enum(#crate_ref::internal::construct::r#enum(#repr, vec![#(#variant_types),*]))),
quote!(datatype::DataType::Enum(internal::construct::r#enum(#repr, vec![#(#variant_types),*]))),
can_flatten,
))
}
6 changes: 3 additions & 3 deletions specta-macros/src/type/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ pub fn construct_field(
field_ty: &Type,
) -> TokenStream {
let field_ty = attrs.r#type.as_ref().unwrap_or(&field_ty);
let deprecated = attrs.common.deprecated_as_tokens(crate_ref);
let deprecated = attrs.common.deprecated_as_tokens();
let optional = attrs.optional;
let doc = attrs.common.doc;
let flatten = attrs.flatten;
let inline = container_attrs.inline || attrs.inline;

// Skip must be handled by the macro so that we don't try and constrain the inner type to `Type` or `Flatten` traits.
if attrs.skip {
return quote!(#crate_ref::internal::construct::skipped_field(
return quote!(internal::construct::skipped_field(
#optional,
#flatten,
#inline,
Expand All @@ -33,7 +33,7 @@ pub fn construct_field(
.flatten
.then(|| quote!(field_flattened))
.unwrap_or_else(|| quote!(field));
let ty = quote!(#crate_ref::internal::construct::#method::<#field_ty>(
let ty = quote!(internal::construct::#method::<#field_ty>(
#optional,
#inline,
#deprecated,
Expand Down
75 changes: 36 additions & 39 deletions specta-macros/src/type/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use attr::*;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};
use r#enum::parse_enum;
use proc_macro2::TokenStream;
use quote::{ToTokens, format_ident, quote};
use r#struct::parse_struct;
use syn::{parse, Data, DeriveInput, GenericParam};
use syn::{Data, DeriveInput, GenericParam, parse};

use crate::utils::{parse_attrs, unraw_raw_ident, AttributeValue};
use crate::utils::{AttributeValue, parse_attrs, unraw_raw_ident};

use self::generics::{
add_type_to_where_clause, generics_with_ident_and_bounds_only, generics_with_ident_only,
Expand Down Expand Up @@ -76,7 +76,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
return Err(syn::Error::new(
attrs.key.span(),
"specta: invalid formatted attribute",
))
));
}
}
}
Expand All @@ -92,10 +92,6 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
}
});

// if container_attrs.inline || container_attrs.transparent {
// let generics = &generics.params;
// quote!(#generics)
// } else {
let shadow_generics = {
let g = generics.params.iter().map(|param| match param {
// Pulled from outside
Expand All @@ -104,7 +100,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
GenericParam::Type(t) => {
let ident = &t.ident;
let placeholder_ident = format_ident!("PLACEHOLDER_{}", t.ident);
quote!(type #ident = #crate_ref::datatype::GenericPlaceholder<#placeholder_ident>;)
quote!(type #ident = datatype::GenericPlaceholder<#placeholder_ident>;)
}
});

Expand All @@ -118,7 +114,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
let ident_str = t.ident.to_string();
Some(quote!(
pub struct #ident;
impl #crate_ref::datatype::ConstGenericPlaceholder for #ident {
impl datatype::ConstGenericPlaceholder for #ident {
const PLACEHOLDER: &'static str = #ident_str;
}
))
Expand Down Expand Up @@ -146,14 +142,14 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt

let comments = &container_attrs.common.doc;
let inline = container_attrs.inline;
let deprecated = container_attrs.common.deprecated_as_tokens(&crate_ref);
let deprecated = container_attrs.common.deprecated_as_tokens();

let reference_generics = generics.params.iter().filter_map(|param| match param {
GenericParam::Lifetime(_) | GenericParam::Const(_) => None,
GenericParam::Type(t) => {
let i = &t.ident;
let i_str = i.to_string();
Some(quote!((#crate_ref::internal::construct::generic_data_type(#i_str), <#i as #crate_ref::Type>::definition(types))))
Some(quote!((internal::construct::generic_data_type(#i_str), <#i as #crate_ref::Type>::definition(types))))
}
});

Expand All @@ -168,41 +164,42 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
Ok(quote! {
#[allow(non_camel_case_types)]
const _: () = {
// This is equivalent to `<Self as #crate_ref::NamedType>::ID` but it's shorter so we use it instead.
const SID: #crate_ref::SpectaID = #crate_ref::internal::construct::sid(#name, concat!("::", module_path!(), ":", line!(), ":", column!()));

#(#generic_placeholders)*
use std::borrow::Cow;
use #crate_ref::{datatype, internal};

#[automatically_derived]
impl #bounds #crate_ref::Type for #ident #type_args #where_bound {
fn definition(types: &mut #crate_ref::TypeCollection) -> #crate_ref::datatype::DataType {
#crate_ref::internal::register(
types,
#name.into(),
#comments.into(),
#deprecated,
SID,
std::borrow::Cow::Borrowed(module_path!()),
vec![#(#definition_generics),*],
|types| {
#shadow_generics
#inlines
},
);

#crate_ref::datatype::Reference::construct(SID, [#(#reference_generics),*], #inline).into()
fn definition(types: &mut #crate_ref::TypeCollection) -> datatype::DataType {
#(#generic_placeholders)*

static SENTINEL: () = ();
datatype::DataType::Reference(
datatype::NamedDataType::init_with_sentinel(
vec![#(#reference_generics),*],
#inline,
types,
&SENTINEL,
|types, ndt| {
ndt.set_name(Cow::Borrowed(#name));
ndt.set_docs(Cow::Borrowed(#comments));
ndt.set_deprecated(#deprecated);
ndt.set_module_path(Cow::Borrowed(module_path!()));
*ndt.generics_mut() = vec![#(#definition_generics),*];
ndt.set_ty({
#shadow_generics
#inlines
});
}
)
)
}
}

#[automatically_derived]
impl #bounds #crate_ref::NamedType for #ident #type_args #where_bound {
const ID: #crate_ref::SpectaID = SID;
}

#flatten_impl

#export
};

}.into())
}
.into())
}
Loading
Loading