From 16f325fe61492c3c9b85242f8aa2fffb31ffcbc1 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Sat, 7 Dec 2024 17:54:18 +0100 Subject: [PATCH] Make API for exporting JS content more explicit --- crates/cli-support/src/js/mod.rs | 76 ++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index e26f7a6d2ca..9cdd2d7ddb0 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -120,6 +120,18 @@ struct FieldAccessor { is_optional: bool, } +/// Different JS constructs that can be exported. +enum ExportJs<'a> { + /// A class of the form `class Name {...}`. + Class(&'a str), + /// An anonymous function expression of the form `function(...) {...}`. + /// + /// Note that the function name is not included in the string. + Function(&'a str), + /// An arbitrary JS expression. + Expression(&'a str), +} + const INITIAL_HEAP_VALUES: &[&str] = &["undefined", "null", "true", "false"]; // Must be kept in sync with `src/lib.rs` of the `wasm-bindgen` crate const INITIAL_HEAP_OFFSET: usize = 128; @@ -163,38 +175,46 @@ impl<'a> Context<'a> { fn export( &mut self, export_name: &str, - contents: &str, + export: ExportJs, comments: Option<&str>, ) -> Result<(), Error> { let definition_name = self.generate_identifier(export_name); - if contents.starts_with("class") && definition_name != export_name { + if matches!(export, ExportJs::Class(_)) && definition_name != export_name { bail!("cannot shadow already defined class `{}`", export_name); } - let contents = contents.trim(); + // write out comments if let Some(c) = comments { self.globals.push_str(c); } + let global = match self.config.mode { - OutputMode::Node { module: false } => { - if contents.starts_with("class") { - format!("{}\nmodule.exports.{1} = {1};\n", contents, export_name) - } else { - format!("module.exports.{} = {};\n", export_name, contents) + OutputMode::Node { module: false } => match export { + ExportJs::Class(class) => { + format!("{}\nmodule.exports.{1} = {1};\n", class, export_name) } - } - OutputMode::NoModules { .. } => { - if contents.starts_with("class") { - format!("{}\n__exports.{1} = {1};\n", contents, export_name) - } else { - format!("__exports.{} = {};\n", export_name, contents) + ExportJs::Function(expr) | ExportJs::Expression(expr) => { + format!("module.exports.{} = {};\n", export_name, expr) } - } + }, + OutputMode::NoModules { .. } => match export { + ExportJs::Class(class) => { + format!("{}\n__exports.{1} = {1};\n", class, export_name) + } + ExportJs::Function(expr) | ExportJs::Expression(expr) => { + format!("__exports.{} = {};\n", export_name, expr) + } + }, OutputMode::Bundler { .. } | OutputMode::Node { module: true } | OutputMode::Web - | OutputMode::Deno => { - if let Some(body) = contents.strip_prefix("function") { + | OutputMode::Deno => match export { + ExportJs::Class(class) => { + assert_eq!(export_name, definition_name); + format!("export {}\n", class) + } + ExportJs::Function(function) => { + let body = function.strip_prefix("function").unwrap(); if export_name == definition_name { format!("export function {}{}\n", export_name, body) } else { @@ -203,14 +223,12 @@ impl<'a> Context<'a> { definition_name, body, definition_name, export_name, ) } - } else if contents.starts_with("class") { - assert_eq!(export_name, definition_name); - format!("export {}\n", contents) - } else { + } + ExportJs::Expression(expr) => { assert_eq!(export_name, definition_name); - format!("export const {} = {};\n", export_name, contents) + format!("export const {} = {};\n", export_name, expr) } - } + }, }; self.global(&global); Ok(()) @@ -1169,10 +1187,10 @@ __wbg_set_wasm(wasm);" self.write_class_field_types(class, &mut ts_dst); - dst.push_str("}\n"); + dst.push('}'); ts_dst.push_str("}\n"); - self.export(name, &dst, Some(&class.comments))?; + self.export(name, ExportJs::Class(&dst), Some(&class.comments))?; if class.generate_typescript { self.typescript.push_str(&class.comments); @@ -2872,7 +2890,11 @@ __wbg_set_wasm(wasm);" self.typescript.push_str(";\n"); } - self.export(name, &format!("function{}", code), Some(&js_docs))?; + self.export( + name, + ExportJs::Function(&format!("function{}", code)), + Some(&js_docs), + )?; self.globals.push('\n'); } AuxExportKind::Constructor(class) => { @@ -3995,7 +4017,7 @@ __wbg_set_wasm(wasm);" self.export( &enum_.name, - &format!("Object.freeze({{\n{}}})", variants), + ExportJs::Expression(&format!("Object.freeze({{\n{}}})", variants)), Some(&docs), )?;