Skip to content

Commit 194cd9e

Browse files
SanderVanRiessens.vanriessen
andauthored
fix: duplicated function names for same interfaces and export (#306)
* fix: duplicated function names for same interfaces and export * chore: formatting * chore: remove to string function on import string * tests: add duplicated function name test * test: add dup interface test * test: replace import override to test file * chore: rename binding name function --------- Co-authored-by: s.vanriessen <sander.vanriessen@bettyblocks.com>
1 parent 629bd96 commit 194cd9e

File tree

9 files changed

+114
-8
lines changed

9 files changed

+114
-8
lines changed

crates/spidermonkey-embedding-splicer/src/bindgen.rs

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,12 @@ pub fn componentize_bindgen(
172172
// consolidate import specifiers and generate wrappers
173173
// we do this separately because function index order matters
174174
let mut import_bindings = Vec::new();
175-
for (_, item) in bindgen.imports.iter() {
175+
for (specifier, item) in bindgen.imports.iter() {
176176
// this import binding order matters
177-
import_bindings.push(binding_name(
177+
import_bindings.push(generate_binding_name_import(
178178
&item.resource.func_name(&item.name),
179179
&item.iface_name,
180+
specifier,
180181
));
181182
}
182183

@@ -204,7 +205,11 @@ pub fn componentize_bindgen(
204205
let item = items.first().unwrap();
205206
if let Some(resource) = resource {
206207
let export_name = resource.to_upper_camel_case();
207-
let binding_name = binding_name(&export_name, &item.iface_name);
208+
let binding_name = generate_binding_name_import(
209+
&export_name,
210+
&item.iface_name,
211+
&item.binding_name,
212+
);
208213
if item.iface {
209214
specifier_list.push(format!("{export_name}: import_{binding_name}"));
210215
} else {
@@ -213,13 +218,12 @@ pub fn componentize_bindgen(
213218
} else {
214219
for BindingItem {
215220
iface,
216-
iface_name,
217221
name,
222+
binding_name,
218223
..
219224
} in items
220225
{
221226
let export_name = name.to_lower_camel_case();
222-
let binding_name = binding_name(&export_name, iface_name);
223227
if *iface {
224228
specifier_list.push(format!("{export_name}: import_{binding_name}"));
225229
} else {
@@ -654,11 +658,12 @@ impl JsBindgen<'_> {
654658
let fn_name = func.item_name();
655659
let fn_camel_name = fn_name.to_lower_camel_case();
656660

657-
use binding_name as binding_name_fn;
661+
use generate_binding_name_import as binding_name_fn;
658662

659663
let (binding_name, resource) = match &func.kind {
660664
FunctionKind::Freestanding => {
661-
let binding_name = binding_name(&fn_camel_name, &iface_name);
665+
let binding_name =
666+
generate_binding_name_import(&fn_camel_name, &iface_name, &import_name);
662667

663668
uwrite!(self.src, "\nfunction import_{binding_name}");
664669

@@ -702,7 +707,11 @@ impl JsBindgen<'_> {
702707
func.params.len(),
703708
&format!(
704709
"$import_{}",
705-
binding_name_fn(&resource.func_name(fn_name), &iface_name)
710+
binding_name_fn(
711+
&resource.func_name(fn_name),
712+
&iface_name,
713+
import_name.as_str()
714+
)
706715
),
707716
StringEncoding::UTF8,
708717
func,
@@ -1294,6 +1303,40 @@ fn binding_name(func_name: &str, iface_name: &Option<String>) -> String {
12941303
}
12951304
}
12961305

1306+
/// Determine the binding name of a given import
1307+
/// example wit:
1308+
/// package local:hello;
1309+
/// interface greeter {
1310+
/// greet(name: string): string;
1311+
/// }
1312+
/// word main {
1313+
/// export greeter;
1314+
/// }
1315+
///
1316+
/// # Arguments
1317+
/// * `func_name` - function name (e.g. `greet`)
1318+
/// * `iface_name` - an interface name, if present (e.g. `greeter`)
1319+
/// * `import_name` - qualified import specifier (e.g. `local:hello`)
1320+
///
1321+
fn generate_binding_name_import(
1322+
func_name: &str,
1323+
iface_name: &Option<String>,
1324+
import_name: &str,
1325+
) -> String {
1326+
// import_name is only valid when FunctionKind is Freestanding
1327+
if import_name != "<<INVALID>>" {
1328+
let valid_import = import_name
1329+
.chars()
1330+
.map(|c| if c.is_alphanumeric() { c } else { '_' })
1331+
.collect::<String>();
1332+
format!("{valid_import}${func_name}")
1333+
} else if let Some(iface_name) = iface_name {
1334+
format!("{iface_name}${func_name}")
1335+
} else {
1336+
func_name.to_string()
1337+
}
1338+
}
1339+
12971340
/// Extract success and error types from a given optional type, if it is a Result
12981341
pub fn get_result_types(
12991342
resolve: &Resolve,

test/bindings.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ suite('Bindings', async () => {
9797
if (impt.startsWith('wasi:')) continue;
9898
if (impt.startsWith('[')) impt = impt.slice(impt.indexOf(']') + 1);
9999
let importName = impt.split('/').pop();
100+
if (testcase.importNameOverride)
101+
importName = testcase.importNameOverride(impt);
100102
if (importName === 'test') importName = 'imports';
101103
map[impt] = `../../cases/${name}/${importName}.js`;
102104
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function hello(name) {
2+
return `Hello 1.0.0, ${name}`
3+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function hello(name) {
2+
if (name) {
3+
return `Hello 2.0.0, ${name}`
4+
} else {
5+
return undefined
6+
}
7+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { hello as hello1 } from 'local:hello/hello';
2+
import { hello as hello2 } from 'local:hello-second/hello';
3+
4+
export const exports = {
5+
hello(str) {
6+
if (str === 'hello') {
7+
return `world ${str} (${hello1('world')})`;
8+
}
9+
if (str === 'hello-second') {
10+
return `world ${str} (${hello2('world')})`;
11+
}
12+
return `world unknown ${str}`;
13+
},
14+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { strictEqual } from 'node:assert';
2+
3+
export function test(instance) {
4+
strictEqual(
5+
instance.exports.hello('hello'),
6+
'world hello (Hello 1.0.0, world)'
7+
);
8+
strictEqual(
9+
instance.exports.hello('hello-second'),
10+
'world hello-second (Hello 2.0.0, world)'
11+
);
12+
strictEqual(instance.exports.hello('unknown'), 'world unknown unknown');
13+
}
14+
15+
export function importNameOverride(importName) {
16+
return importName.replace('/', '-').replace(':', '-');
17+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package local:hello-second;
2+
3+
interface hello {
4+
hello: func(name: option<string>) -> option<string>;
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package local:hello;
2+
3+
interface hello {
4+
hello: func(name: string) -> string;
5+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package test:test;
2+
3+
world hello {
4+
import local:hello/hello;
5+
import local:hello-second/hello;
6+
7+
export exports: interface {
8+
hello: func(name: string) -> string;
9+
}
10+
}

0 commit comments

Comments
 (0)