Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Type Parameters are not imported #241

Merged
merged 37 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
622afa8
reproduce in E2E test, run example during CI
NyxCode Feb 22, 2024
44998d4
implement proposed fix
NyxCode Feb 22, 2024
9a385d2
adjust impl_wrapper!, fix clippy warning
NyxCode Feb 22, 2024
8c9c2e4
fix CI for example
NyxCode Feb 22, 2024
ee733be
Implement TS::Generics
escritorio-gustavo Feb 23, 2024
90ca381
Add TS::Generics to chrono types
escritorio-gustavo Feb 23, 2024
1ae0341
Add T to impl_wrapper! generics method
escritorio-gustavo Feb 23, 2024
2b7d25b
Proposed fix for Vec, HashMap, Option and Result
escritorio-gustavo Feb 23, 2024
9043961
add test for #168 and #232, expand e2e dependencies test
NyxCode Feb 23, 2024
c24107c
fix tests
NyxCode Feb 23, 2024
f9bba02
rename TS::Generics to TS::WithoutGenerics
NyxCode Feb 23, 2024
438b2ff
cargo +nightly fmt
escritorio-gustavo Feb 26, 2024
8659267
Merge branch 'type-params-are-not-imported' of github.com:Aleph-Alpha…
escritorio-gustavo Feb 26, 2024
02f47b8
cargo +nightly fmt
escritorio-gustavo Feb 26, 2024
2506ff5
Improve atribute parse compiler error
escritorio-gustavo Feb 27, 2024
4aab519
Update tests to use ts(export) except raw_idents
escritorio-gustavo Feb 29, 2024
ffa5113
Separatly update raw_idents as it would panic
escritorio-gustavo Feb 29, 2024
67fe641
Fix usage of serde(skip)
escritorio-gustavo Feb 29, 2024
75d2b7d
Fix usage of serde(skip) again...
escritorio-gustavo Feb 29, 2024
a0cee6c
Fix imports test to work with all features
escritorio-gustavo Feb 29, 2024
3eda16f
Fix issue-70 test to generate valid TS
escritorio-gustavo Feb 29, 2024
fe5b375
cargo fmt
escritorio-gustavo Feb 29, 2024
7bc2c87
Update CI to run tsc
escritorio-gustavo Feb 29, 2024
1da87b5
Fix remaining dependency issues
escritorio-gustavo Feb 29, 2024
f4da385
enable globstar in CI
NyxCode Feb 29, 2024
e179efb
Update changelog
escritorio-gustavo Feb 29, 2024
0367a6b
Merge branch 'type-params-are-not-imported' of github.com:Aleph-Alpha…
escritorio-gustavo Feb 29, 2024
f4572ea
self_referential.rs: Do not rename types
NyxCode Feb 29, 2024
cf01efc
Merge remote-tracking branch 'origin/type-params-are-not-imported' in…
NyxCode Feb 29, 2024
8ea5cf0
Revert "self_referential.rs: Do not rename types"
NyxCode Feb 29, 2024
6e09571
self_referential.rs: Rename types to unique names
NyxCode Feb 29, 2024
22a8edc
Remove ts(export) from self referential internally tagged enum
escritorio-gustavo Feb 29, 2024
ed397da
Add tests for all impl_shadow! types
NyxCode Feb 29, 2024
10c09ad
Implement `TS::generics()` within impl_shadow
NyxCode Feb 29, 2024
2136c75
fix imports for TypeList in macros
NyxCode Feb 29, 2024
a177f89
CI: use tsc --strict in all jobs
NyxCode Feb 29, 2024
535eeff
Test hashmap.rs: Change CustomKey to yield a valid TS Record
NyxCode Feb 29, 2024
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
44 changes: 32 additions & 12 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ jobs:
working-directory: e2e/dependencies/consumer
run: |
cargo t
tsc bindings/* --noEmit
tsc bindings/* --noEmit --noUnusedLocals --strict
- name: dependencies e2e test with default export env
working-directory: e2e/dependencies/consumer
run: |
TS_RS_EXPORT_DIR=custom-bindings cargo t
tsc custom-bindings/* --noEmit
tsc custom-bindings/* --noEmit --noUnusedLocals --strict
e2e-workspace:
name: Run 'workspace' end-to-end test
runs-on: ubuntu-latest
Expand All @@ -31,12 +31,30 @@ jobs:
working-directory: e2e/workspace
run: |
cargo t
tsc parent/bindings/* --noEmit
tsc parent/bindings/* --noEmit --noUnusedLocals --strict
- name: workspace e2e with default export env
working-directory: e2e/workspace
run: |
TS_RS_EXPORT_DIR=custom-bindings cargo t
tsc parent/custom-bindings/* --noEmit
tsc parent/custom-bindings/* --noEmit --noUnusedLocals --strict
e2e-example:
name: End-to-end test example
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: example e2e test
working-directory: example
run: |
cargo t
tsc bindings/* --noEmit
- name: example e2e with default export env
working-directory: example
run: |
TS_RS_EXPORT_DIR=custom-bindings cargo t
tsc custom-bindings/* --noEmit --noUnusedLocals --strict

readme-up-to-date:
name: Check that README.md is up-to-date
Expand All @@ -60,11 +78,13 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --manifest-path ts-rs/Cargo.toml
- uses: actions-rs/cargo@v1
with:
command: test
args: --all-features --manifest-path ts-rs/Cargo.toml
- name: No features
run: |
cargo test --no-default-features
shopt -s globstar
tsc ts-rs/tests-out/**/*.ts --noEmit --noUnusedLocals
- name: All features
run: |
cargo test --all-features
shopt -s globstar
tsc ts-rs/tests-out/**/*.ts --noEmit --noUnusedLocals --strict
19 changes: 13 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
# master

### Breaking
### Breaking

- Export types as `type` instead of `ìnterface` ([#203](https://github.com/Aleph-Alpha/ts-rs/pull/203))
- Automatically export all dependencies when using `#[ts(export)]`, add `TS::dependency_types()` ([#221](https://github.com/Aleph-Alpha/ts-rs/pull/221))
- Remove support for "skip_serializing", "skip_serializing_if" and "skip_deserializing". ([#204](https://github.com/Aleph-Alpha/ts-rs/pull/204))
- Initially supporting these by skipping a field was a mistake. If a user wishes to skip a field, they can still
annotate it with `#[ts(skip)]`

- Initially supporting these by skipping a field was a mistake. If a user wishes to skip a field, they can still
annotate it with `#[ts(skip)]`
- Added `TS::dependency_types()` ([#221](https://github.com/Aleph-Alpha/ts-rs/pull/221))
- Added `TS::generics()` ([#241](https://github.com/Aleph-Alpha/ts-rs/pull/241))
- Added `TS::WithoutGenerics` ([#241](https://github.com/Aleph-Alpha/ts-rs/pull/241))
- `Result`, `Option`, `HashMap` and `Vec` had their implementations of `TS` changed ([#241](https://github.com/Aleph-Alpha/ts-rs/pull/241))

### Features

- Implement `#[ts(as = "..")]` ([#174](https://github.com/Aleph-Alpha/ts-rs/pull/174))
- For small arrays, generate tuples instead of `Array<T>` ([#209](https://github.com/Aleph-Alpha/ts-rs/pull/209))
- Implement `#[ts(optional = nullable)]` ([#213](https://github.com/Aleph-Alpha/ts-rs/pull/213))
- Allow inlining of fields with generic types ([#212](https://github.com/Aleph-Alpha/ts-rs/pull/212), [#215](https://github.com/Aleph-Alpha/ts-rs/pull/215), [#216](https://github.com/Aleph-Alpha/ts-rs/pull/216))
- Allow flattening enum fields ([#206](https://github.com/Aleph-Alpha/ts-rs/pull/206))
- Add `semver-impl` cargo feature with support for the *semver* crate ([#176](https://github.com/Aleph-Alpha/ts-rs/pull/176))
- Add `semver-impl` cargo feature with support for the _semver_ crate ([#176](https://github.com/Aleph-Alpha/ts-rs/pull/176))
- Support `HashMap` with custom hashers ([#173](https://github.com/Aleph-Alpha/ts-rs/pull/173))
- Add `import-esm` cargo feature to import files with a `.js` extension ([#192](https://github.com/Aleph-Alpha/ts-rs/pull/192))
- Implement `#[ts(...)]` equivalents for `#[serde(tag = "...")]`, `#[serde(tag = "...", content = "...")]` and `#[serde(untagged)]` ([#227](https://github.com/Aleph-Alpha/ts-rs/pull/227))
Expand All @@ -22,7 +28,8 @@
- Export Rust doc comments/attributes on structs/enums as TSDoc strings ([#187](https://github.com/Aleph-Alpha/ts-rs/pull/187))

### Fixes

- fix `#[ts(skip)]` and `#[serde(skip)]` in variants of adjacently or internally tagged enums ([#231](https://github.com/Aleph-Alpha/ts-rs/pull/231))
- `rename_all` with `camelCase` produces wrong names if fields were already in camelCase ([#198](https://github.com/Aleph-Alpha/ts-rs/pull/198))
- Improve support for references ([#199](https://github.com/Aleph-Alpha/ts-rs/pull/199))

- Generic type aliases generate correctly ([#233](https://github.com/Aleph-Alpha/ts-rs/pull/233))
12 changes: 12 additions & 0 deletions e2e/dependencies/consumer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ struct ConsumerType {
pub ty2_2: LibraryType2<&'static Self>,
pub ty2_3: LibraryType2<LibraryType2<Box<ConsumerType>>>,
pub ty2_4: LibraryType2<LibraryType2<LibraryType1>>,
pub ty2_5: LibraryType2<LibraryType3>,
}

#[derive(TS)]
#[ts(export)]
struct T0;

#[derive(TS)]
#[ts(export)]
struct T1 {
t0: Option<T0>
}


fn main() {}
3 changes: 3 additions & 0 deletions e2e/dependencies/dependency1/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ pub struct LibraryType1 {
pub struct LibraryType2<T> {
pub t: T
}

#[derive(TS)]
pub struct LibraryType3;
3 changes: 3 additions & 0 deletions macros/src/deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ impl Dependencies {
/// If the type is transparent, then we'll get resolve the child dependencies during runtime.
pub fn push(&mut self, ty: &Type) {
self.0.push(quote![.push::<#ty>()]);
self.0.push(quote![
.extend(<#ty as ts_rs::TS>::generics())
]);
}

pub fn append(&mut self, other: Dependencies) {
Expand Down
73 changes: 58 additions & 15 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use syn::{
TypeParam, WhereClause,
};

use crate::deps::Dependencies;
use crate::utils::format_generics;
use crate::{deps::Dependencies, utils::format_generics};

#[macro_use]
mod utils;
Expand Down Expand Up @@ -47,9 +46,9 @@ impl DerivedTS {
}
};

let export = self.export.then(
|| self.generate_export_test(&rust_ty, &generics)
);
let export = self
.export
.then(|| self.generate_export_test(&rust_ty, &generics));

let docs = match &*self.docs {
"" => None,
Expand All @@ -58,24 +57,28 @@ impl DerivedTS {

let ident = self.ts_name.clone();
let impl_start = generate_impl_block_header(&rust_ty, &generics);
let assoc_type = generate_assoc_type(&rust_ty, &generics);
let name = self.generate_name_fn();
let inline = self.generate_inline_fn();
let decl = self.generate_decl_fn(&rust_ty);
let dependencies = &self.dependencies;
let generics_fn = self.generate_generics_fn();

quote! {
#impl_start {
#assoc_type
const EXPORT_TO: Option<&'static str> = Some(#export_to);

fn ident() -> String {
#ident.to_owned()
}

#get_export_to
#docs
#name
#decl
#inline
#generics_fn

#[allow(clippy::unused_unit)]
fn dependency_types() -> impl ts_rs::typelist::TypeList
Expand Down Expand Up @@ -140,6 +143,7 @@ impl DerivedTS {
}
}
impl TS for #generics {
type WithoutGenerics = #generics;
fn name() -> String { stringify!(#generics).to_owned() }
fn transparent() -> bool { false }
}
Expand All @@ -148,10 +152,11 @@ impl DerivedTS {
}

fn generate_export_test(&self, rust_ty: &Ident, generics: &Generics) -> TokenStream {
let test_fn = format_ident!("export_bindings_{}", rust_ty.to_string().to_lowercase());
let generic_params = generics
.type_params()
.map(|_| quote! { ts_rs::Dummy });
let test_fn = format_ident!(
"export_bindings_{}",
rust_ty.to_string().to_lowercase().replace("r#", "")
);
let generic_params = generics.type_params().map(|_| quote! { ts_rs::Dummy });
let ty = quote!(<#rust_ty<#(#generic_params),*> as ts_rs::TS>);

quote! {
Expand All @@ -163,12 +168,29 @@ impl DerivedTS {
}
}

fn generate_generics_fn(&self) -> TokenStream {
let generics = self
.generics
.type_params()
.map(|TypeParam { ident, .. }| quote![.push::<#ident>().extend(<#ident as ts_rs::TS>::generics())]);
quote! {
#[allow(clippy::unused_unit)]
fn generics() -> impl ts_rs::typelist::TypeList
where
Self: 'static,
{
use ts_rs::typelist::TypeList;
()#(#generics)*
}
}
}

fn generate_name_fn(&self) -> TokenStream {
let name = self.name_with_generics();
quote! {
fn name() -> String {
#name
}
fn name() -> String {
#name
}
}
}

Expand Down Expand Up @@ -211,8 +233,9 @@ impl DerivedTS {
//
// We keep const parameters as they are, since there's no sensible default value we can
// use instead. This might be something to change in the future.
G::Type(TypeParam { ident, .. }) |
G::Const(ConstParam { ident, .. }) => Some(quote!(#ident)),
G::Type(TypeParam { ident, .. }) | G::Const(ConstParam { ident, .. }) => {
Some(quote!(#ident))
}
});
quote! {
fn decl_concrete() -> String {
Expand All @@ -228,6 +251,26 @@ impl DerivedTS {
}
}

fn generate_assoc_type(rust_ty: &Ident, generics: &Generics) -> TokenStream {
use GenericParam as G;

let generics_params = generics
.params
.iter()
.map(|x| match x {
G::Type(_) => quote! { ts_rs::Dummy },
G::Const(ConstParam { ident, .. }) => quote! { #ident },
G::Lifetime(LifetimeParam { lifetime, .. }) => quote! { #lifetime },
})
.collect::<Vec<_>>();

if generics_params.is_empty() {
quote! { type WithoutGenerics = #rust_ty; }
} else {
quote! { type WithoutGenerics = #rust_ty<#(#generics_params),*>; }
}
}

// generate start of the `impl TS for #ty` block, up to (excluding) the open brace
fn generate_impl_block_header(ty: &Ident, generics: &Generics) -> TokenStream {
use GenericParam as G;
Expand Down
9 changes: 3 additions & 6 deletions macros/src/types/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use syn::{Fields, Generics, ItemEnum, Type, Variant};
use crate::{
attr::{EnumAttr, FieldAttr, StructAttr, Tagged, VariantAttr},
deps::Dependencies,
DerivedTS,
types,
types, DerivedTS,
};

pub(crate) fn r#enum_def(s: &ItemEnum) -> syn::Result<DerivedTS> {
Expand Down Expand Up @@ -113,8 +112,6 @@ fn format_variant(
..
} = FieldAttr::from_attrs(&unnamed.unnamed[0].attrs)?;



if skip {
quote!(format!("{{ \"{}\": \"{}\" }}", #tag, #name))
} else {
Expand All @@ -128,7 +125,7 @@ fn format_variant(
(None, None) => {
let ty = &unnamed.unnamed[0].ty;
quote!(<#ty as ts_rs::TS>::name())
},
}
};

quote!(format!("{{ \"{}\": \"{}\", \"{}\": {} }}", #tag, #name, #content, #ty))
Expand Down Expand Up @@ -178,7 +175,7 @@ fn format_variant(
(None, None) => {
let ty = &unnamed.unnamed[0].ty;
quote!(<#ty as ts_rs::TS>::name())
},
}
};

quote!(format!("{{ \"{}\": \"{}\" }} & {}", #tag, #name, #ty))
Expand Down
2 changes: 1 addition & 1 deletion macros/src/types/named.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use syn::{Field, FieldsNamed, GenericArgument, Generics, PathArguments, Result,
use crate::{
attr::{FieldAttr, Inflection, Optional, StructAttr},
deps::Dependencies,
DerivedTS,
utils::{raw_name_to_ts_field, to_ts_ident},
DerivedTS,
};

pub(crate) fn named(
Expand Down
16 changes: 12 additions & 4 deletions macros/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::convert::TryFrom;

use proc_macro2::{Ident, TokenStream};
use syn::{Attribute, Error, Expr, ExprLit, GenericParam, Generics, Lit, Meta, Result, spanned::Spanned};
use quote::quote;
use syn::{
spanned::Spanned, Attribute, Error, Expr, ExprLit, GenericParam, Generics, Lit, Meta, Result,
};

use crate::deps::Dependencies;

macro_rules! syn_err {
Expand All @@ -26,11 +29,16 @@ macro_rules! impl_parse {
fn parse($input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut $out = $i::default();
loop {
let span = $input.span();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting the span before the key improves the location of the error:

Assignment attributes

Before, points at the equals sign:
image

After, points at the attribute's name:
image

Flag attributes:

Before, points at the token after the attribute (close bracket or comma):
image

After, points at the attribute's name:
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it, great work!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Btw, this is the first good look I've had at exactly how impl_parse! works, and I gotta say, I'm definetly using that for every proc_macro I make in the future lol. Awesome job man!

let key: Ident = $input.call(syn::ext::IdentExt::parse_any)?;
match &*key.to_string() {
$($k => $e,)*
#[allow(unreachable_patterns)]
_ => syn_err!($input.span(); "unexpected attribute")
x => syn_err!(
span;
"Unknown attribute \"{x}\". Allowed attributes are: {}",
[$(stringify!($k),)*].join(", ")
Comment on lines +39 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tell the user what attributes are accepted, since LSP autocomplete can't do that

)
}

match $input.is_empty() {
Expand Down Expand Up @@ -65,7 +73,7 @@ pub fn raw_name_to_ts_field(value: String) -> String {
let valid_chars = value
.chars()
.all(|c| c.is_alphanumeric() || c == '_' || c == '$');

let does_not_start_with_digit = value
.chars()
.next()
Expand Down Expand Up @@ -140,7 +148,7 @@ pub fn parse_docs(attrs: &[Attribute]) -> Result<String> {
.map(|attr| {
attr.map(|line| match line.trim() {
"" => " *".to_owned(),
_ => format!(" *{}", line.trim_end())
_ => format!(" *{}", line.trim_end()),
})
})
.collect::<Result<Vec<_>>>()?;
Expand Down
Loading
Loading