Skip to content

Commit

Permalink
Merge branch 'main' into var-name-binding
Browse files Browse the repository at this point in the history
  • Loading branch information
RunDevelopment committed Dec 8, 2024
2 parents 6e5f2e9 + af7c106 commit 5572877
Show file tree
Hide file tree
Showing 62 changed files with 1,708 additions and 1,003 deletions.
18 changes: 17 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- run: rustup update --no-self-update stable && rustup default stable
- run: rustup component add rustfmt
- run: cargo fmt --all -- --check

# Check TOML style by using Taplo.
taplo:
name: Taplo
Expand Down Expand Up @@ -240,6 +240,22 @@ jobs:
# WBINDGEN_I_PROMISE_JS_SYNTAX_WORKS_IN_NODE: 1
# - run: cargo build --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --features "Node Window Document"

# This checks that the output of the CLI is actually valid JavaScript and TypeScript
test_cli_reference_typescript:
name: Run CLI reference TypeScript check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- run: npm i -g typescript
- run: npm i --save @types/node @types/deno
- name: Check TypeScript output
run: tsc --noEmit --skipLibCheck --lib esnext,dom $(echo crates/cli/tests/reference/*.d.ts)
- name: Check JavaScript output
run: tsc --noEmit --skipLibCheck --lib esnext,dom --module esnext --allowJs $(echo crates/cli/tests/reference/*.js)

test_native:
name: Run native tests
runs-on: ubuntu-latest
Expand Down
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
# `wasm-bindgen` Change Log
--------------------------------------------------------------------------------

## Unreleased

### Added

* Add a `copy_to_uninit()` method to all `TypedArray`s. It takes `&mut [MaybeUninit<T>]` and returns `&mut [T]`.
[#4340](https://github.com/rustwasm/wasm-bindgen/pull/4340)

### Changed

* Optional parameters are now typed as `T | undefined | null` to reflect the actual JS behavior.
[#4188](https://github.com/rustwasm/wasm-bindgen/pull/4188)

### Fixed

- Fixed using [JavaScript keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords) as identifiers not being handled correctly.
[#4329](https://github.com/rustwasm/wasm-bindgen/pull/4329)

- Using JS keywords as `struct` and `enum` names will now error at compile time, instead of causing invalid JS code gen.
- Using JS keywords that are not valid to call or access properties on will now error at compile time, instead of causing invalid JS code gen if used as:
1. The first part of a `js_namespace` on imports.
2. The name of an imported type or constant if the type or constant does not have a `js_namespace` or `module` attribute.
3. The name of an imported function if the function is not a method and does not have a `js_namespace` or `module` attribute.
- Using JS keywords on imports in places other than the above will no longer cause the keywords to be escaped as `_{keyword}`.

--------------------------------------------------------------------------------

## [0.2.99](https://github.com/rustwasm/wasm-bindgen/compare/0.2.98...0.2.99)

Released 2024-12-07
Expand Down
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ features = ["serde-serialize"]
test = false

[features]
default = ["spans", "std"]
default = ["std"]
enable-interning = ["std"]
serde-serialize = ["serde", "serde_json", "std"]
spans = ["wasm-bindgen-macro/spans"]
spans = []
std = ["wasm-bindgen-macro/std", "once_cell/std"]

# Whether or not the `#[wasm_bindgen]` macro is strict and generates an error on
# all unused attributes
strict-macro = ["wasm-bindgen-macro/strict-macro"]

# Enables gg-alloc as system allocator when using wasm-bindgen-test to check that large pointers
# INTERNAL ONLY: Enables gg-alloc as system allocator when using wasm-bindgen-test to check that large pointers
# are handled correctly
gg-alloc = ["wasm-bindgen-test/gg-alloc"]

# This is only for debugging wasm-bindgen! No stability guarantees, so enable
# INTERNAL ONLY: This is only for debugging wasm-bindgen! No stability guarantees, so enable
# this at your own peril!
xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_generated_code"]

Expand Down
1 change: 0 additions & 1 deletion crates/backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ version = "0.2.99"
[features]
default = ["std"]
extra-traits = ["syn/extra-traits"]
spans = []
std = []

[dependencies]
Expand Down
43 changes: 33 additions & 10 deletions crates/cli-support/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,13 +324,15 @@ impl<'a, 'b> Builder<'a, 'b> {
let mut ts = String::new();
match ty {
AdapterType::Option(ty) if omittable => {
// e.g. `foo?: string | null`
arg.push_str("?: ");
adapter2ts(ty, &mut ts, Some(&mut ts_refs));
adapter2ts(ty, TypePosition::Argument, &mut ts, Some(&mut ts_refs));
ts.push_str(" | null");
}
ty => {
omittable = false;
arg.push_str(": ");
adapter2ts(ty, &mut ts, Some(&mut ts_refs));
adapter2ts(ty, TypePosition::Argument, &mut ts, Some(&mut ts_refs));
}
}
arg.push_str(&ts);
Expand Down Expand Up @@ -366,7 +368,12 @@ impl<'a, 'b> Builder<'a, 'b> {
let mut ret = String::new();
match result_tys.len() {
0 => ret.push_str("void"),
1 => adapter2ts(&result_tys[0], &mut ret, Some(&mut ts_refs)),
1 => adapter2ts(
&result_tys[0],
TypePosition::Return,
&mut ret,
Some(&mut ts_refs),
),
_ => ret.push_str("[any]"),
}
if asyncness {
Expand Down Expand Up @@ -398,16 +405,18 @@ impl<'a, 'b> Builder<'a, 'b> {
for (name, ty) in fn_arg_names.iter().zip(arg_tys).rev() {
let mut arg = "@param {".to_string();

adapter2ts(ty, &mut arg, None);
arg.push_str("} ");
match ty {
AdapterType::Option(..) if omittable => {
AdapterType::Option(ty) if omittable => {
adapter2ts(ty, TypePosition::Argument, &mut arg, None);
arg.push_str(" | null} ");
arg.push('[');
arg.push_str(name);
arg.push(']');
}
_ => {
omittable = false;
adapter2ts(ty, TypePosition::Argument, &mut arg, None);
arg.push_str("} ");
arg.push_str(name);
}
}
Expand All @@ -419,7 +428,7 @@ impl<'a, 'b> Builder<'a, 'b> {

if let (Some(name), Some(ty)) = (variadic_arg, arg_tys.last()) {
ret.push_str("@param {...");
adapter2ts(ty, &mut ret, None);
adapter2ts(ty, TypePosition::Argument, &mut ret, None);
ret.push_str("} ");
ret.push_str(name);
ret.push('\n');
Expand Down Expand Up @@ -1537,7 +1546,18 @@ impl Invocation {
}
}

fn adapter2ts(ty: &AdapterType, dst: &mut String, refs: Option<&mut HashSet<TsReference>>) {
#[derive(Debug, Clone, Copy)]
enum TypePosition {
Argument,
Return,
}

fn adapter2ts(
ty: &AdapterType,
position: TypePosition,
dst: &mut String,
refs: Option<&mut HashSet<TsReference>>,
) {
match ty {
AdapterType::I32
| AdapterType::S8
Expand All @@ -1559,8 +1579,11 @@ fn adapter2ts(ty: &AdapterType, dst: &mut String, refs: Option<&mut HashSet<TsRe
AdapterType::Bool => dst.push_str("boolean"),
AdapterType::Vector(kind) => dst.push_str(&kind.js_ty()),
AdapterType::Option(ty) => {
adapter2ts(ty, dst, refs);
dst.push_str(" | undefined");
adapter2ts(ty, position, dst, refs);
dst.push_str(match position {
TypePosition::Argument => " | null | undefined",
TypePosition::Return => " | undefined",
});
}
AdapterType::NamedExternref(name) => dst.push_str(name),
AdapterType::Struct(name) => dst.push_str(name),
Expand Down
76 changes: 49 additions & 27 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,18 @@ struct FieldAccessor {
is_optional: bool,
}

/// Different JS constructs that can be exported.
enum ExportJs<'a> {
/// A class of the form `class Name {...}`.
Class(&'a str),
/// An anonymous function expression of the form `function(...) {...}`.
///
/// Note that the function name is not included in the string.
Function(&'a str),
/// An arbitrary JS expression.
Expression(&'a str),
}

const INITIAL_HEAP_VALUES: &[&str] = &["undefined", "null", "true", "false"];
// Must be kept in sync with `src/lib.rs` of the `wasm-bindgen` crate
const INITIAL_HEAP_OFFSET: usize = 128;
Expand Down Expand Up @@ -163,38 +175,46 @@ impl<'a> Context<'a> {
fn export(
&mut self,
export_name: &str,
contents: &str,
export: ExportJs,
comments: Option<&str>,
) -> Result<(), Error> {
let definition_name = self.generate_identifier(export_name);
if contents.starts_with("class") && definition_name != export_name {
if matches!(export, ExportJs::Class(_)) && definition_name != export_name {
bail!("cannot shadow already defined class `{}`", export_name);
}

let contents = contents.trim();
// write out comments
if let Some(c) = comments {
self.globals.push_str(c);
}

let global = match self.config.mode {
OutputMode::Node { module: false } => {
if contents.starts_with("class") {
format!("{}\nmodule.exports.{1} = {1};\n", contents, export_name)
} else {
format!("module.exports.{} = {};\n", export_name, contents)
OutputMode::Node { module: false } => match export {
ExportJs::Class(class) => {
format!("{}\nmodule.exports.{1} = {1};\n", class, export_name)
}
}
OutputMode::NoModules { .. } => {
if contents.starts_with("class") {
format!("{}\n__exports.{1} = {1};\n", contents, export_name)
} else {
format!("__exports.{} = {};\n", export_name, contents)
ExportJs::Function(expr) | ExportJs::Expression(expr) => {
format!("module.exports.{} = {};\n", export_name, expr)
}
}
},
OutputMode::NoModules { .. } => match export {
ExportJs::Class(class) => {
format!("{}\n__exports.{1} = {1};\n", class, export_name)
}
ExportJs::Function(expr) | ExportJs::Expression(expr) => {
format!("__exports.{} = {};\n", export_name, expr)
}
},
OutputMode::Bundler { .. }
| OutputMode::Node { module: true }
| OutputMode::Web
| OutputMode::Deno => {
if let Some(body) = contents.strip_prefix("function") {
| OutputMode::Deno => match export {
ExportJs::Class(class) => {
assert_eq!(export_name, definition_name);
format!("export {}\n", class)
}
ExportJs::Function(function) => {
let body = function.strip_prefix("function").unwrap();
if export_name == definition_name {
format!("export function {}{}\n", export_name, body)
} else {
Expand All @@ -203,14 +223,12 @@ impl<'a> Context<'a> {
definition_name, body, definition_name, export_name,
)
}
} else if contents.starts_with("class") {
assert_eq!(export_name, definition_name);
format!("export {}\n", contents)
} else {
}
ExportJs::Expression(expr) => {
assert_eq!(export_name, definition_name);
format!("export const {} = {};\n", export_name, contents)
format!("export const {} = {};\n", export_name, expr)
}
}
},
};
self.global(&global);
Ok(())
Expand Down Expand Up @@ -1169,10 +1187,10 @@ __wbg_set_wasm(wasm);"

self.write_class_field_types(class, &mut ts_dst);

dst.push_str("}\n");
dst.push('}');
ts_dst.push_str("}\n");

self.export(name, &dst, Some(&class.comments))?;
self.export(name, ExportJs::Class(&dst), Some(&class.comments))?;

if class.generate_typescript {
self.typescript.push_str(&class.comments);
Expand Down Expand Up @@ -2872,7 +2890,11 @@ __wbg_set_wasm(wasm);"
self.typescript.push_str(";\n");
}

self.export(name, &format!("function{}", code), Some(&js_docs))?;
self.export(
name,
ExportJs::Function(&format!("function{}", code)),
Some(&js_docs),
)?;
self.globals.push('\n');
}
AuxExportKind::Constructor(class) => {
Expand Down Expand Up @@ -3995,7 +4017,7 @@ __wbg_set_wasm(wasm);"

self.export(
&enum_.name,
&format!("Object.freeze({{\n{}}})", variants),
ExportJs::Expression(&format!("Object.freeze({{\n{}}})", variants)),
Some(&docs),
)?;

Expand Down
Loading

0 comments on commit 5572877

Please sign in to comment.