@@ -8,6 +8,7 @@ use crate::js::Context;
8
8
use crate :: wit:: InstructionData ;
9
9
use crate :: wit:: { Adapter , AdapterId , AdapterKind , AdapterType , Instruction } ;
10
10
use anyhow:: { anyhow, bail, Error } ;
11
+ use std:: collections:: HashSet ;
11
12
use std:: fmt:: Write ;
12
13
use walrus:: { Module , ValType } ;
13
14
@@ -68,6 +69,7 @@ pub struct JsFunction {
68
69
pub js_doc : String ,
69
70
pub ts_arg_tys : Vec < String > ,
70
71
pub ts_ret_ty : Option < String > ,
72
+ pub ts_refs : HashSet < TsReference > ,
71
73
/// Whether this function has a single optional argument.
72
74
///
73
75
/// If the function is a setter, that means that the field it sets is optional.
@@ -76,6 +78,14 @@ pub struct JsFunction {
76
78
pub log_error : bool ,
77
79
}
78
80
81
+ /// A references to an (likely) exported symbol used in TS type expression.
82
+ ///
83
+ /// Right now, only string enum require this type of anaylsis.
84
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
85
+ pub enum TsReference {
86
+ StringEnum ( String ) ,
87
+ }
88
+
79
89
impl < ' a , ' b > Builder < ' a , ' b > {
80
90
pub fn new ( cx : & ' a mut Context < ' b > ) -> Builder < ' a , ' b > {
81
91
Builder {
@@ -246,7 +256,7 @@ impl<'a, 'b> Builder<'a, 'b> {
246
256
// should start from here. Struct fields(Getter) only have one arg, and
247
257
// this is the clue we can infer if a function might be a field.
248
258
let mut might_be_optional_field = false ;
249
- let ( ts_sig, ts_arg_tys, ts_ret_ty) = self . typescript_signature (
259
+ let ( ts_sig, ts_arg_tys, ts_ret_ty, ts_refs ) = self . typescript_signature (
250
260
& function_args,
251
261
& arg_tys,
252
262
& adapter. inner_results ,
@@ -266,6 +276,7 @@ impl<'a, 'b> Builder<'a, 'b> {
266
276
js_doc,
267
277
ts_arg_tys,
268
278
ts_ret_ty,
279
+ ts_refs,
269
280
might_be_optional_field,
270
281
catch : self . catch ,
271
282
log_error : self . log_error ,
@@ -285,11 +296,12 @@ impl<'a, 'b> Builder<'a, 'b> {
285
296
might_be_optional_field : & mut bool ,
286
297
asyncness : bool ,
287
298
variadic : bool ,
288
- ) -> ( String , Vec < String > , Option < String > ) {
299
+ ) -> ( String , Vec < String > , Option < String > , HashSet < TsReference > ) {
289
300
// Build up the typescript signature as well
290
301
let mut omittable = true ;
291
302
let mut ts_args = Vec :: new ( ) ;
292
303
let mut ts_arg_tys = Vec :: new ( ) ;
304
+ let mut ts_refs = HashSet :: new ( ) ;
293
305
for ( name, ty) in arg_names. iter ( ) . zip ( arg_tys) . rev ( ) {
294
306
// In TypeScript, we can mark optional parameters as omittable
295
307
// using the `?` suffix, but only if they're not followed by
@@ -301,12 +313,12 @@ impl<'a, 'b> Builder<'a, 'b> {
301
313
match ty {
302
314
AdapterType :: Option ( ty) if omittable => {
303
315
arg. push_str ( "?: " ) ;
304
- adapter2ts ( ty, & mut ts) ;
316
+ adapter2ts ( ty, & mut ts, Some ( & mut ts_refs ) ) ;
305
317
}
306
318
ty => {
307
319
omittable = false ;
308
320
arg. push_str ( ": " ) ;
309
- adapter2ts ( ty, & mut ts) ;
321
+ adapter2ts ( ty, & mut ts, Some ( & mut ts_refs ) ) ;
310
322
}
311
323
}
312
324
arg. push_str ( & ts) ;
@@ -342,7 +354,7 @@ impl<'a, 'b> Builder<'a, 'b> {
342
354
let mut ret = String :: new ( ) ;
343
355
match result_tys. len ( ) {
344
356
0 => ret. push_str ( "void" ) ,
345
- 1 => adapter2ts ( & result_tys[ 0 ] , & mut ret) ,
357
+ 1 => adapter2ts ( & result_tys[ 0 ] , & mut ret, Some ( & mut ts_refs ) ) ,
346
358
_ => ret. push_str ( "[any]" ) ,
347
359
}
348
360
if asyncness {
@@ -351,7 +363,7 @@ impl<'a, 'b> Builder<'a, 'b> {
351
363
ts. push_str ( & ret) ;
352
364
ts_ret = Some ( ret) ;
353
365
}
354
- ( ts, ts_arg_tys, ts_ret)
366
+ ( ts, ts_arg_tys, ts_ret, ts_refs )
355
367
}
356
368
357
369
/// Returns a helpful JS doc comment which lists types for all parameters
@@ -374,7 +386,7 @@ impl<'a, 'b> Builder<'a, 'b> {
374
386
for ( name, ty) in fn_arg_names. iter ( ) . zip ( arg_tys) . rev ( ) {
375
387
let mut arg = "@param {" . to_string ( ) ;
376
388
377
- adapter2ts ( ty, & mut arg) ;
389
+ adapter2ts ( ty, & mut arg, None ) ;
378
390
arg. push_str ( "} " ) ;
379
391
match ty {
380
392
AdapterType :: Option ( ..) if omittable => {
@@ -395,7 +407,7 @@ impl<'a, 'b> Builder<'a, 'b> {
395
407
396
408
if let ( Some ( name) , Some ( ty) ) = ( variadic_arg, arg_tys. last ( ) ) {
397
409
ret. push_str ( "@param {..." ) ;
398
- adapter2ts ( ty, & mut ret) ;
410
+ adapter2ts ( ty, & mut ret, None ) ;
399
411
ret. push_str ( "} " ) ;
400
412
ret. push_str ( name) ;
401
413
ret. push ( '\n' ) ;
@@ -1416,7 +1428,7 @@ impl Invocation {
1416
1428
}
1417
1429
}
1418
1430
1419
- fn adapter2ts ( ty : & AdapterType , dst : & mut String ) {
1431
+ fn adapter2ts ( ty : & AdapterType , dst : & mut String , refs : Option < & mut HashSet < TsReference > > ) {
1420
1432
match ty {
1421
1433
AdapterType :: I32
1422
1434
| AdapterType :: S8
@@ -1434,13 +1446,19 @@ fn adapter2ts(ty: &AdapterType, dst: &mut String) {
1434
1446
AdapterType :: Bool => dst. push_str ( "boolean" ) ,
1435
1447
AdapterType :: Vector ( kind) => dst. push_str ( & kind. js_ty ( ) ) ,
1436
1448
AdapterType :: Option ( ty) => {
1437
- adapter2ts ( ty, dst) ;
1449
+ adapter2ts ( ty, dst, refs ) ;
1438
1450
dst. push_str ( " | undefined" ) ;
1439
1451
}
1440
1452
AdapterType :: NamedExternref ( name) => dst. push_str ( name) ,
1441
1453
AdapterType :: Struct ( name) => dst. push_str ( name) ,
1442
1454
AdapterType :: Enum ( name) => dst. push_str ( name) ,
1443
- AdapterType :: StringEnum => dst. push_str ( "any" ) ,
1455
+ AdapterType :: StringEnum ( name) => {
1456
+ if let Some ( refs) = refs {
1457
+ refs. insert ( TsReference :: StringEnum ( name. clone ( ) ) ) ;
1458
+ }
1459
+
1460
+ dst. push_str ( name) ;
1461
+ }
1444
1462
AdapterType :: Function => dst. push_str ( "any" ) ,
1445
1463
}
1446
1464
}
0 commit comments