Skip to content

Commit c1a3e09

Browse files
committed
refactor: consolidate JS runtime emit functions
Extract build_js_args helper and remove duplicate emit_js_namespace_method and emit_js_namespace_getter functions. Namespace methods reuse emit_js_method/emit_js_getter with is_static=true since they generate identical JS code.
1 parent 345185c commit c1a3e09

2 files changed

Lines changed: 51 additions & 77 deletions

File tree

webapi_gen/emit/emit_js_runtime.mbt

Lines changed: 31 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -163,18 +163,11 @@ fn emit_js_setter(
163163
}
164164

165165
///|
166-
/// Emit JS method - generates appropriate argument list and call.
167-
/// `import_name` is the wasm import key (disambiguated, e.g. "fill_2"),
168-
/// `original_name` is the actual JS method name (e.g. "fill").
169-
fn emit_js_method(
170-
import_name : String,
171-
original_name : String,
166+
/// Build JS argument name and call-expression lists from WebIDL arguments.
167+
/// Returns (param_names, call_parts) where call_parts include spread for variadic args.
168+
fn build_js_args(
172169
args : Array[@parser.Argument],
173-
is_static : Bool,
174-
is_bigint? : Bool = false,
175-
interface_name? : String = "",
176-
) -> String {
177-
// Build argument names list (params without spread, call_args with spread for variadic)
170+
) -> (Array[String], Array[String]) {
178171
let arg_names : Array[String] = []
179172
let call_parts : Array[String] = []
180173
for arg in args {
@@ -186,16 +179,31 @@ fn emit_js_method(
186179
call_parts.push(name)
187180
}
188181
}
182+
(arg_names, call_parts)
183+
}
184+
185+
///|
186+
/// Emit JS method - generates appropriate argument list and call.
187+
/// `import_name` is the wasm import key (disambiguated, e.g. "fill_2"),
188+
/// `original_name` is the actual JS method name (e.g. "fill").
189+
/// Also used for namespace methods (via is_static=true, interface_name=namespace).
190+
fn emit_js_method(
191+
import_name : String,
192+
original_name : String,
193+
args : Array[@parser.Argument],
194+
is_static : Bool,
195+
is_bigint? : Bool = false,
196+
interface_name? : String = "",
197+
) -> String {
198+
let (arg_names, call_parts) = build_js_args(args)
189199
let comma_sep = ", "
190200
if is_static {
191-
// Static method: no obj parameter, call on the class directly
192201
let params = arg_names.join(comma_sep)
193202
let call_args = call_parts.join(comma_sep)
194203
let expr = "\{interface_name}.\{original_name}(\{call_args})"
195204
let expr = if is_bigint { "BigInt(\{expr})" } else { expr }
196205
" \{import_name}: (\{params}) => \{expr}"
197206
} else {
198-
// Instance method: obj is first parameter
199207
let args_str = arg_names.join(comma_sep)
200208
let params = if arg_names.length() > 0 { "obj, \{args_str}" } else { "obj" }
201209
let call_args = call_parts.join(comma_sep)
@@ -213,17 +221,7 @@ fn emit_js_constructor(
213221
interface_name : String,
214222
args : Array[@parser.Argument],
215223
) -> String {
216-
let arg_names : Array[String] = []
217-
let call_parts : Array[String] = []
218-
for arg in args {
219-
let name = js_safe(@type_mapping.safe_identifier(arg.name))
220-
arg_names.push(name)
221-
if arg.variadic {
222-
call_parts.push("...\{name}")
223-
} else {
224-
call_parts.push(name)
225-
}
226-
}
224+
let (arg_names, call_parts) = build_js_args(args)
227225
let comma_sep = ", "
228226
let params = arg_names.join(comma_sep)
229227
let call_args = call_parts.join(comma_sep)
@@ -448,47 +446,9 @@ fn emit_js_callback_module(cb : @parser.CallbackFunctionDefinition) -> String {
448446
}
449447

450448
///|
451-
/// Emit JS method for a namespace (static call with namespace prefix).
452-
fn emit_js_namespace_method(
453-
import_name : String,
454-
namespace_name : String,
455-
method_name : String,
456-
args : Array[@parser.Argument],
457-
is_bigint? : Bool = false,
458-
) -> String {
459-
let arg_names : Array[String] = []
460-
let call_parts : Array[String] = []
461-
for arg in args {
462-
let name = js_safe(@type_mapping.safe_identifier(arg.name))
463-
arg_names.push(name)
464-
if arg.variadic {
465-
call_parts.push("...\{name}")
466-
} else {
467-
call_parts.push(name)
468-
}
469-
}
470-
let comma_sep = ", "
471-
let params = arg_names.join(comma_sep)
472-
let call_args = call_parts.join(comma_sep)
473-
let expr = "\{namespace_name}.\{method_name}(\{call_args})"
474-
let expr = if is_bigint { "BigInt(\{expr})" } else { expr }
475-
" \{import_name}: (\{params}) => \{expr}"
476-
}
477-
478-
///|
479-
/// Emit JS getter for a namespace attribute.
480-
fn emit_js_namespace_getter(
481-
namespace_name : String,
482-
attr_name : String,
483-
is_bigint? : Bool = false,
484-
) -> String {
485-
let expr = "\{namespace_name}.\{attr_name}"
486-
let expr = if is_bigint { "BigInt(\{expr})" } else { expr }
487-
" get_\{attr_name}: () => \{expr}"
488-
}
489-
490-
///|
491-
/// Emit a complete JS module for a namespace
449+
/// Emit a complete JS module for a namespace.
450+
/// Reuses emit_js_method/emit_js_getter with is_static=true since
451+
/// namespace members are just static calls on the global namespace object.
492452
fn emit_js_namespace_module(
493453
ns : @partial_merged.PartialMergedNamespace,
494454
) -> String {
@@ -508,21 +468,23 @@ fn emit_js_namespace_module(
508468
used_method_names,
509469
)
510470
entries.push(
511-
emit_js_namespace_method(
471+
emit_js_method(
512472
import_name,
513-
ns.name,
514473
op.name,
515474
op.arguments,
475+
true,
516476
is_bigint=is_bigint_type(op.return_type),
477+
interface_name=ns.name,
517478
),
518479
)
519480
}
520481
Attribute(attr) =>
521482
entries.push(
522-
emit_js_namespace_getter(
523-
ns.name,
483+
emit_js_getter(
524484
attr.name,
485+
is_static=true,
525486
is_bigint=is_bigint_type(attr.type_),
487+
interface_name=ns.name,
526488
),
527489
)
528490
Const(_) => continue // Constants don't need JS runtime entries

webapi_gen/emit/emit_js_runtime_wbtest.mbt

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -241,35 +241,47 @@ test "emit_js_special_operation deleter" {
241241
}
242242

243243
///|
244-
test "emit_js_namespace_method" {
244+
test "emit_js_method static for namespace" {
245245
let args = [make_arg("data", @parser.Type::Any, variadic=true)]
246246
inspect(
247-
emit_js_namespace_method("log", "console", "log", args),
247+
emit_js_method("log", "log", args, true, interface_name="console"),
248248
content=" log: (data) => console.log(...data)",
249249
)
250250
}
251251

252252
///|
253-
test "emit_js_namespace_method with bigint" {
253+
test "emit_js_method static for namespace with bigint" {
254254
let args : Array[@parser.Argument] = []
255255
inspect(
256-
emit_js_namespace_method("now", "performance", "now", args, is_bigint=true),
256+
emit_js_method(
257+
"now",
258+
"now",
259+
args,
260+
true,
261+
is_bigint=true,
262+
interface_name="performance",
263+
),
257264
content=" now: () => BigInt(performance.now())",
258265
)
259266
}
260267

261268
///|
262-
test "emit_js_namespace_getter" {
269+
test "emit_js_getter static for namespace" {
263270
inspect(
264-
emit_js_namespace_getter("console", "enabled"),
271+
emit_js_getter("enabled", is_static=true, interface_name="console"),
265272
content=" get_enabled: () => console.enabled",
266273
)
267274
}
268275

269276
///|
270-
test "emit_js_namespace_getter with bigint" {
277+
test "emit_js_getter static for namespace with bigint" {
271278
inspect(
272-
emit_js_namespace_getter("performance", "timeOrigin", is_bigint=true),
279+
emit_js_getter(
280+
"timeOrigin",
281+
is_static=true,
282+
is_bigint=true,
283+
interface_name="performance",
284+
),
273285
content=" get_timeOrigin: () => BigInt(performance.timeOrigin)",
274286
)
275287
}

0 commit comments

Comments
 (0)