Skip to content

Commit

Permalink
Fix invalid typescript generation for empy enums (#23)
Browse files Browse the repository at this point in the history
* Add e2e tests (with purposeful error)
* Allow empty enums
  • Loading branch information
siefkenj authored Apr 11, 2024
1 parent 01de96e commit 011268d
Show file tree
Hide file tree
Showing 19 changed files with 230 additions and 23 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/on-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,18 @@ jobs:
override: true
components: rustfmt

- name: Install wasm-pack
uses: jetli/[email protected]
with:
# Optional version of wasm-pack to install(eg. 'v0.9.1', 'latest')
version: "latest"

- name: Add cargo-expand
run: cargo install cargo-expand

# Run the ./test.sh script
- name: Test
uses: actions-rs/cargo@v1
with:
command: test
run: ./test.sh
lint:
name: Lint
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
Cargo.lock
.vscode
tests-e2e/*/pkg
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tsify-next"
version = "0.5.0"
version = "0.5.1"
edition = "2021"
authors = [
"Madono Haru <[email protected]>",
Expand All @@ -14,7 +14,7 @@ keywords = ["wasm", "wasm-bindgen", "typescript"]
categories = ["wasm"]

[dependencies]
tsify-next-macros = { path = "tsify-next-macros", version = "^0.5" }
tsify-next-macros = { path = "tsify-next-macros", version = "0.5.1" }
wasm-bindgen = { version = "0.2.86", optional = true }
serde = { version = "1.0", optional = true }
serde_json = { version = "1.0", optional = true }
Expand Down Expand Up @@ -50,4 +50,5 @@ json = [
]

[workspace]
members = ["tsify-next-macros"]
members = ["tsify-next-macros", "tests-e2e/*"]
exclude = ["tests-e2e/reference_output"]
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub struct SerializationConfig {
pub large_number_types_as_bigints: bool,
}

/// `Tsify` is a trait that allows you to convert a type to and from JavaScript.
/// Can be implemented manually if you need to customize the serialization or deserialization.
pub trait Tsify {
#[cfg(feature = "wasm-bindgen")]
type JsType: JsCast;
Expand Down
6 changes: 5 additions & 1 deletion test.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ set -ex
cargo test --all
cargo test --all -F js
wasm-pack test --node
wasm-pack test --node -F js
wasm-pack test --node -F js

# Test the end-to-end tests
./tests-e2e/build_all.sh
./tests-e2e/reference_output/compare_output.sh
6 changes: 6 additions & 0 deletions tests-e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# tests-e2e

These tests test the actual `.d.ts` file output by `wasm-pack`. When `wasm-pack build` is run
on a project in one of the sub-folders, a `pkg/` directory will be created. Running `./reference_output/compare_output.sh`
will compare the reference output (stored in a directory match the test name) to that generated in the `pkg/` directory
output by `wasm-pack`.
23 changes: 23 additions & 0 deletions tests-e2e/build_all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

# Define the root directory for the search
ROOT_DIR="tests-e2e"

# Find all Cargo.toml files in the root directory and its direct subdirectories
FILES=$(find "$ROOT_DIR" -maxdepth 2 -name Cargo.toml)

for FILE in $FILES; do
# Get the directory of the file
DIR=$(dirname "$FILE")
# Push the directory onto the stack and change to it
pushd "$DIR" > /dev/null || exit

echo ""
echo "Building in $DIR"
echo ""

# Run wasm-pack build
wasm-pack build
# Pop the directory from the stack and change back to the original directory
popd > /dev/null || exit
done
45 changes: 45 additions & 0 deletions tests-e2e/reference_output/compare_output.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/bash

# Given files <folder>/<file> search for identically named files in `../<folder>/pkg/<file>`
# and compare them. If the files differ, print the differences and return an error exit code.

# Change the current directory to the directory where the script is located
cd "$(dirname "$0")" || exit

DIFF_FOUND=0

# Find all directories in the current directory
for FOLDERNAME in $(find . -maxdepth 1 -type d); do
# Skip the current directory
if [ "$FOLDERNAME" = "." ]; then
continue
fi

# Remove the leading "./" from the folder name
FOLDERNAME="${FOLDERNAME#./}"

# Find all files in the current folder and its subdirectories
FILES=$(find "./${FOLDERNAME}/" -type f)
for FILE in $FILES; do
# Remove the leading "./<foldername>/" from the file path
RELATIVE_PATH="${FILE#./${FOLDERNAME}/}"
# Construct the path to the corresponding file in ../<foldername>/pkg/
OTHER_FILE="../${FOLDERNAME}/pkg/${RELATIVE_PATH}"
# Compare the files
if [ -f "$OTHER_FILE" ]; then
echo "Comparing $FILE with $OTHER_FILE"

# suppress the exit code if the files differ beause we want to print out all differences
DIFF_OUTPUT=$(diff --brief "$FILE" "$OTHER_FILE" || true)
if [ -n "$DIFF_OUTPUT" ]; then
echo " $DIFF_OUTPUT"
diff "$FILE" "$OTHER_FILE"
DIFF_FOUND=1
else
echo " Files are identical"
fi
fi
done
done

exit $DIFF_FOUND
11 changes: 11 additions & 0 deletions tests-e2e/reference_output/test1/test1.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* tslint:disable */
/* eslint-disable */
/**
* @returns {Point}
*/
export function into_js(): Point;
export interface Point {
x: number;
y: number;
}

13 changes: 13 additions & 0 deletions tests-e2e/reference_output/test2/test2.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* tslint:disable */
/* eslint-disable */
/**
* @returns {Point}
*/
export function into_js(): Point;
export interface Point {
x: number;
y: number;
}

export type NullPoint = void;

21 changes: 21 additions & 0 deletions tests-e2e/test1/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "test1"
publish = false
version = "0.1.0"
edition = "2021"

[dependencies]
wasm-bindgen = "0.2"
tsify-next = { path = "../..", version = "*" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[dev-dependencies]
wasm-bindgen-test = "0.3"

[lib]
path = "entry_point.rs"
crate-type = ["cdylib"]

[build-dependencies]
wasm-bindgen-cli = "0.2"
15 changes: 15 additions & 0 deletions tests-e2e/test1/entry_point.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use serde::{Deserialize, Serialize};
use tsify_next::Tsify;
use wasm_bindgen::prelude::*;

#[derive(Tsify, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Point {
x: i32,
y: i32,
}

#[wasm_bindgen]
pub fn into_js() -> Point {
Point { x: 0, y: 0 }
}
21 changes: 21 additions & 0 deletions tests-e2e/test2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "test2"
publish = false
version = "0.1.0"
edition = "2021"

[dependencies]
wasm-bindgen = "0.2"
tsify-next = { path = "../..", version = "*" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[dev-dependencies]
wasm-bindgen-test = "0.3"

[lib]
path = "entry_point.rs"
crate-type = ["cdylib"]

[build-dependencies]
wasm-bindgen-cli = "0.2"
19 changes: 19 additions & 0 deletions tests-e2e/test2/entry_point.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use serde::{Deserialize, Serialize};
use tsify_next::Tsify;
use wasm_bindgen::prelude::*;

#[derive(Tsify, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Point {
x: i32,
y: i32,
}

#[derive(Tsify, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub enum NullPoint {}

#[wasm_bindgen]
pub fn into_js() -> Point {
Point { x: 0, y: 0 }
}
12 changes: 12 additions & 0 deletions tests/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ fn test_externally_tagged_enum() {
assert_eq!(External::DECL, expected);
}

#[test]
fn test_empty_enum() {
#[derive(Tsify)]
enum Empty {}

let expected = indoc! {r#"
export type Empty = void;"#
};

assert_eq!(Empty::DECL, expected);
}

#[test]
fn test_externally_tagged_enum_with_namespace() {
/// Comment for External
Expand Down
2 changes: 1 addition & 1 deletion tsify-next-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tsify-next-macros"
version = "0.5.0"
version = "0.5.1"
edition = "2021"
authors = [
"Madono Haru <[email protected]>",
Expand Down
3 changes: 3 additions & 0 deletions tsify-next-macros/src/decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl Display for TsInterfaceDecl {
}
}

/// A Typescript type resulting from an enum declaration.
#[derive(Debug)]
pub struct TsEnumDecl {
pub id: String,
Expand Down Expand Up @@ -278,6 +279,8 @@ impl Display for TsEnumDecl {
}
}

/// A typescript type declaration. For example `type Foo = string;`
/// or `interface Bar { baz: number; }`
#[allow(clippy::enum_variant_names)]
pub enum Decl {
TsTypeAlias(TsTypeAliasDecl),
Expand Down
1 change: 1 addition & 0 deletions tsify-next-macros/src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub fn expand(input: DeriveInput) -> syn::Result<TokenStream> {
Ok(tokens)
}

/// Expand an `enum` or `struct` with `#[derive(Tsify)]`.
pub fn expand_by_attr(args: TokenStream, input: DeriveInput) -> syn::Result<TokenStream> {
let mut cloned_input = input.clone();
let attr: syn::Attribute = parse_quote!(#[tsify(#args)]);
Expand Down
34 changes: 19 additions & 15 deletions tsify-next-macros/src/typescript/ts_type_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,23 +91,27 @@ impl Display for TsType {
write!(f, "{types}")
}

TsType::Union(types) => {
if types.len() == 1 {
TsType::Union(types) => match types.len() {
0 => {
write!(f, "void")
}
1 => {
let ty = &types[0];
return write!(f, "{ty}");
write!(f, "{ty}")
}

let types = types
.iter()
.map(|ty| match ty {
TsType::Intersection(_) => format!("({ty})"),
_ => ty.to_string(),
})
.collect::<Vec<_>>()
.join(" | ");

write!(f, "{types}")
}
_ => {
let types = types
.iter()
.map(|ty| match ty {
TsType::Intersection(_) => format!("({ty})"),
_ => ty.to_string(),
})
.collect::<Vec<_>>()
.join(" | ");

write!(f, "{types}")
}
},

TsType::Override { type_override, .. } => f.write_str(type_override),
}
Expand Down

0 comments on commit 011268d

Please sign in to comment.