Skip to content

Commit f1e2d6e

Browse files
Better TS type formatting for array types (#4346)
1 parent 83a2ff4 commit f1e2d6e

File tree

9 files changed

+185
-55
lines changed

9 files changed

+185
-55
lines changed

crates/cli-support/src/descriptor.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::char;
22

3+
use crate::js::identifier::is_valid_ident;
4+
35
macro_rules! tys {
46
($($a:ident)*) => (tys! { @ ($($a)*) 0 });
57
(@ () $v:expr) => {};
@@ -306,7 +308,11 @@ impl VectorKind {
306308
VectorKind::F64 => "Float64Array".to_string(),
307309
VectorKind::Externref => "any[]".to_string(),
308310
VectorKind::NamedExternref(ref name) => {
309-
format!("({})[]", name)
311+
if is_valid_ident(name.as_str()) {
312+
format!("{}[]", name)
313+
} else {
314+
format!("({})[]", name)
315+
}
310316
}
311317
}
312318
}
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/// Returns whether a character has the Unicode `ID_Start` properly.
2+
///
3+
/// This is only ever-so-slightly different from `XID_Start` in a few edge
4+
/// cases, so we handle those edge cases manually and delegate everything else
5+
/// to `unicode-ident`.
6+
fn is_id_start(c: char) -> bool {
7+
match c {
8+
'\u{037A}' | '\u{0E33}' | '\u{0EB3}' | '\u{309B}' | '\u{309C}' | '\u{FC5E}'
9+
| '\u{FC5F}' | '\u{FC60}' | '\u{FC61}' | '\u{FC62}' | '\u{FC63}' | '\u{FDFA}'
10+
| '\u{FDFB}' | '\u{FE70}' | '\u{FE72}' | '\u{FE74}' | '\u{FE76}' | '\u{FE78}'
11+
| '\u{FE7A}' | '\u{FE7C}' | '\u{FE7E}' | '\u{FF9E}' | '\u{FF9F}' => true,
12+
_ => unicode_ident::is_xid_start(c),
13+
}
14+
}
15+
16+
/// Returns whether a character has the Unicode `ID_Continue` properly.
17+
///
18+
/// This is only ever-so-slightly different from `XID_Continue` in a few edge
19+
/// cases, so we handle those edge cases manually and delegate everything else
20+
/// to `unicode-ident`.
21+
fn is_id_continue(c: char) -> bool {
22+
match c {
23+
'\u{037A}' | '\u{309B}' | '\u{309C}' | '\u{FC5E}' | '\u{FC5F}' | '\u{FC60}'
24+
| '\u{FC61}' | '\u{FC62}' | '\u{FC63}' | '\u{FDFA}' | '\u{FDFB}' | '\u{FE70}'
25+
| '\u{FE72}' | '\u{FE74}' | '\u{FE76}' | '\u{FE78}' | '\u{FE7A}' | '\u{FE7C}'
26+
| '\u{FE7E}' => true,
27+
_ => unicode_ident::is_xid_continue(c),
28+
}
29+
}
30+
31+
/// Returns whether a string is a valid JavaScript identifier.
32+
/// Defined at https://tc39.es/ecma262/#prod-IdentifierName.
33+
pub fn is_valid_ident(name: &str) -> bool {
34+
!name.is_empty()
35+
&& name.chars().enumerate().all(|(i, char)| {
36+
if i == 0 {
37+
is_id_start(char) || char == '$' || char == '_'
38+
} else {
39+
is_id_continue(char) || char == '$' || char == '\u{200C}' || char == '\u{200D}'
40+
}
41+
})
42+
}

crates/cli-support/src/js/mod.rs

+2-42
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::wit::{JsImport, JsImportName, NonstandardWitSection, WasmBindgenAux};
1010
use crate::{reset_indentation, Bindgen, EncodeInto, OutputMode, PLACEHOLDER_MODULE};
1111
use anyhow::{anyhow, bail, Context as _, Error};
1212
use binding::TsReference;
13+
use identifier::is_valid_ident;
1314
use std::borrow::Cow;
1415
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
1516
use std::fmt;
@@ -19,6 +20,7 @@ use std::path::{Path, PathBuf};
1920
use walrus::{FunctionId, ImportId, MemoryId, Module, TableId, ValType};
2021

2122
mod binding;
23+
pub mod identifier;
2224

2325
pub struct Context<'a> {
2426
globals: String,
@@ -4535,48 +4537,6 @@ fn require_class<'a>(
45354537
.or_default()
45364538
}
45374539

4538-
/// Returns whether a character has the Unicode `ID_Start` properly.
4539-
///
4540-
/// This is only ever-so-slightly different from `XID_Start` in a few edge
4541-
/// cases, so we handle those edge cases manually and delegate everything else
4542-
/// to `unicode-ident`.
4543-
fn is_id_start(c: char) -> bool {
4544-
match c {
4545-
'\u{037A}' | '\u{0E33}' | '\u{0EB3}' | '\u{309B}' | '\u{309C}' | '\u{FC5E}'
4546-
| '\u{FC5F}' | '\u{FC60}' | '\u{FC61}' | '\u{FC62}' | '\u{FC63}' | '\u{FDFA}'
4547-
| '\u{FDFB}' | '\u{FE70}' | '\u{FE72}' | '\u{FE74}' | '\u{FE76}' | '\u{FE78}'
4548-
| '\u{FE7A}' | '\u{FE7C}' | '\u{FE7E}' | '\u{FF9E}' | '\u{FF9F}' => true,
4549-
_ => unicode_ident::is_xid_start(c),
4550-
}
4551-
}
4552-
4553-
/// Returns whether a character has the Unicode `ID_Continue` properly.
4554-
///
4555-
/// This is only ever-so-slightly different from `XID_Continue` in a few edge
4556-
/// cases, so we handle those edge cases manually and delegate everything else
4557-
/// to `unicode-ident`.
4558-
fn is_id_continue(c: char) -> bool {
4559-
match c {
4560-
'\u{037A}' | '\u{309B}' | '\u{309C}' | '\u{FC5E}' | '\u{FC5F}' | '\u{FC60}'
4561-
| '\u{FC61}' | '\u{FC62}' | '\u{FC63}' | '\u{FDFA}' | '\u{FDFB}' | '\u{FE70}'
4562-
| '\u{FE72}' | '\u{FE74}' | '\u{FE76}' | '\u{FE78}' | '\u{FE7A}' | '\u{FE7C}'
4563-
| '\u{FE7E}' => true,
4564-
_ => unicode_ident::is_xid_continue(c),
4565-
}
4566-
}
4567-
4568-
/// Returns whether a string is a valid JavaScript identifier.
4569-
/// Defined at https://tc39.es/ecma262/#prod-IdentifierName.
4570-
fn is_valid_ident(name: &str) -> bool {
4571-
name.chars().enumerate().all(|(i, char)| {
4572-
if i == 0 {
4573-
is_id_start(char) || char == '$' || char == '_'
4574-
} else {
4575-
is_id_continue(char) || char == '$' || char == '\u{200C}' || char == '\u{200D}'
4576-
}
4577-
})
4578-
}
4579-
45804540
/// Returns a string to tack on to the end of an expression to access a
45814541
/// property named `name` of the object that expression resolves to.
45824542
///

crates/cli/tests/reference/echo.d.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ export function echo_vec_uninit_u32(a: Uint32Array): Uint32Array;
3333
export function echo_vec_uninit_i32(a: Int32Array): Int32Array;
3434
export function echo_vec_uninit_u64(a: BigUint64Array): BigUint64Array;
3535
export function echo_vec_uninit_i64(a: BigInt64Array): BigInt64Array;
36-
export function echo_vec_string(a: (string)[]): (string)[];
36+
export function echo_vec_string(a: string[]): string[];
3737
export function echo_struct(a: Foo): Foo;
38-
export function echo_vec_struct(a: (Foo)[]): (Foo)[];
38+
export function echo_vec_struct(a: Foo[]): Foo[];
3939
export function echo_option_u8(a?: number | null): number | undefined;
4040
export function echo_option_i8(a?: number | null): number | undefined;
4141
export function echo_option_u16(a?: number | null): number | undefined;
@@ -69,9 +69,9 @@ export function echo_option_vec_uninit_u32(a?: Uint32Array | null): Uint32Array
6969
export function echo_option_vec_uninit_i32(a?: Int32Array | null): Int32Array | undefined;
7070
export function echo_option_vec_uninit_u64(a?: BigUint64Array | null): BigUint64Array | undefined;
7171
export function echo_option_vec_uninit_i64(a?: BigInt64Array | null): BigInt64Array | undefined;
72-
export function echo_option_vec_string(a?: (string)[] | null): (string)[] | undefined;
72+
export function echo_option_vec_string(a?: string[] | null): string[] | undefined;
7373
export function echo_option_struct(a?: Foo | null): Foo | undefined;
74-
export function echo_option_vec_struct(a?: (Foo)[] | null): (Foo)[] | undefined;
74+
export function echo_option_vec_struct(a?: Foo[] | null): Foo[] | undefined;
7575
export class Foo {
7676
private constructor();
7777
free(): void;

crates/cli/tests/reference/echo.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -685,8 +685,8 @@ function getArrayJsValueFromWasm0(ptr, len) {
685685
return result;
686686
}
687687
/**
688-
* @param {(string)[]} a
689-
* @returns {(string)[]}
688+
* @param {string[]} a
689+
* @returns {string[]}
690690
*/
691691
export function echo_vec_string(a) {
692692
const ptr0 = passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
@@ -714,8 +714,8 @@ export function echo_struct(a) {
714714
}
715715

716716
/**
717-
* @param {(Foo)[]} a
718-
* @returns {(Foo)[]}
717+
* @param {Foo[]} a
718+
* @returns {Foo[]}
719719
*/
720720
export function echo_vec_struct(a) {
721721
const ptr0 = passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
@@ -1145,8 +1145,8 @@ export function echo_option_vec_uninit_i64(a) {
11451145
}
11461146

11471147
/**
1148-
* @param {(string)[] | null} [a]
1149-
* @returns {(string)[] | undefined}
1148+
* @param {string[] | null} [a]
1149+
* @returns {string[] | undefined}
11501150
*/
11511151
export function echo_option_vec_string(a) {
11521152
var ptr0 = isLikeNone(a) ? 0 : passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
@@ -1175,8 +1175,8 @@ export function echo_option_struct(a) {
11751175
}
11761176

11771177
/**
1178-
* @param {(Foo)[] | null} [a]
1179-
* @returns {(Foo)[] | undefined}
1178+
* @param {Foo[] | null} [a]
1179+
* @returns {Foo[] | undefined}
11801180
*/
11811181
export function echo_option_vec_struct(a) {
11821182
var ptr0 = isLikeNone(a) ? 0 : passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* tslint:disable */
2+
/* eslint-disable */
3+
export function single(a: number | string): void;
4+
export function slice(a: (number | string)[]): void;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
let wasm;
2+
export function __wbg_set_wasm(val) {
3+
wasm = val;
4+
}
5+
6+
7+
const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;
8+
9+
let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });
10+
11+
cachedTextDecoder.decode();
12+
13+
let cachedUint8ArrayMemory0 = null;
14+
15+
function getUint8ArrayMemory0() {
16+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
17+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
18+
}
19+
return cachedUint8ArrayMemory0;
20+
}
21+
22+
function getStringFromWasm0(ptr, len) {
23+
ptr = ptr >>> 0;
24+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
25+
}
26+
/**
27+
* @param {number | string} a
28+
*/
29+
export function single(a) {
30+
wasm.single(a);
31+
}
32+
33+
let cachedDataViewMemory0 = null;
34+
35+
function getDataViewMemory0() {
36+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
37+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
38+
}
39+
return cachedDataViewMemory0;
40+
}
41+
42+
let WASM_VECTOR_LEN = 0;
43+
44+
function addToExternrefTable0(obj) {
45+
const idx = wasm.__externref_table_alloc();
46+
wasm.__wbindgen_export_0.set(idx, obj);
47+
return idx;
48+
}
49+
50+
function passArrayJsValueToWasm0(array, malloc) {
51+
const ptr = malloc(array.length * 4, 4) >>> 0;
52+
const mem = getDataViewMemory0();
53+
for (let i = 0; i < array.length; i++) {
54+
mem.setUint32(ptr + 4 * i, addToExternrefTable0(array[i]), true);
55+
}
56+
WASM_VECTOR_LEN = array.length;
57+
return ptr;
58+
}
59+
/**
60+
* @param {(number | string)[]} a
61+
*/
62+
export function slice(a) {
63+
const ptr0 = passArrayJsValueToWasm0(a, wasm.__wbindgen_malloc);
64+
const len0 = WASM_VECTOR_LEN;
65+
wasm.slice(ptr0, len0);
66+
}
67+
68+
export function __wbindgen_init_externref_table() {
69+
const table = wasm.__wbindgen_export_0;
70+
const offset = table.grow(4);
71+
table.set(0, undefined);
72+
table.set(offset + 0, undefined);
73+
table.set(offset + 1, null);
74+
table.set(offset + 2, true);
75+
table.set(offset + 3, false);
76+
;
77+
};
78+
79+
export function __wbindgen_throw(arg0, arg1) {
80+
throw new Error(getStringFromWasm0(arg0, arg1));
81+
};
82+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen]
4+
extern "C" {
5+
#[wasm_bindgen(typescript_type = "number | string")]
6+
type CustomType;
7+
}
8+
9+
#[wasm_bindgen]
10+
pub fn single(a: CustomType) {}
11+
12+
#[wasm_bindgen]
13+
pub fn slice(a: Vec<CustomType>) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
(module $reference_test.wasm
2+
(type (;0;) (func))
3+
(type (;1;) (func (result i32)))
4+
(type (;2;) (func (param i32 i32)))
5+
(type (;3;) (func (param i32 i32) (result i32)))
6+
(type (;4;) (func (param externref)))
7+
(import "./reference_test_bg.js" "__wbindgen_init_externref_table" (func (;0;) (type 0)))
8+
(func $__wbindgen_malloc (;1;) (type 3) (param i32 i32) (result i32))
9+
(func $slice (;2;) (type 2) (param i32 i32))
10+
(func $__externref_table_alloc (;3;) (type 1) (result i32))
11+
(func $"single externref shim" (;4;) (type 4) (param externref))
12+
(table (;0;) 128 externref)
13+
(memory (;0;) 17)
14+
(export "memory" (memory 0))
15+
(export "single" (func $"single externref shim"))
16+
(export "slice" (func $slice))
17+
(export "__wbindgen_export_0" (table 0))
18+
(export "__externref_table_alloc" (func $__externref_table_alloc))
19+
(export "__wbindgen_malloc" (func $__wbindgen_malloc))
20+
(export "__wbindgen_start" (func 0))
21+
(@custom "target_features" (after code) "\04+\0amultivalue+\0fmutable-globals+\0freference-types+\08sign-ext")
22+
)
23+

0 commit comments

Comments
 (0)