@@ -62,97 +62,94 @@ fn args_are_optional(name: &str) -> bool {
62
62
63
63
pub fn interface ( module : & Module ) -> Result < String , Error > {
64
64
let mut exports = String :: new ( ) ;
65
+ module_export_types ( module, |name, ty| {
66
+ writeln ! ( exports, " readonly {}: {};" , name, ty) . unwrap ( ) ;
67
+ } ) ;
68
+ Ok ( exports)
69
+ }
70
+
71
+ pub fn typescript ( module : & Module ) -> Result < String , Error > {
72
+ let mut exports = "/* tslint:disable */\n /* eslint-disable */\n " . to_string ( ) ;
73
+ module_export_types ( module, |name, ty| {
74
+ writeln ! ( exports, "export const {}: {};" , name, ty) . unwrap ( ) ;
75
+ } ) ;
76
+ Ok ( exports)
77
+ }
65
78
79
+ /// Iterates over all the exports in a module and generates TypeScript types. All
80
+ /// name-type pairs are passed to the `export` function.
81
+ fn module_export_types ( module : & Module , mut export : impl FnMut ( & str , & str ) ) {
66
82
for entry in module. exports . iter ( ) {
67
- let id = match entry. item {
68
- walrus:: ExportItem :: Function ( i) => i,
69
- walrus:: ExportItem :: Memory ( _) => {
70
- exports. push_str ( & format ! ( " readonly {}: WebAssembly.Memory;\n " , entry. name, ) ) ;
71
- continue ;
72
- }
73
- walrus:: ExportItem :: Table ( _) => {
74
- exports. push_str ( & format ! ( " readonly {}: WebAssembly.Table;\n " , entry. name, ) ) ;
75
- continue ;
83
+ match entry. item {
84
+ walrus:: ExportItem :: Function ( id) => {
85
+ let func = module. funcs . get ( id) ;
86
+ let ty = module. types . get ( func. ty ( ) ) ;
87
+ let ts_type = function_type_to_ts ( ty, args_are_optional ( & entry. name ) ) ;
88
+ export ( & entry. name , & ts_type) ;
76
89
}
90
+ walrus:: ExportItem :: Memory ( _) => export ( & entry. name , "WebAssembly.Memory" ) ,
91
+ walrus:: ExportItem :: Table ( _) => export ( & entry. name , "WebAssembly.Table" ) ,
77
92
walrus:: ExportItem :: Global ( _) => continue ,
78
93
} ;
94
+ }
95
+ }
96
+ fn val_type_to_ts ( ty : walrus:: ValType ) -> & ' static str {
97
+ // see https://webassembly.github.io/spec/js-api/index.html#towebassemblyvalue
98
+ // and https://webassembly.github.io/spec/js-api/index.html#tojsvalue
99
+ match ty {
100
+ walrus:: ValType :: I32 | walrus:: ValType :: F32 | walrus:: ValType :: F64 => "number" ,
101
+ walrus:: ValType :: I64 => "bigint" ,
102
+ // there could be anything behind a reference
103
+ walrus:: ValType :: Ref ( _) => "any" ,
104
+ // V128 currently isn't supported in JS and therefore doesn't have a
105
+ // specific type in the spec. When it does get support, this type will
106
+ // still be technically correct, but should be updated to something more
107
+ // specific.
108
+ walrus:: ValType :: V128 => "any" ,
109
+ }
110
+ }
111
+ fn function_type_to_ts ( function : & walrus:: Type , all_args_optional : bool ) -> String {
112
+ let mut out = String :: new ( ) ;
79
113
80
- let func = module. funcs . get ( id) ;
81
- let ty = module. types . get ( func. ty ( ) ) ;
82
- let mut args = String :: new ( ) ;
83
- for ( i, _) in ty. params ( ) . iter ( ) . enumerate ( ) {
84
- if i > 0 {
85
- args. push_str ( ", " ) ;
86
- }
87
-
88
- push_index_identifier ( i, & mut args) ;
89
- if args_are_optional ( & entry. name ) {
90
- args. push ( '?' ) ;
91
- }
92
- args. push_str ( ": number" ) ;
114
+ // parameters
115
+ out. push ( '(' ) ;
116
+ for ( i, arg_type) in function. params ( ) . iter ( ) . enumerate ( ) {
117
+ if i > 0 {
118
+ out. push_str ( ", " ) ;
93
119
}
94
120
95
- exports. push_str ( & format ! (
96
- " readonly {name}: ({args}) => {ret};\n " ,
97
- name = entry. name,
98
- args = args,
99
- ret = match ty. results( ) . len( ) {
100
- 0 => "void" ,
101
- 1 => "number" ,
102
- _ => "number[]" ,
103
- } ,
104
- ) ) ;
121
+ push_index_identifier ( i, & mut out) ;
122
+ if all_args_optional {
123
+ out. push ( '?' ) ;
124
+ }
125
+ out. push_str ( ": " ) ;
126
+ out. push_str ( val_type_to_ts ( * arg_type) ) ;
105
127
}
128
+ out. push ( ')' ) ;
106
129
107
- Ok ( exports)
108
- }
109
-
110
- pub fn typescript ( module : & Module ) -> Result < String , Error > {
111
- let mut exports = "/* tslint:disable */\n /* eslint-disable */\n " . to_string ( ) ;
112
- for entry in module. exports . iter ( ) {
113
- let id = match entry. item {
114
- walrus:: ExportItem :: Function ( i) => i,
115
- walrus:: ExportItem :: Memory ( _) => {
116
- exports. push_str ( & format ! (
117
- "export const {}: WebAssembly.Memory;\n " ,
118
- entry. name,
119
- ) ) ;
120
- continue ;
121
- }
122
- walrus:: ExportItem :: Table ( _) => {
123
- exports. push_str ( & format ! (
124
- "export const {}: WebAssembly.Table;\n " ,
125
- entry. name,
126
- ) ) ;
127
- continue ;
128
- }
129
- walrus:: ExportItem :: Global ( _) => continue ,
130
- } ;
130
+ // arrow
131
+ out. push_str ( " => " ) ;
131
132
132
- let func = module. funcs . get ( id) ;
133
- let ty = module. types . get ( func. ty ( ) ) ;
134
- let mut args = String :: new ( ) ;
135
- for ( i, _) in ty. params ( ) . iter ( ) . enumerate ( ) {
136
- if i > 0 {
137
- args. push_str ( ", " ) ;
133
+ // results
134
+ let results = function. results ( ) ;
135
+ // this match follows the spec:
136
+ // https://webassembly.github.io/spec/js-api/index.html#exported-function-exotic-objects
137
+ match results. len ( ) {
138
+ 0 => out. push_str ( "void" ) ,
139
+ 1 => out. push_str ( val_type_to_ts ( results[ 0 ] ) ) ,
140
+ _ => {
141
+ out. push ( '[' ) ;
142
+ for ( i, result) in results. iter ( ) . enumerate ( ) {
143
+ if i > 0 {
144
+ out. push_str ( ", " ) ;
145
+ }
146
+ out. push_str ( val_type_to_ts ( * result) ) ;
138
147
}
139
- push_index_identifier ( i, & mut args) ;
140
- args. push_str ( ": number" ) ;
148
+ out. push ( ']' ) ;
141
149
}
142
-
143
- exports. push_str ( & format ! (
144
- "export function {name}({args}): {ret};\n " ,
145
- name = entry. name,
146
- args = args,
147
- ret = match ty. results( ) . len( ) {
148
- 0 => "void" ,
149
- 1 => "number" ,
150
- _ => "number[]" ,
151
- } ,
152
- ) ) ;
153
150
}
154
151
155
- Ok ( exports )
152
+ out
156
153
}
157
154
158
155
impl Output {
0 commit comments