wasm-bindgen-cli-support 0.2.118

Shared support for the wasm-bindgen-cli package, an internal dependency
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
use crate::intrinsic::Intrinsic;
use crate::wit::AdapterId;
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::path::PathBuf;
use walrus::TypedCustomSectionId;

/// A synthetic custom section which is not standardized, never will be, and
/// cannot be serialized or parsed. This is synthesized from all of the
/// compiler-emitted wasm-bindgen sections and then immediately removed to be
/// processed in the JS generation pass.
#[derive(Default, Debug)]
pub struct WasmBindgenAux {
    /// Extra typescript annotations that should be appended to the generated
    /// TypeScript file. This is provided via a custom attribute in Rust code.
    pub extra_typescript: Vec<String>,

    /// A map from identifier to the contents of each local module defined via
    /// the `#[wasm_bindgen(module = "/foo.js")]` import options.
    pub local_modules: HashMap<String, String>,

    /// A map from unique crate identifier to the list of inline JS snippets for
    /// that crate identifier.
    pub snippets: BTreeMap<String, Vec<String>>,

    /// A list of all `package.json` files that are intended to be included in
    /// the final build.
    pub package_jsons: HashSet<PathBuf>,

    /// A map from exported function id to where it's expected to be exported
    /// to.
    pub export_map: HashMap<AdapterId, AuxExport>,

    /// A map from imported function id to what it's expected to import.
    pub import_map: HashMap<AdapterId, AuxImport>,

    /// List of imports that should be re-exported, keyed by reexport name.
    /// The bool indicates whether TypeScript definitions should be generated for the reexport.
    pub reexports: BTreeMap<String, (JsImport, bool)>,

    /// Small bits of metadata about imports.
    pub imports_with_catch: HashSet<AdapterId>,
    pub imports_with_variadic: HashSet<AdapterId>,
    pub imports_with_assert_no_shim: HashSet<AdapterId>,

    /// Auxiliary information to go into JS/TypeScript bindings describing the
    /// exported enums from Rust.
    pub enums: HashMap<String, AuxEnum>,
    /// Auxiliary information to go into JS/TypeScript bindings describing the
    /// exported string enums from Rust.
    pub string_enums: HashMap<String, AuxStringEnum>,

    /// Auxiliary information to go into JS/TypeScript bindings describing the
    /// exported structs from Rust and their fields they've got exported.
    pub structs: Vec<AuxStruct>,

    /// Information about various internal functions used to manage the `externref`
    /// table, later used to process JS bindings.
    pub externref_table: Option<walrus::TableId>,
    pub function_table: Option<walrus::TableId>,
    pub externref_alloc: Option<walrus::FunctionId>,
    pub externref_drop: Option<walrus::FunctionId>,
    pub externref_drop_slice: Option<walrus::FunctionId>,

    /// Various intrinsics used for JS glue generation
    pub exn_store: Option<walrus::FunctionId>,
    pub destroy_closure: Option<walrus::FunctionId>,
    pub stack_pointer: Option<walrus::GlobalId>,
    pub thread_destroy: Option<walrus::FunctionId>,

    /// The imported JSTag for catching JavaScript exceptions in Wasm.
    /// When this is `Some`, all imports with `catch` use Wasm catch wrappers
    /// instead of JS `handleError` wrappers.
    pub js_tag: Option<walrus::TagId>,

    /// The imported wrapped JSTag for abort-reinit mode.
    /// This is a custom WebAssembly.Tag used to wrap exceptions so they can be
    /// distinguished from other JS exceptions.
    pub wrapped_js_tag: Option<walrus::TagId>,

    /// Whether the `__wbindgen_reinit` intrinsic is used. When true, the
    /// reinit machinery (`__wbg_reset_state` as a private function + the
    /// reinit flag check in `__wbg_termination_guard`) is emitted regardless
    /// of `--experimental-reset-state-function`.
    pub uses_reinit: bool,
}

pub type WasmBindgenAuxId = TypedCustomSectionId<WasmBindgenAux>;

#[derive(Debug)]
pub struct AuxExport {
    /// When generating errors about this export, a helpful name to remember it
    /// by.
    pub debug_name: String,
    /// Comments parsed in Rust and forwarded here to show up in JS bindings.
    pub comments: String,
    /// Function's argument info in Rust forwarded here to configure the signature
    /// that shows up in bindings.
    pub args: Option<Vec<AuxFunctionArgumentData>>,
    /// Whether this is an async function, to configure the TypeScript return value.
    pub asyncness: bool,
    /// What kind of function this is and where it shows up
    pub kind: AuxExportKind,
    /// The namespace to export the item through, if any
    pub js_namespace: Option<Vec<String>>,
    /// Whether typescript bindings should be generated for this export.
    pub generate_typescript: bool,
    /// Whether jsdoc comments should be generated for this export.
    pub generate_jsdoc: bool,
    /// Whether typescript bindings should be generated for this export.
    pub variadic: bool,
    /// Function's return overriding type
    pub fn_ret_ty_override: Option<String>,
    /// Function's return description
    pub fn_ret_desc: Option<String>,
}

/// Information about a functions' argument
#[derive(Debug, Clone)]
pub struct AuxFunctionArgumentData {
    /// Specifies the argument name
    pub name: String,
    /// Specifies the function argument type override
    pub ty_override: Option<String>,
    /// Specifies whether the parameter is optional
    pub optional: bool,
    /// Specifies the argument description
    pub desc: Option<String>,
}

/// All possible kinds of exports from a Wasm module.
///
/// This `enum` says where to place an exported Wasm function. For example it
/// may want to get hooked up to a JS class, or it may want to be exported as a
/// free function (etc).
///
/// TODO: it feels like this should not really be here per se. We probably want
/// to either construct the JS object itself from within Wasm or somehow move
/// more of this information into some other section. Really what this is is
/// sort of an "export map" saying how to wire up all the free functions from
/// the Wasm module into the output expected JS module. All our functions here
/// currently take integer parameters and require a JS wrapper, but ideally
/// we'd change them one day to taking/receiving `externref` which then use some
/// sort of webidl import to customize behavior or something like that. In any
/// case this doesn't feel quite right in terms of privilege separation, so
/// we'll want to work on this. For now though it works.
#[derive(Debug)]
pub enum AuxExportKind {
    /// A free function that's just listed on the exported module
    Function(String),

    /// A free function that receives JS `this` as its first parameter
    FunctionThis(String),

    /// A function that's used to create an instance of a class. The function
    /// actually return just an integer which is put on an JS object currently.
    Constructor(String),

    /// A function that's associated with a class.
    ///
    /// This can either be a static method (indicated by `AuxReceiverKind::None`),
    /// which is basically just a free function namespaced under the class, or
    /// a proper method.
    ///
    /// It can also be a getter or a setter for a (possibly static) field of
    /// the class, in which case `name` is the name of the field.
    ///
    /// If the function isn't static, the first argument is the index of the
    /// Rust object in the JS heap.
    Method {
        class: String,
        name: String,
        receiver: AuxReceiverKind,
        kind: AuxExportedMethodKind,
    },
}

/// All the possible kinds of exported methods.
#[derive(Debug, Clone, Copy)]
pub enum AuxExportedMethodKind {
    /// A regular method.
    Method,
    /// A getter for a field.
    Getter,
    /// A setter for a field.
    Setter,
}

/// The 'receiver' of a method; in other words, the type that the method is called on.
///
/// This is `None` if the method is static, or `Borrowed` or `Owned` if the
/// method takes `&[mut] self` or `self` respectively.
#[derive(Debug, Clone, Copy)]
pub enum AuxReceiverKind {
    None,
    Borrowed,
    Owned,
}

impl AuxReceiverKind {
    /// Returns whether this is `AuxReceiverKind::None` (in other words,
    /// whether the method with this receiver is static).
    pub fn is_static(self) -> bool {
        matches!(self, Self::None)
    }
}

#[derive(Debug)]
pub struct AuxEnum {
    /// The name of this enum
    pub name: String,
    /// The copied Rust comments to forward to JS
    pub comments: String,
    /// A list of variants with their name, value and comments
    /// and whether typescript bindings should be generated for each variant
    pub variants: Vec<(String, i64, String)>,
    /// Whether typescript bindings should be generated for this enum.
    pub generate_typescript: bool,
    /// Whether to not export this enum from the module exports
    pub private: bool,
    /// The namespace to export the enum through, if any
    pub js_namespace: Option<Vec<String>>,
}

#[derive(Debug)]
pub struct AuxStringEnum {
    /// The name of this enum
    pub name: String,
    /// The copied Rust comments to forward to JS
    pub comments: String,
    /// A list of variants values
    pub variant_values: Vec<String>,
    /// Whether typescript bindings should be generated for this enum.
    pub generate_typescript: bool,
    /// The namespace to export the enum through, if any
    /// Note: Currently unused as string enums don't generate exports,
    /// but kept for consistency and potential future use.
    #[allow(dead_code)]
    pub js_namespace: Option<Vec<String>>,
}

#[derive(Debug)]
pub struct AuxStruct {
    /// The JS name of this struct (used for JS output)
    pub name: String,
    /// The Rust name of this struct (used as internal key, matches js_class on exports)
    pub rust_name: String,
    /// The namespace-qualified name (used for wasm symbol generation)
    pub qualified_name: String,
    /// The copied Rust comments to forward to JS
    pub comments: String,
    /// Whether to generate helper methods for inspecting the class
    pub is_inspectable: bool,
    /// Whether typescript bindings should be generated for this struct.
    pub generate_typescript: bool,
    /// Whether to not export this struct from the module exports
    pub private: bool,
    /// The namespace to export the struct through, if any
    pub js_namespace: Option<Vec<String>>,
}

/// All possible types of imports that can be imported by a Wasm module.
///
/// This `enum` is intended to map out what an imported value is. For example
/// this contains a ton of shims and various ways you can call a function. The
/// base variant here is `Value` which simply means "hook this up to the import"
/// and the signatures will match up.
///
/// Note that this is *not* the same as the webidl bindings section. This is
/// intended to be coupled with that to map out what actually gets hooked up to
/// an import in the Wasm module. The two work in tandem.
/// Represents the source of a re-export.
///
/// Some of these items here are native to JS (like `Value`, indexing
/// operations, etc). Others are shims generated by wasm-bindgen (like `Closure`
/// or `Instanceof`).
#[derive(Debug)]
pub enum AuxImport {
    /// This import is expected to simply be whatever is the value that's
    /// imported
    Value(AuxValue),

    /// A static method on a class is being imported, and the `this` of the
    /// function call is expected to always be the class.
    ValueWithThis(JsImport, String),

    /// This import is expected to be a function that takes an `externref` and
    /// returns a `bool`. It's expected that it tests if the argument is an
    /// instance of (using `instanceof`) the name specified.
    ///
    /// TODO: can we use `Reflect` or something like that to avoid an extra kind
    /// of import here?
    Instanceof(JsImport),

    /// This import is expected to be a shim that returns the JS value named by
    /// `JsImport`.
    Static { js: JsImport, optional: bool },

    /// This import is expected to be a shim that returns an exported `JsString`.
    String(String),

    /// This import is a generic cast function, monomorphised for a specific `fn(A) -> R` signature.
    Cast { sig_comment: String },

    /// This import is expected to be a shim that simply calls the `foo` method
    /// on the first object, passing along all other parameters and returning
    /// the resulting value.
    StructuralMethod(String),

    /// This import is a "structural getter" which simply returns the `.field`
    /// value of the first argument as an object.
    ///
    /// e.g. `function(x) { return x.foo; }`
    StructuralGetter(String),

    /// This import is a "structural getter" which simply returns the `.field`
    /// value of the specified class
    ///
    /// e.g. `function() { return TheClass.foo; }`
    StructuralClassGetter(JsImport, String),

    /// This import is a "structural setter" which simply sets the `.field`
    /// value of the first argument to the second argument.
    ///
    /// e.g. `function(x, y) { x.foo = y; }`
    StructuralSetter(String),

    /// This import is a "structural setter" which simply sets the `.field`
    /// value of the specified class to the first argument of the function.
    ///
    /// e.g. `function(x) { TheClass.foo = x; }`
    StructuralClassSetter(JsImport, String),

    /// This import is expected to be a shim that is an indexing getter of the
    /// JS class here, where the first argument of the function is the field to
    /// look up. The return value is the value of the field.
    ///
    /// e.g. `function(x) { return TheClass[x]; }`
    ///
    /// TODO: can we use `Reflect` or something like that to avoid an extra kind
    /// of import here?
    IndexingGetterOfClass(JsImport),

    /// This import is expected to be a shim that is an indexing getter of the
    /// first argument interpreted as an object where the field to look up is
    /// the second argument.
    ///
    /// e.g. `function(x, y) { return x[y]; }`
    ///
    /// TODO: can we use `Reflect` or something like that to avoid an extra kind
    /// of import here?
    IndexingGetterOfObject,

    /// This import is expected to be a shim that is an indexing setter of the
    /// JS class here, where the first argument of the function is the field to
    /// set and the second is the value to set it to.
    ///
    /// e.g. `function(x, y) { TheClass[x] = y; }`
    ///
    /// TODO: can we use `Reflect` or something like that to avoid an extra kind
    /// of import here?
    IndexingSetterOfClass(JsImport),

    /// This import is expected to be a shim that is an indexing setter of the
    /// first argument interpreted as an object where the next two fields are
    /// the field to set and the value to set it to.
    ///
    /// e.g. `function(x, y, z) { x[y] = z; }`
    ///
    /// TODO: can we use `Reflect` or something like that to avoid an extra kind
    /// of import here?
    IndexingSetterOfObject,

    /// This import is expected to be a shim that is an indexing deleter of the
    /// JS class here, where the first argument of the function is the field to
    /// delete.
    ///
    /// e.g. `function(x) { delete TheClass[x]; }`
    ///
    /// TODO: can we use `Reflect` or something like that to avoid an extra kind
    /// of import here?
    IndexingDeleterOfClass(JsImport),

    /// This import is expected to be a shim that is an indexing deleter of the
    /// first argument interpreted as an object where the second argument is
    /// the field to delete.
    ///
    /// e.g. `function(x, y) { delete x[y]; }`
    ///
    /// TODO: can we use `Reflect` or something like that to avoid an extra kind
    /// of import here?
    IndexingDeleterOfObject,

    /// This import is a generated shim which will wrap the provided pointer in
    /// a JS object corresponding to the Class name given here. The class name
    /// is one that is exported from the Rust/wasm.
    ///
    /// TODO: sort of like the export map below we should ideally create the
    /// `externref` from within Rust itself and then return it directly rather than
    /// requiring an intrinsic here to do so.
    WrapInExportedClass(String),

    /// This is an intrinsic function expected to be implemented with a JS glue
    /// shim. Each intrinsic has its own expected signature and implementation.
    Intrinsic(Intrinsic),

    /// This is a function which returns a URL pointing to a specific file,
    /// usually a JS snippet. The supplied path is relative to the JS glue shim.
    /// The Option may contain the contents of the linked file, so it can be
    /// embedded.
    LinkTo(String, Option<String>),

    /// This import is a generated shim which will attempt to unwrap JsValue to an
    /// instance of the given exported class. The class name is one that is
    /// exported from the Rust/wasm.
    UnwrapExportedClass(String),
}

/// Values that can be imported verbatim to hook up to an import.
#[derive(Debug)]
pub enum AuxValue {
    /// A bare JS value, no transformations, just put it in the slot.
    Bare(JsImport),

    /// A getter function for the class listed for the field, acquired using
    /// `getOwnPropertyDescriptor`.
    Getter(JsImport, String),

    /// Like `Getter`, but accesses a field of a class instead of an instance
    /// of the class.
    ClassGetter(JsImport, String),

    /// Like `Getter`, except the `set` property.
    Setter(JsImport, String),

    /// Like `Setter`, but for class fields instead of instance fields.
    ClassSetter(JsImport, String),
}

/// What can actually be imported and typically a value in each of the variants
/// above of `AuxImport`
///
/// A `JsImport` is intended to indicate what exactly is being imported for a
/// particular operation.
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
pub struct JsImport {
    /// The base of whatever is being imported, either from a module, the global
    /// namespace, or similar.
    pub name: JsImportName,
    /// Various field accesses (like `.foo.bar.baz`) to hang off the `name`
    /// above.
    pub fields: Vec<String>,
}

/// Return value of `determine_import` which is where we look at an imported
/// function AST and figure out where it's actually being imported from
/// (performing some validation checks and whatnot).
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
pub enum JsImportName {
    /// An item is imported from the global scope. The `name` is what's
    /// imported.
    Global { name: String },
    /// Same as `Global`, except the `name` is imported via an ESM import from
    /// the specified `module` path.
    Module { module: String, name: String },
    /// Same as `Module`, except we're importing from a local module defined in
    /// a local JS snippet.
    LocalModule { module: String, name: String },
    /// Same as `Module`, except we're importing from an `inline_js` attribute
    InlineJs {
        unique_crate_identifier: String,
        snippet_idx_in_crate: usize,
        name: String,
    },
    /// A global import which may have a number of vendor prefixes associated
    /// with it, like `webkitAudioPrefix`. The `name` is the name to test
    /// whether it's prefixed.
    VendorPrefixed { name: String, prefixes: Vec<String> },
}

impl walrus::CustomSection for WasmBindgenAux {
    fn name(&self) -> &str {
        "wasm-bindgen custom section"
    }

    fn data(&self, _: &walrus::IdsToIndices) -> Cow<'_, [u8]> {
        panic!("shouldn't emit custom sections just yet");
    }

    fn add_gc_roots(&self, roots: &mut walrus::passes::Roots) {
        if let Some(id) = self.externref_table {
            roots.push_table(id);
        }
        if let Some(id) = self.function_table {
            roots.push_table(id);
        }
        if let Some(id) = self.externref_alloc {
            roots.push_func(id);
        }
        if let Some(id) = self.externref_drop_slice {
            roots.push_func(id);
        }
        if let Some(id) = self.exn_store {
            roots.push_func(id);
        }
        if let Some(id) = self.destroy_closure {
            roots.push_func(id);
        }
        if let Some(id) = self.stack_pointer {
            roots.push_global(id);
        }
        if let Some(id) = self.thread_destroy {
            roots.push_func(id);
        }
        if let Some(id) = self.js_tag {
            roots.push_tag(id);
        }
    }
}