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

Better TS type formatting for array types #4346

Merged
merged 2 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion crates/cli-support/src/descriptor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::char;

use crate::js::identifier::is_valid_ident;

macro_rules! tys {
($($a:ident)*) => (tys! { @ ($($a)*) 0 });
(@ () $v:expr) => {};
Expand Down Expand Up @@ -306,7 +308,11 @@ impl VectorKind {
VectorKind::F64 => "Float64Array".to_string(),
VectorKind::Externref => "any[]".to_string(),
VectorKind::NamedExternref(ref name) => {
format!("({})[]", name)
if is_valid_ident(name.as_str()) {
format!("{}[]", name)
} else {
format!("({})[]", name)
}
}
}
}
Expand Down
42 changes: 42 additions & 0 deletions crates/cli-support/src/js/identifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/// Returns whether a character has the Unicode `ID_Start` properly.
///
/// This is only ever-so-slightly different from `XID_Start` in a few edge
/// cases, so we handle those edge cases manually and delegate everything else
/// to `unicode-ident`.
fn is_id_start(c: char) -> bool {
match c {
'\u{037A}' | '\u{0E33}' | '\u{0EB3}' | '\u{309B}' | '\u{309C}' | '\u{FC5E}'
| '\u{FC5F}' | '\u{FC60}' | '\u{FC61}' | '\u{FC62}' | '\u{FC63}' | '\u{FDFA}'
| '\u{FDFB}' | '\u{FE70}' | '\u{FE72}' | '\u{FE74}' | '\u{FE76}' | '\u{FE78}'
| '\u{FE7A}' | '\u{FE7C}' | '\u{FE7E}' | '\u{FF9E}' | '\u{FF9F}' => true,
_ => unicode_ident::is_xid_start(c),
}
}

/// Returns whether a character has the Unicode `ID_Continue` properly.
///
/// This is only ever-so-slightly different from `XID_Continue` in a few edge
/// cases, so we handle those edge cases manually and delegate everything else
/// to `unicode-ident`.
fn is_id_continue(c: char) -> bool {
match c {
'\u{037A}' | '\u{309B}' | '\u{309C}' | '\u{FC5E}' | '\u{FC5F}' | '\u{FC60}'
| '\u{FC61}' | '\u{FC62}' | '\u{FC63}' | '\u{FDFA}' | '\u{FDFB}' | '\u{FE70}'
| '\u{FE72}' | '\u{FE74}' | '\u{FE76}' | '\u{FE78}' | '\u{FE7A}' | '\u{FE7C}'
| '\u{FE7E}' => true,
_ => unicode_ident::is_xid_continue(c),
}
}

/// Returns whether a string is a valid JavaScript identifier.
/// Defined at https://tc39.es/ecma262/#prod-IdentifierName.
pub fn is_valid_ident(name: &str) -> bool {
!name.is_empty()
&& name.chars().enumerate().all(|(i, char)| {
if i == 0 {
is_id_start(char) || char == '$' || char == '_'
} else {
is_id_continue(char) || char == '$' || char == '\u{200C}' || char == '\u{200D}'
}
})
}
44 changes: 2 additions & 42 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::wit::{JsImport, JsImportName, NonstandardWitSection, WasmBindgenAux};
use crate::{reset_indentation, Bindgen, EncodeInto, OutputMode, PLACEHOLDER_MODULE};
use anyhow::{anyhow, bail, Context as _, Error};
use binding::TsReference;
use identifier::is_valid_ident;
use std::borrow::Cow;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::fmt;
Expand All @@ -19,6 +20,7 @@ use std::path::{Path, PathBuf};
use walrus::{FunctionId, ImportId, MemoryId, Module, TableId, ValType};

mod binding;
pub mod identifier;

pub struct Context<'a> {
globals: String,
Expand Down Expand Up @@ -4535,48 +4537,6 @@ fn require_class<'a>(
.or_default()
}

/// Returns whether a character has the Unicode `ID_Start` properly.
///
/// This is only ever-so-slightly different from `XID_Start` in a few edge
/// cases, so we handle those edge cases manually and delegate everything else
/// to `unicode-ident`.
fn is_id_start(c: char) -> bool {
match c {
'\u{037A}' | '\u{0E33}' | '\u{0EB3}' | '\u{309B}' | '\u{309C}' | '\u{FC5E}'
| '\u{FC5F}' | '\u{FC60}' | '\u{FC61}' | '\u{FC62}' | '\u{FC63}' | '\u{FDFA}'
| '\u{FDFB}' | '\u{FE70}' | '\u{FE72}' | '\u{FE74}' | '\u{FE76}' | '\u{FE78}'
| '\u{FE7A}' | '\u{FE7C}' | '\u{FE7E}' | '\u{FF9E}' | '\u{FF9F}' => true,
_ => unicode_ident::is_xid_start(c),
}
}

/// Returns whether a character has the Unicode `ID_Continue` properly.
///
/// This is only ever-so-slightly different from `XID_Continue` in a few edge
/// cases, so we handle those edge cases manually and delegate everything else
/// to `unicode-ident`.
fn is_id_continue(c: char) -> bool {
match c {
'\u{037A}' | '\u{309B}' | '\u{309C}' | '\u{FC5E}' | '\u{FC5F}' | '\u{FC60}'
| '\u{FC61}' | '\u{FC62}' | '\u{FC63}' | '\u{FDFA}' | '\u{FDFB}' | '\u{FE70}'
| '\u{FE72}' | '\u{FE74}' | '\u{FE76}' | '\u{FE78}' | '\u{FE7A}' | '\u{FE7C}'
| '\u{FE7E}' => true,
_ => unicode_ident::is_xid_continue(c),
}
}

/// Returns whether a string is a valid JavaScript identifier.
/// Defined at https://tc39.es/ecma262/#prod-IdentifierName.
fn is_valid_ident(name: &str) -> bool {
name.chars().enumerate().all(|(i, char)| {
if i == 0 {
is_id_start(char) || char == '$' || char == '_'
} else {
is_id_continue(char) || char == '$' || char == '\u{200C}' || char == '\u{200D}'
}
})
}

/// Returns a string to tack on to the end of an expression to access a
/// property named `name` of the object that expression resolves to.
///
Expand Down
8 changes: 4 additions & 4 deletions crates/cli/tests/reference/echo.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export function echo_vec_uninit_u32(a: Uint32Array): Uint32Array;
export function echo_vec_uninit_i32(a: Int32Array): Int32Array;
export function echo_vec_uninit_u64(a: BigUint64Array): BigUint64Array;
export function echo_vec_uninit_i64(a: BigInt64Array): BigInt64Array;
export function echo_vec_string(a: (string)[]): (string)[];
export function echo_vec_string(a: string[]): string[];
export function echo_struct(a: Foo): Foo;
export function echo_vec_struct(a: (Foo)[]): (Foo)[];
export function echo_vec_struct(a: Foo[]): Foo[];
export function echo_option_u8(a?: number | null): number | undefined;
export function echo_option_i8(a?: number | null): number | undefined;
export function echo_option_u16(a?: number | null): number | undefined;
Expand Down Expand Up @@ -69,9 +69,9 @@ export function echo_option_vec_uninit_u32(a?: Uint32Array | null): Uint32Array
export function echo_option_vec_uninit_i32(a?: Int32Array | null): Int32Array | undefined;
export function echo_option_vec_uninit_u64(a?: BigUint64Array | null): BigUint64Array | undefined;
export function echo_option_vec_uninit_i64(a?: BigInt64Array | null): BigInt64Array | undefined;
export function echo_option_vec_string(a?: (string)[] | null): (string)[] | undefined;
export function echo_option_vec_string(a?: string[] | null): string[] | undefined;
export function echo_option_struct(a?: Foo | null): Foo | undefined;
export function echo_option_vec_struct(a?: (Foo)[] | null): (Foo)[] | undefined;
export function echo_option_vec_struct(a?: Foo[] | null): Foo[] | undefined;
export class Foo {
private constructor();
free(): void;
Expand Down
16 changes: 8 additions & 8 deletions crates/cli/tests/reference/echo.js
Original file line number Diff line number Diff line change
Expand Up @@ -685,8 +685,8 @@ function getArrayJsValueFromWasm0(ptr, len) {
return result;
}
/**
* @param {(string)[]} a
* @returns {(string)[]}
* @param {string[]} a
* @returns {string[]}
*/
export function echo_vec_string(a) {
const ptr0 = passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
Expand Down Expand Up @@ -714,8 +714,8 @@ export function echo_struct(a) {
}

/**
* @param {(Foo)[]} a
* @returns {(Foo)[]}
* @param {Foo[]} a
* @returns {Foo[]}
*/
export function echo_vec_struct(a) {
const ptr0 = passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
Expand Down Expand Up @@ -1145,8 +1145,8 @@ export function echo_option_vec_uninit_i64(a) {
}

/**
* @param {(string)[] | null} [a]
* @returns {(string)[] | undefined}
* @param {string[] | null} [a]
* @returns {string[] | undefined}
*/
export function echo_option_vec_string(a) {
var ptr0 = isLikeNone(a) ? 0 : passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
Expand Down Expand Up @@ -1175,8 +1175,8 @@ export function echo_option_struct(a) {
}

/**
* @param {(Foo)[] | null} [a]
* @returns {(Foo)[] | undefined}
* @param {Foo[] | null} [a]
* @returns {Foo[] | undefined}
*/
export function echo_option_vec_struct(a) {
var ptr0 = isLikeNone(a) ? 0 : passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
Expand Down
4 changes: 4 additions & 0 deletions crates/cli/tests/reference/typescript-type.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* tslint:disable */
/* eslint-disable */
export function single(a: number | string): void;
export function slice(a: (number | string)[]): void;
82 changes: 82 additions & 0 deletions crates/cli/tests/reference/typescript-type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
let wasm;
export function __wbg_set_wasm(val) {
wasm = val;
}


const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;

let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });

cachedTextDecoder.decode();

let cachedUint8ArrayMemory0 = null;

function getUint8ArrayMemory0() {
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8ArrayMemory0;
}

function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
}
/**
* @param {number | string} a
*/
export function single(a) {
wasm.single(a);
}

let cachedDataViewMemory0 = null;

function getDataViewMemory0() {
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
}
return cachedDataViewMemory0;
}

let WASM_VECTOR_LEN = 0;

function addToExternrefTable0(obj) {
const idx = wasm.__externref_table_alloc();
wasm.__wbindgen_export_0.set(idx, obj);
return idx;
}

function passArrayJsValueToWasm0(array, malloc) {
const ptr = malloc(array.length * 4, 4) >>> 0;
const mem = getDataViewMemory0();
for (let i = 0; i < array.length; i++) {
mem.setUint32(ptr + 4 * i, addToExternrefTable0(array[i]), true);
}
WASM_VECTOR_LEN = array.length;
return ptr;
}
/**
* @param {(number | string)[]} a
*/
export function slice(a) {
const ptr0 = passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
wasm.slice(ptr0, len0);
}

export function __wbindgen_init_externref_table() {
const table = wasm.__wbindgen_export_0;
const offset = table.grow(4);
table.set(0, undefined);
table.set(offset + 0, undefined);
table.set(offset + 1, null);
table.set(offset + 2, true);
table.set(offset + 3, false);
;
};

export function __wbindgen_throw(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};

13 changes: 13 additions & 0 deletions crates/cli/tests/reference/typescript-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(typescript_type = "number | string")]
type CustomType;
}

#[wasm_bindgen]
pub fn single(a: CustomType) {}

#[wasm_bindgen]
pub fn slice(a: Vec<CustomType>) {}
23 changes: 23 additions & 0 deletions crates/cli/tests/reference/typescript-type.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
(module $reference_test.wasm
(type (;0;) (func))
(type (;1;) (func (result i32)))
(type (;2;) (func (param i32 i32)))
(type (;3;) (func (param i32 i32) (result i32)))
(type (;4;) (func (param externref)))
(import "./reference_test_bg.js" "__wbindgen_init_externref_table" (func (;0;) (type 0)))
(func $__wbindgen_malloc (;1;) (type 3) (param i32 i32) (result i32))
(func $slice (;2;) (type 2) (param i32 i32))
(func $__externref_table_alloc (;3;) (type 1) (result i32))
(func $"single externref shim" (;4;) (type 4) (param externref))
(table (;0;) 128 externref)
(memory (;0;) 17)
(export "memory" (memory 0))
(export "single" (func $"single externref shim"))
(export "slice" (func $slice))
(export "__wbindgen_export_0" (table 0))
(export "__externref_table_alloc" (func $__externref_table_alloc))
(export "__wbindgen_malloc" (func $__wbindgen_malloc))
(export "__wbindgen_start" (func 0))
(@custom "target_features" (after code) "\04+\0amultivalue+\0fmutable-globals+\0freference-types+\08sign-ext")
)

Loading