@@ -17,6 +17,43 @@ use wit_bindgen_core::{
1717} ;
1818use wit_component:: ComponentInterfaces ;
1919
20+ // https://tc39.es/ecma262/#prod-IdentifierStartChar
21+ // Unicode ID_Start | "$" | "_"
22+ fn is_js_identifier_start ( code : char ) -> bool {
23+ return match code {
24+ 'A' ..='Z' | 'a' ..='z' | '$' | '_' => true ,
25+ // leaving out non-ascii for now...
26+ _ => false ,
27+ } ;
28+ }
29+
30+ // https://tc39.es/ecma262/#prod-IdentifierPartChar
31+ // Unicode ID_Continue | "$" | U+200C | U+200D
32+ fn is_js_identifier_char ( code : char ) -> bool {
33+ return match code {
34+ '0' ..='9' | 'A' ..='Z' | 'a' ..='z' | '$' | '_' => true ,
35+ // leaving out non-ascii for now...
36+ _ => false ,
37+ } ;
38+ }
39+
40+ fn is_js_identifier ( s : & str ) -> bool {
41+ let mut chars = s. chars ( ) ;
42+ if let Some ( char) = chars. next ( ) {
43+ if !is_js_identifier_start ( char) {
44+ return false ;
45+ }
46+ } else {
47+ return false ;
48+ }
49+ while let Some ( char) = chars. next ( ) {
50+ if !is_js_identifier_char ( char) {
51+ return false ;
52+ }
53+ }
54+ return true ;
55+ }
56+
2057#[ derive( Default ) ]
2158struct Js {
2259 /// The source code for the "main" file that's going to be created for the
@@ -191,7 +228,12 @@ impl ComponentGenerator for Js {
191228 }
192229
193230 fn finish_component ( & mut self , name : & str , files : & mut Files ) {
194- files. push ( & format ! ( "{name}.js" ) , self . src . js . as_bytes ( ) ) ;
231+ let mut bytes = self . src . js . as_bytes ( ) ;
232+ // strip leading newline
233+ if bytes[ 0 ] == b'\n' {
234+ bytes = & bytes[ 1 ..] ;
235+ }
236+ files. push ( & format ! ( "{name}.js" ) , bytes) ;
195237 if !self . opts . no_typescript {
196238 files. push ( & format ! ( "{name}.d.ts" ) , self . src . ts . as_bytes ( ) ) ;
197239 }
@@ -327,7 +369,7 @@ impl Js {
327369 " ) ,
328370
329371 Intrinsic :: IsLE => self . src . js ( "
330- const isLE = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
372+ const isLE = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
331373 " ) ,
332374
333375 Intrinsic :: ValidateGuestChar => self . src . js ( "
@@ -397,77 +439,61 @@ impl Js {
397439 " ) ,
398440
399441 Intrinsic :: ToBigInt64 => self . src . js ( "
400- function toInt64(val) {
401- return BigInt.asIntN(64, val);
402- }
442+ const toInt64 = val => BigInt.asIntN(64, val);
403443 " ) ,
404444 Intrinsic :: ToBigUint64 => self . src . js ( "
405- function toUint64(val) {
406- return BigInt.asUintN(64, val);
407- }
445+ const toUint64 = val => BigInt.asUintN(64, val);
408446 " ) ,
409447
448+ // Calling `String` almost directly calls `ToString`, except that it also allows symbols,
449+ // which is why we have the symbol-rejecting branch above.
450+ //
451+ // Definition of `String`: https://tc39.es/ecma262/#sec-string-constructor-string-value
410452 Intrinsic :: ToString => self . src . js ( "
411453 function toString(val) {
412- if (typeof val === 'symbol') {
413- throw new TypeError('symbols cannot be converted to strings');
414- } else {
415- // Calling `String` almost directly calls `ToString`, except that it also allows symbols,
416- // which is why we have the symbol-rejecting branch above.
417- //
418- // Definition of `String`: https://tc39.es/ecma262/#sec-string-constructor-string-value
419- return String(val);
420- }
454+ if (typeof val === 'symbol') throw new TypeError('symbols cannot be converted to strings');
455+ return String(val);
421456 }
422457 " ) ,
423458
424459 Intrinsic :: I32ToF32 => self . src . js ( "
425- function i32ToF32(i) {
426- i32ToF32I[0] = i;
427- return i32ToF32F[0];
428- }
460+ const i32ToF32 = i => (i32ToF32I[0] = i, i32ToF32F[0]);
429461 " ) ,
430462 Intrinsic :: F32ToI32 => self . src . js ( "
431- function f32ToI32(f) {
432- i32ToF32F[0] = f;
433- return i32ToF32I[0];
434- }
463+ const f32ToI32 = f => (i32ToF32F[0] = f, i32ToF32I[0]);
435464 " ) ,
436465 Intrinsic :: I64ToF64 => self . src . js ( "
437- function i64ToF64(i) {
438- i64ToF64I[0] = i;
439- return i64ToF64F[0];
440- }
466+ const i64ToF64 = i => (i64ToF64I[0] = i, i64ToF64F[0]);
441467 " ) ,
442468 Intrinsic :: F64ToI64 => self . src . js ( "
443- function f64ToI64(f) {
444- i64ToF64F[0] = f;
445- return i64ToF64I[0];
446- }
469+ const f64ToI64 = f => (i64ToF64F[0] = f, i64ToF64I[0]);
447470 " ) ,
448471
449472 Intrinsic :: Utf8Decoder => self
450473 . src
451- . js ( "const utf8Decoder = new TextDecoder();\n " ) ,
474+ . js ( "
475+ const utf8Decoder = new TextDecoder();
476+ " ) ,
452477
453478 Intrinsic :: Utf16Decoder => self
454479 . src
455- . js ( "const utf16Decoder = new TextDecoder('utf-16');\n " ) ,
480+ . js ( "
481+ const utf16Decoder = new TextDecoder('utf-16');
482+ " ) ,
456483
457- Intrinsic :: Utf8EncodedLen => self . src . js ( "let utf8EncodedLen = 0; \n " ) ,
484+ Intrinsic :: Utf8EncodedLen => { } ,
458485
459486 Intrinsic :: Utf8Encode => self . src . js ( "
460487 const utf8Encoder = new TextEncoder();
461488
489+ let utf8EncodedLen = 0;
462490 function utf8Encode(s, realloc, memory) {
463491 if (typeof s !== 'string') \
464492 throw new TypeError('expected a string');
465-
466493 if (s.length === 0) {
467494 utf8EncodedLen = 0;
468495 return 1;
469496 }
470-
471497 let allocLen = 0;
472498 let ptr = 0;
473499 let writtenTotal = 0;
@@ -595,7 +621,9 @@ impl Instantiator<'_> {
595621 fn instantiate ( & mut self ) {
596622 uwriteln ! (
597623 self . src. js,
598- "export async function instantiate(instantiateCore, imports) {{"
624+ "
625+ export async function instantiate(instantiateCore, imports) {{\
626+ "
599627 ) ;
600628
601629 for init in self . component . initializers . iter ( ) {
@@ -676,9 +704,19 @@ impl Instantiator<'_> {
676704 } else {
677705 imports. push_str ( "{\n " ) ;
678706 for ( module, names) in import_obj {
679- uwrite ! ( imports, "\" {module}\" : {{\n " ) ;
707+ if is_js_identifier ( module) {
708+ imports. push_str ( module) ;
709+ } else {
710+ uwrite ! ( imports, "'{module}'" ) ;
711+ }
712+ imports. push_str ( ": {\n " ) ;
680713 for ( name, val) in names {
681- uwriteln ! ( imports, "\" {name}\" : {val}," ) ;
714+ if is_js_identifier ( name) {
715+ imports. push_str ( name) ;
716+ } else {
717+ uwrite ! ( imports, "'{name}'" ) ;
718+ }
719+ uwriteln ! ( imports, ": {val}," ) ;
682720 }
683721 imports. push_str ( "},\n " ) ;
684722 }
@@ -823,7 +861,11 @@ impl Instantiator<'_> {
823861 ExportItem :: Name ( s) => s,
824862 } ;
825863 let i = export. instance . as_u32 ( ) as usize ;
826- format ! ( "instance{i}.exports[\" {name}\" ]" )
864+ if is_js_identifier ( name) {
865+ format ! ( "instance{i}.exports.{name}" )
866+ } else {
867+ format ! ( "instance{i}.exports[\" {name}\" ]" )
868+ }
827869 }
828870
829871 fn exports (
@@ -1743,7 +1785,7 @@ impl Bindgen for FunctionBindgen<'_> {
17431785 let block_result = & block_results[ 0 ] ;
17441786 self . src . js ( & format ! (
17451787 "case {i}: {{
1746- {block}
1788+ {block}\
17471789 union{tmp} = {{
17481790 tag: {i},
17491791 val: {block_result},
@@ -1788,12 +1830,12 @@ impl Bindgen for FunctionBindgen<'_> {
17881830 "
17891831 switch (variant{tmp}.tag) {{
17901832 case \" none\" : {{
1791- {none}
1833+ {none}\
17921834 break;
17931835 }}
17941836 case \" some\" : {{
17951837 const e = variant{tmp}.val;
1796- {some}
1838+ {some}\
17971839 break;
17981840 }}
17991841 default: {{
@@ -1804,15 +1846,15 @@ impl Bindgen for FunctionBindgen<'_> {
18041846 ) ) ;
18051847 } else {
18061848 self . src . js ( & format ! (
1807- "
1849+ "\
18081850 switch (variant{tmp}) {{
18091851 case null: {{
1810- {none}
1852+ {none}\
18111853 break;
18121854 }}
18131855 default: {{
18141856 const e = variant{tmp};
1815- {some}
1857+ {some}\
18161858 break;
18171859 }}
18181860 }}
@@ -1835,36 +1877,36 @@ impl Bindgen for FunctionBindgen<'_> {
18351877
18361878 if self . gen . maybe_null ( iface, payload) {
18371879 self . src . js ( & format ! (
1838- "
1880+ "\
18391881 case 0: {{
1840- {none}
1882+ {none}\
18411883 variant{tmp} = {{ tag: \" none\" }};
18421884 break;
18431885 }}
18441886 case 1: {{
1845- {some}
1887+ {some}\
18461888 variant{tmp} = {{ tag: \" some\" , val: {some_result} }};
18471889 break;
18481890 }}
18491891 " ,
18501892 ) ) ;
18511893 } else {
18521894 self . src . js ( & format ! (
1853- "
1895+ "\
18541896 case 0: {{
1855- {none}
1897+ {none}\
18561898 variant{tmp} = null;
18571899 break;
18581900 }}
18591901 case 1: {{
1860- {some}
1902+ {some}\
18611903 variant{tmp} = {some_result};
18621904 break;
18631905 }}
18641906 " ,
18651907 ) ) ;
18661908 }
1867- self . src . js ( "
1909+ self . src . js ( "\
18681910 default:
18691911 throw new RangeError(\" invalid variant discriminant for option\" );
18701912 " ) ;
@@ -1894,16 +1936,16 @@ impl Bindgen for FunctionBindgen<'_> {
18941936 }
18951937
18961938 self . src . js ( & format ! (
1897- "
1939+ "\
18981940 switch (variant{tmp}.tag) {{
18991941 case \" ok\" : {{
19001942 const e = variant{tmp}.val;
1901- {ok}
1943+ {ok}\
19021944 break;
19031945 }}
19041946 case \" err\" : {{
19051947 const e = variant{tmp}.val;
1906- {err}
1948+ {err}\
19071949 break;
19081950 }}
19091951 default: {{
@@ -1938,12 +1980,12 @@ impl Bindgen for FunctionBindgen<'_> {
19381980 let variant{tmp};
19391981 switch ({op0}) {{
19401982 case 0: {{
1941- {ok}
1983+ {ok}\
19421984 variant{tmp} = {{ tag: \" ok\" , val: {ok_result} }};
19431985 break;
19441986 }}
19451987 case 1: {{
1946- {err}
1988+ {err}\
19471989 variant{tmp} = {{ tag: \" err\" , val: {err_result} }};
19481990 break;
19491991 }}
@@ -2139,7 +2181,7 @@ impl Bindgen for FunctionBindgen<'_> {
21392181 // result.
21402182 uwriteln ! ( self . src. js, "for (let i = 0; i < {vec}.length; i++) {{" ) ;
21412183 uwriteln ! ( self . src. js, "const e = {vec}[i];" ) ;
2142- uwriteln ! ( self . src. js, "const base = {result} + i * {size};" ) ;
2184+ uwrite ! ( self . src. js, "const base = {result} + i * {size};" ) ;
21432185 self . src . js ( & body) ;
21442186 self . src . js ( "}\n " ) ;
21452187
0 commit comments