@bytecodealliance/jco 0.13.3 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +23 -21
  2. package/lib/wasi_snapshot_preview1.command.wasm +0 -0
  3. package/lib/wasi_snapshot_preview1.reactor.wasm +0 -0
  4. package/obj/interfaces/wasi-filesystem-types.d.ts +1 -6
  5. package/obj/interfaces/wasi-io-error.d.ts +6 -0
  6. package/obj/interfaces/wasi-io-streams.d.ts +7 -9
  7. package/obj/js-component-bindgen-component.component.wasm +0 -0
  8. package/obj/js-component-bindgen-component.core.wasm +0 -0
  9. package/obj/js-component-bindgen-component.core2.wasm +0 -0
  10. package/obj/js-component-bindgen-component.d.ts +11 -2
  11. package/obj/js-component-bindgen-component.js +478 -453
  12. package/obj/wasm-tools.component.wasm +0 -0
  13. package/obj/wasm-tools.core.wasm +0 -0
  14. package/obj/wasm-tools.core2.wasm +0 -0
  15. package/obj/wasm-tools.d.ts +1 -0
  16. package/obj/wasm-tools.js +408 -420
  17. package/package.json +7 -5
  18. package/src/api.d.ts +42 -0
  19. package/src/api.d.ts.map +1 -0
  20. package/src/browser.d.ts +3 -0
  21. package/src/browser.d.ts.map +1 -0
  22. package/src/browser.js +11 -3
  23. package/src/cmd/componentize.d.ts +2 -0
  24. package/src/cmd/componentize.d.ts.map +1 -0
  25. package/src/cmd/componentize.js +1 -0
  26. package/src/cmd/opt.d.ts +15 -0
  27. package/src/cmd/opt.d.ts.map +1 -0
  28. package/src/cmd/run.d.ts +2 -0
  29. package/src/cmd/run.d.ts.map +1 -0
  30. package/src/cmd/run.js +22 -6
  31. package/src/cmd/transpile.d.ts +44 -0
  32. package/src/cmd/transpile.d.ts.map +1 -0
  33. package/src/cmd/transpile.js +206 -47
  34. package/src/cmd/wasm-tools.d.ts +8 -0
  35. package/src/cmd/wasm-tools.d.ts.map +1 -0
  36. package/src/cmd/wasm-tools.js +3 -2
  37. package/src/common.d.ts +16 -0
  38. package/src/common.d.ts.map +1 -0
  39. package/src/common.js +3 -0
  40. package/src/jco.d.ts +3 -0
  41. package/src/jco.d.ts.map +1 -0
  42. package/src/jco.js +9 -4
  43. package/src/ora-shim.d.ts +7 -0
  44. package/src/ora-shim.d.ts.map +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytecodealliance/jco",
3
- "version": "0.13.3",
3
+ "version": "0.14.1",
4
4
  "description": "JavaScript tooling for working with WebAssembly Components",
5
5
  "author": "Guy Bedford",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "type": "module",
20
20
  "dependencies": {
21
- "@bytecodealliance/preview2-shim": "0.0.21",
21
+ "@bytecodealliance/preview2-shim": "0.14.1",
22
22
  "binaryen": "^111.0.0",
23
23
  "chalk-template": "^0.4.0",
24
24
  "commander": "^9.4.1",
@@ -27,7 +27,7 @@
27
27
  "terser": "^5.16.1"
28
28
  },
29
29
  "devDependencies": {
30
- "@bytecodealliance/componentize-js": "^0.4.1",
30
+ "@bytecodealliance/componentize-js": "^0.5.0",
31
31
  "@types/node": "^18.11.17",
32
32
  "@typescript-eslint/eslint-plugin": "^5.41.0",
33
33
  "@typescript-eslint/parser": "^5.41.0",
@@ -51,10 +51,12 @@
51
51
  },
52
52
  "homepage": "https://github.com/bytecodealliance/jco#readme",
53
53
  "scripts": {
54
- "build": "cargo xtask build workspace",
54
+ "build": "cargo xtask build debug",
55
+ "build:release": "cargo xtask build release",
55
56
  "build:types:preview2-shim": "cargo xtask generate wasi-types",
56
57
  "lint": "eslint -c eslintrc.cjs lib/**/*.js packages/*/lib/**/*.js",
57
- "test": "mocha -u tdd test/test.js --timeout 120000"
58
+ "test": "mocha -u tdd test/test.js --timeout 120000",
59
+ "prepublishOnly": "cargo xtask build release && npm run test"
58
60
  },
59
61
  "files": [
60
62
  "lib",
package/src/api.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @param {Parameters<import('../obj/wasm-tools.js').print>[0]} binary
3
+ * @return {Promise<ReturnType<import('../obj/wasm-tools.js').print>>}
4
+ */
5
+ export function print(binary: Parameters<import('../obj/wasm-tools.js').print>[0]): Promise<ReturnType<import('../obj/wasm-tools.js').print>>;
6
+ /**
7
+ * @param {Parameters<import('../obj/wasm-tools.js').parse>[0]} wat
8
+ * @return {Promise<ReturnType<import('../obj/wasm-tools.js').parse>>}
9
+ */
10
+ export function parse(wat: Parameters<import('../obj/wasm-tools.js').parse>[0]): Promise<ReturnType<import('../obj/wasm-tools.js').parse>>;
11
+ /**
12
+ * @param {Parameters<import('../obj/wasm-tools.js').componentWit>[0]} binary
13
+ * @return {Promise<ReturnType<import('../obj/wasm-tools.js').componentWit>>}
14
+ */
15
+ export function componentWit(binary: Parameters<import('../obj/wasm-tools.js').componentWit>[0]): Promise<ReturnType<import('../obj/wasm-tools.js').componentWit>>;
16
+ /**
17
+ * @param {Parameters<import('../obj/wasm-tools.js').componentNew>[0]} binary
18
+ * @param {Parameters<import('../obj/wasm-tools.js').componentNew>[1]} adapters
19
+ * @return {Promise<ReturnType<import('../obj/wasm-tools.js').componentNew>>}
20
+ */
21
+ export function componentNew(binary: Parameters<import('../obj/wasm-tools.js').componentNew>[0], adapters: Parameters<import('../obj/wasm-tools.js').componentNew>[1]): Promise<ReturnType<import('../obj/wasm-tools.js').componentNew>>;
22
+ /**
23
+ * @param {Parameters<import('../obj/wasm-tools.js').componentEmbed>[0]} embedOpts
24
+ * @return {Promise<ReturnType<import('../obj/wasm-tools.js').componentEmbed>>}
25
+ */
26
+ export function componentEmbed(embedOpts: Parameters<import('../obj/wasm-tools.js').componentEmbed>[0]): Promise<ReturnType<import('../obj/wasm-tools.js').componentEmbed>>;
27
+ /**
28
+ * @param {Parameters<import('../obj/wasm-tools.js').metadataAdd>[0]} binary
29
+ * @param {Parameters<import('../obj/wasm-tools.js').metadataAdd>[1]} metadata
30
+ * @return {Promise<ReturnType<import('../obj/wasm-tools.js').metadataAdd>>}
31
+ */
32
+ export function metadataAdd(binary: Parameters<import('../obj/wasm-tools.js').metadataAdd>[0], metadata: Parameters<import('../obj/wasm-tools.js').metadataAdd>[1]): Promise<ReturnType<import('../obj/wasm-tools.js').metadataAdd>>;
33
+ /**
34
+ * @param {Parameters<import('../obj/wasm-tools.js').metadataShow>[0]} binary
35
+ * @return {Promise<ReturnType<import('../obj/wasm-tools.js').metadataShow>>}
36
+ */
37
+ export function metadataShow(binary: Parameters<import('../obj/wasm-tools.js').metadataShow>[0]): Promise<ReturnType<import('../obj/wasm-tools.js').metadataShow>>;
38
+ export function preview1AdapterCommandPath(): URL;
39
+ export function preview1AdapterReactorPath(): URL;
40
+ export { optimizeComponent as opt } from "./cmd/opt.js";
41
+ export { transpileComponent as transpile } from "./cmd/transpile.js";
42
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["api.js"],"names":[],"mappings":"AAKA;;;GAGG;AACH,8BAHW,WAAW,OAAO,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAClD,QAAQ,WAAW,OAAO,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAKpE;AACD;;;GAGG;AACH,2BAHW,WAAW,OAAO,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAClD,QAAQ,WAAW,OAAO,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAKpE;AACD;;;GAGG;AACH,qCAHW,WAAW,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,GACzD,QAAQ,WAAW,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC,CAK3E;AACD;;;;GAIG;AACH,qCAJW,WAAW,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,YAC1D,WAAW,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,GACzD,QAAQ,WAAW,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC,CAK3E;AACD;;;GAGG;AACH,0CAHW,WAAW,OAAO,sBAAsB,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,GAC3D,QAAQ,WAAW,OAAO,sBAAsB,EAAE,cAAc,CAAC,CAAC,CAK7E;AACD;;;;GAIG;AACH,oCAJW,WAAW,OAAO,sBAAsB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,YACzD,WAAW,OAAO,sBAAsB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,GACxD,QAAQ,WAAW,OAAO,sBAAsB,EAAE,WAAW,CAAC,CAAC,CAK1E;AACD;;;GAGG;AACH,qCAHW,WAAW,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,GACzD,QAAQ,WAAW,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC,CAK3E;AACD,kDAEC;AACD,kDAEC"}
@@ -0,0 +1,3 @@
1
+ export function transpile(...args: any[]): Promise<any>;
2
+ export function generateTypes(...args: any[]): Promise<any>;
3
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["browser.js"],"names":[],"mappings":"AAEA,wDAGC;AAED,4DAGC"}
package/src/browser.js CHANGED
@@ -1,3 +1,11 @@
1
- import { $init, generate, generateTypes } from '../obj/js-component-bindgen-component.js';
2
- await $init;
3
- export { generate as transpile, generateTypes }
1
+ import { $init, generate, generateTypes as _generateTypes } from '../obj/js-component-bindgen-component.js';
2
+
3
+ export async function transpile () {
4
+ await $init;
5
+ return generate.apply(this, arguments);
6
+ }
7
+
8
+ export async function generateTypes () {
9
+ await $init;
10
+ return _generateTypes.apply(this, arguments);
11
+ }
@@ -0,0 +1,2 @@
1
+ export function componentize(jsSource: any, opts: any): Promise<void>;
2
+ //# sourceMappingURL=componentize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"componentize.d.ts","sourceRoot":"","sources":["componentize.js"],"names":[],"mappings":"AAKA,sEAkBC"}
@@ -1,6 +1,7 @@
1
1
  import { readFile, writeFile } from 'node:fs/promises';
2
2
  import { resolve } from 'node:path';
3
3
  import c from 'chalk-template';
4
+ import { isWindows } from '../common.js';
4
5
 
5
6
  export async function componentize (jsSource, opts) {
6
7
  let componentizeFn;
@@ -0,0 +1,15 @@
1
+ export function opt(componentPath: any, opts: any, program: any): Promise<void>;
2
+ /**
3
+ *
4
+ * @param {Uint8Array} componentBytes
5
+ * @param {{ quiet: boolean, optArgs?: string[] }} options?
6
+ * @returns {Promise<{ component: Uint8Array, compressionInfo: { beforeBytes: number, afterBytes: number }[] >}
7
+ */
8
+ export function optimizeComponent(componentBytes: Uint8Array, opts: any): Promise<{
9
+ component: Uint8Array;
10
+ compressionInfo: {
11
+ beforeBytes: number;
12
+ afterBytes: number;
13
+ }[];
14
+ }>;
15
+ //# sourceMappingURL=opt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opt.d.ts","sourceRoot":"","sources":["opt.js"],"names":[],"mappings":"AAeA,gFAoCC;AAED;;;;;GAKG;AACH,kDAJW,UAAU,cAER,QAAQ;IAAE,SAAS,EAAE,UAAU,CAAC;IAAC,eAAe,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAA,CAAE,CA8E7G"}
@@ -0,0 +1,2 @@
1
+ export function run(componentPath: any, args: any, opts: any): Promise<void>;
2
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["run.js"],"names":[],"mappings":"AASA,6EA+FC"}
package/src/cmd/run.js CHANGED
@@ -4,15 +4,20 @@ import { rm, stat, mkdir, writeFile, symlink } from 'node:fs/promises';
4
4
  import { basename, resolve, extname } from 'node:path';
5
5
  import { fork } from 'node:child_process';
6
6
  import process from 'node:process';
7
- import { fileURLToPath } from 'node:url';
7
+ import { fileURLToPath, pathToFileURL } from 'node:url';
8
8
  import c from 'chalk-template';
9
9
 
10
- export async function run (componentPath, args) {
10
+ export async function run (componentPath, args, opts) {
11
11
  // Ensure that `args` is an array
12
12
  args = [...args];
13
13
 
14
+ const jcoImport = opts.jcoImport ? resolve(opts.jcoImport) : null;
15
+
14
16
  const name = basename(componentPath.slice(0, -extname(componentPath).length || Infinity));
15
- const outDir = await getTmpDir();
17
+ const outDir = opts.jcoDir || await getTmpDir();
18
+ if (opts.jcoDir) {
19
+ await mkdir(outDir, { recursive: true });
20
+ }
16
21
  try {
17
22
  try {
18
23
  await transpile(componentPath, {
@@ -20,7 +25,8 @@ export async function run (componentPath, args) {
20
25
  quiet: true,
21
26
  noTypescript: true,
22
27
  wasiShim: true,
23
- outDir
28
+ outDir,
29
+ tracing: opts.jcoTrace
24
30
  });
25
31
  }
26
32
  catch (e) {
@@ -46,10 +52,17 @@ export async function run (componentPath, args) {
46
52
 
47
53
  const modulesDir = resolve(outDir, 'node_modules', '@bytecodealliance');
48
54
  await mkdir(modulesDir, { recursive: true });
49
- await symlink(preview2ShimPath, resolve(modulesDir, 'preview2-shim'), 'dir');
55
+
56
+ try {
57
+ await symlink(preview2ShimPath, resolve(modulesDir, 'preview2-shim'), 'dir');
58
+ } catch (e) {
59
+ if (e.code !== 'EEXIST')
60
+ throw e;
61
+ }
50
62
 
51
63
  const runPath = resolve(outDir, '_run.js');
52
64
  await writeFile(runPath, `
65
+ ${jcoImport ? `import ${JSON.stringify(pathToFileURL(jcoImport))}` : ''}
53
66
  function logInvalidCommand () {
54
67
  console.error('Not a valid command component to execute, make sure it was built to a command adapter and with the same version.');
55
68
  }
@@ -62,6 +75,8 @@ export async function run (componentPath, args) {
62
75
  }
63
76
  try {
64
77
  mod.run.run();
78
+ // TODO: figure out stdout flush!
79
+ setTimeout(() => {});
65
80
  }
66
81
  catch (e) {
67
82
  console.error(e);
@@ -83,7 +98,8 @@ export async function run (componentPath, args) {
83
98
  }
84
99
  finally {
85
100
  try {
86
- await rm(outDir, { recursive: true });
101
+ if (!opts.jcoDir)
102
+ await rm(outDir, { recursive: true });
87
103
  } catch {}
88
104
  }
89
105
  }
@@ -0,0 +1,44 @@
1
+ export function transpile(componentPath: any, opts: any, program: any): Promise<void>;
2
+ /**
3
+ *
4
+ * @param {Uint8Array} component
5
+ * @param {{
6
+ * name: string,
7
+ * instantiation?: 'async' | 'sync',
8
+ * map?: Record<string, string>,
9
+ * validLiftingOptimization?: bool,
10
+ * tracing?: bool,
11
+ * nodejsCompat?: bool,
12
+ * tlaCompat?: bool,
13
+ * base64Cutoff?: bool,
14
+ * js?: bool,
15
+ * minify?: bool,
16
+ * optimize?: bool,
17
+ * namespacedExports?: bool,
18
+ * optArgs?: string[],
19
+ * }} opts
20
+ * @returns {Promise<{ files: { [filename: string]: Uint8Array }, imports: string[], exports: [string, 'function' | 'instance'][] }>}
21
+ */
22
+ export function transpileComponent(component: Uint8Array, opts?: {
23
+ name: string;
24
+ instantiation?: 'async' | 'sync';
25
+ map?: Record<string, string>;
26
+ validLiftingOptimization?: bool;
27
+ tracing?: bool;
28
+ nodejsCompat?: bool;
29
+ tlaCompat?: bool;
30
+ base64Cutoff?: bool;
31
+ js?: bool;
32
+ minify?: bool;
33
+ optimize?: bool;
34
+ namespacedExports?: bool;
35
+ optArgs?: string[];
36
+ }): Promise<{
37
+ files: {
38
+ [filename: string]: Uint8Array;
39
+ };
40
+ imports: string[];
41
+ exports: [string, 'function' | 'instance'][];
42
+ }>;
43
+ import { minify } from "terser";
44
+ //# sourceMappingURL=transpile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transpile.d.ts","sourceRoot":"","sources":["transpile.js"],"names":[],"mappings":"AAWA,sFA2BC;AAuBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,8CAlBW,UAAU;UAEV,MAAM;oBACI,OAAO,GAAG,MAAM;UAC1B,OAAO,MAAM,EAAE,MAAM,CAAC;;;;;;;;;;cAUlB,MAAM,EAAE;;;;;aAEoD,MAAM,EAAE;aAAW,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAAC,EAAE;GAmShI"}
@@ -46,7 +46,7 @@ try {
46
46
  }
47
47
 
48
48
  /**
49
- * @param {Uint8Array} source
49
+ * @param {Uint8Array} source
50
50
  * @returns {Promise<Uint8Array>}
51
51
  */
52
52
  async function wasm2Js (source) {
@@ -60,22 +60,23 @@ async function wasm2Js (source) {
60
60
  }
61
61
 
62
62
  /**
63
- *
64
- * @param {Uint8Array} component
63
+ *
64
+ * @param {Uint8Array} component
65
65
  * @param {{
66
66
  * name: string,
67
- * instantiation?: bool,
67
+ * instantiation?: 'async' | 'sync',
68
68
  * map?: Record<string, string>,
69
69
  * validLiftingOptimization?: bool,
70
70
  * tracing?: bool,
71
- * noNodejsCompat?: bool,
71
+ * nodejsCompat?: bool,
72
72
  * tlaCompat?: bool,
73
73
  * base64Cutoff?: bool,
74
74
  * js?: bool,
75
75
  * minify?: bool,
76
76
  * optimize?: bool,
77
+ * namespacedExports?: bool,
77
78
  * optArgs?: string[],
78
- * }} opts
79
+ * }} opts
79
80
  * @returns {Promise<{ files: { [filename: string]: Uint8Array }, imports: string[], exports: [string, 'function' | 'instance'][] }>}
80
81
  */
81
82
  export async function transpileComponent (component, opts = {}) {
@@ -96,23 +97,33 @@ export async function transpileComponent (component, opts = {}) {
96
97
  'wasi:filesystem/*': '@bytecodealliance/preview2-shim/filesystem#*',
97
98
  'wasi:http/*': '@bytecodealliance/preview2-shim/http#*',
98
99
  'wasi:io/*': '@bytecodealliance/preview2-shim/io#*',
99
- 'wasi:logging/*': '@bytecodealliance/preview2-shim/logging#*',
100
- 'wasi:poll/*': '@bytecodealliance/preview2-shim/poll#*',
101
100
  'wasi:random/*': '@bytecodealliance/preview2-shim/random#*',
102
101
  'wasi:sockets/*': '@bytecodealliance/preview2-shim/sockets#*',
103
102
  }, opts.map || {});
104
103
  }
105
104
 
105
+ let instantiation = null;
106
+
107
+ // Let's define `instantiation` from `--instantiation` if it's present.
108
+ if (opts.instantiation) {
109
+ instantiation = { tag: opts.instantiation };
110
+ }
111
+ // Otherwise, if `--js` is present, an `instantiate` function is required.
112
+ else if (opts.js) {
113
+ instantiation = { tag: 'async' };
114
+ }
115
+
106
116
  let { files, imports, exports } = generate(component, {
107
117
  name: opts.name ?? 'component',
108
118
  map: Object.entries(opts.map ?? {}),
109
- instantiation: opts.instantiation || opts.js,
119
+ instantiation,
110
120
  validLiftingOptimization: opts.validLiftingOptimization ?? false,
111
121
  tracing: opts.tracing ?? false,
112
122
  noNodejsCompat: !(opts.nodejsCompat ?? true),
113
123
  noTypescript: opts.noTypescript || false,
114
124
  tlaCompat: opts.tlaCompat ?? false,
115
- base64Cutoff: opts.js ? 0 : opts.base64Cutoff ?? 5000
125
+ base64Cutoff: opts.js ? 0 : opts.base64Cutoff ?? 5000,
126
+ noNamespacedExports: opts.namespacedExports === false,
116
127
  });
117
128
 
118
129
  let outDir = (opts.outDir ?? '').replace(/\\/g, '/');
@@ -122,16 +133,67 @@ export async function transpileComponent (component, opts = {}) {
122
133
 
123
134
  const jsFile = files.find(([name]) => name.endsWith('.js'));
124
135
 
136
+ // Generate code for the `--js` option.
137
+ //
138
+ // `--js` can be called with or without `--instantiation`. The generated code
139
+ // isn't exactly the same!
140
+ //
141
+ // `--js` needs an `instantiate` function to work, so it might look like
142
+ // `--instantiation` is always implied, but actually no. It is correct
143
+ // that when `--js` is present, an `instantiate` function _is_ generated,
144
+ // but it doesn't mean that we expect the function to be used, it's simply
145
+ // not exported, plus `instantiate` is automatically called (if `--tla-compat`
146
+ // is `false`). When `--instantiation` is missing, functions are exported
147
+ // with the `export` directive, and imports are imported with the `import`
148
+ // directive. When `--instantiation` is present, there is no `export` and no
149
+ // `import`: only a single exported `instantiate` function.
150
+ //
151
+ // Basically, we get this:
152
+ //
153
+ // * `--js` only:
154
+ // * `instantiate` is renamed to `_instantiate`,
155
+ // * A new `instantiate` function is created, that calls `_instantiate` with
156
+ // the correct imports (which are ASM.js code) and returns the exports,
157
+ // * A new `$init` function is created, that calls `instantiate` and maps
158
+ // the returned exports to their respective trampolines,
159
+ // * Trampolines are exported,
160
+ // * `$init` is called automatically.
161
+ //
162
+ // * `--js` with `--tla-compat`:
163
+ // * Same as with `--js` only, except that `$init` is exported instead of
164
+ // being called immediately.
165
+ //
166
+ // * `--js` with `--instantiation[=async]`:
167
+ // * `instantiate` is renamed to `_instantiate`,
168
+ // * A new `instantiate` function is created, that calls `_instantiate` with
169
+ // the correct imports (which are ASM.js code) and returns the exports,
170
+ // * `instantiate` is exported.
171
+ //
172
+ // * `--js` with `--instantiation=sync`:
173
+ // * Same as `--js` with `--instantiation[=async]`, except that
174
+ // `_instantiate` and `instantiate` are non-async.
175
+ //
176
+ // Be careful with the variables: `opts.instantiation` reflects the presence
177
+ // or the absence of the `--instantiation` flag, whilst `instantiation`
178
+ // reflects how the `instantiate` function must be generated. We also use
179
+ // `instantiation` to know whether the generated code must be async or
180
+ // non-async.
125
181
  if (opts.js) {
182
+ const withInstantiation = opts.instantiation !== undefined;
183
+ const async_ = instantiation.tag == 'async' ? 'async ' : '';
184
+ const await_ = instantiation.tag == 'async' ? 'await ' : '';
185
+
186
+ // Format the previously generated code.
126
187
  const source = Buffer.from(jsFile[1]).toString('utf8')
127
188
  // update imports manging to match emscripten asm
128
- .replace(/exports(\d+)\['([^']+)']/g, (_, i, s) => `exports${i}['${asmMangle(s)}']`);
129
-
189
+ .replace(/exports(\d+)\['([^']+)']/g, (_, i, s) => `exports${i}['${asmMangle(s)}']`)
190
+ .replace(/export (async )?function instantiate/, '$1function _instantiate') ;
191
+
192
+ // Collect all Wasm files.
130
193
  const wasmFiles = files.filter(([name]) => name.endsWith('.wasm'));
131
194
  files = files.filter(([name]) => !name.endsWith('.wasm'));
132
195
 
133
- // TODO: imports as specifier list
134
-
196
+ // Configure the spinner.
135
197
  let completed = 0;
136
198
  const spinnerText = () => c`{cyan ${completed} / ${wasmFiles.length}} Running Binaryen wasm2js on Wasm core modules (this takes a while)...\n`;
137
199
  if (showSpinner) {
@@ -142,6 +204,7 @@ export async function transpileComponent (component, opts = {}) {
142
204
  spinner.text = spinnerText();
143
205
  }
144
206
 
207
+ // Compile all Wasm modules into ASM.js codes.
145
208
  try {
146
209
  const asmFiles = await Promise.all(wasmFiles.map(async ([, source]) => {
147
210
  const output = (await wasm2Js(source)).toString('utf8');
@@ -152,44 +215,140 @@ export async function transpileComponent (component, opts = {}) {
152
215
  return output;
153
216
  }));
154
217
 
155
- const asms = asmFiles.map((asm, i) =>`function asm${i}(imports) {
218
+ const asms = asmFiles.map((asm, nth) => `function asm${nth}(imports) {
156
219
  ${
157
- // strip and replace the asm instantiation wrapper
158
- asm
159
- .replace(/import \* as [^ ]+ from '[^']*';/g, '')
160
- .replace('function asmFunc(imports) {', '')
161
- .replace(/export var ([^ ]+) = ([^. ]+)\.([^ ]+);/g, '')
162
- .replace(/var retasmFunc = [\s\S]*$/, '')
163
- .replace(/var memasmFunc = new ArrayBuffer\(0\);/g, '')
164
- .replace('memory.grow = __wasm_memory_grow;', '')
165
- .trim()
166
- }`).join(',\n');
167
-
168
- const outSource = `${
169
- imports.map((impt, i) => `import * as import${i} from '${impt}';`).join('\n')}
170
- ${source.replace('export async function instantiate', 'async function instantiate')}
171
-
172
- let ${exports.filter(([, ty]) => ty === 'function').map(([name]) => '_' + name).join(', ')};
173
-
174
- ${exports.map(([name, ty]) => ty === 'function' ? `\nfunction ${asmMangle(name)} () {
175
- return _${name}.apply(this, arguments);
176
- }` : `\nlet ${asmMangle(name)};`).join('\n')}
220
+ // strip and replace the asm instantiation wrapper
221
+ asm
222
+ .replace(/import \* as [^ ]+ from '[^']*';/g, '')
223
+ .replace('function asmFunc(imports) {', '')
224
+ .replace(/export var ([^ ]+) = ([^. ]+)\.([^ ]+);/g, '')
225
+ .replace(/var retasmFunc = [\s\S]*$/, '')
226
+ .replace(/var memasmFunc = new ArrayBuffer\(0\);/g, '')
227
+ .replace('memory.grow = __wasm_memory_grow;', '')
228
+ .trim()
229
+ }`)
230
+ .join(',\n');
231
+
232
+ // The `instantiate` function.
233
+ const instantiateFunction =
234
+ `${
235
+ withInstantiation ? 'export ' : ''
236
+ }${async_}function instantiate(imports) {
237
+ const wasm_file_to_asm_index = {
238
+ ${wasmFiles.map(([path], nth) => `'${basename(path)}': ${nth}`).join(',\n ')}
239
+ };
240
+
241
+ return ${await_}_instantiate(
242
+ module_name => wasm_file_to_asm_index[module_name],
243
+ imports,
244
+ (module_index, imports) => ({ exports: asmInit[module_index](imports) })
245
+ );
246
+ }`;
247
+
248
+ // If `--js` is used without `--instantiation`.
249
+ let importDirectives = '';
250
+ let exportDirectives = '';
251
+ let exportTrampolines = '';
252
+ let autoInstantiate = '';
253
+
254
+ if (!withInstantiation) {
255
+ importDirectives = imports
256
+ .map((import_file, nth) => `import * as import${nth} from '${import_file}';`)
257
+ .join('\n');
258
+
259
+ if (exports.length > 0 || opts.tlaCompat) {
260
+ exportDirectives =
261
+ `export {
262
+ ${
263
+ // Exporting `$init` must come first to not break the transpiling tests.
264
+ (opts.tlaCompat) ? ' $init,\n' : ''
265
+ }${
266
+ exports
267
+ .map(([name]) => {
268
+ if (name === asmMangle(name)) {
269
+ return ` ${name},`;
270
+ } else {
271
+ return ` ${asmMangle(name)} as '${name}',`;
272
+ }
273
+ })
274
+ .join('\n')
275
+ }
276
+ }`
277
+ }
278
+
279
+ exportTrampolines =
280
+ `let ${
281
+ exports
282
+ .filter(([, ty]) => ty === 'function')
283
+ .map(([name]) => `_${asmMangle(name)}`)
284
+ .join(', ')
285
+ };
286
+ ${
287
+ exports
288
+ .map(([name, ty]) => {
289
+ if (ty === 'function') {
290
+ return `\nfunction ${asmMangle(name)} () {
291
+ return _${asmMangle(name)}.apply(this, arguments);
292
+ }`;
293
+ } else {
294
+ return `\nlet ${asmMangle(name)};`;
295
+ }
296
+ })
297
+ .join('\n')
298
+ }`;
299
+
300
+ autoInstantiate =
301
+ `${async_}function $init() {
302
+ ( {
303
+ ${
304
+ exports
305
+ .map( ([name, ty]) => {
306
+ if (ty === 'function') {
307
+ return ` '${ name }': _${ asmMangle(name) },`;
308
+ } else if (asmMangle(name) === name) {
309
+ return ` ${ name },`;
310
+ } else {
311
+ return ` '${ name }': ${ asmMangle(name) },`;
312
+ }
313
+ })
314
+ .join('\n')
315
+ }
316
+ } = ${await_}instantiate(
317
+ {
318
+ ${
319
+ imports
320
+ .map((import_file, nth) => ` '${import_file}': import${ nth },`)
321
+ .join('\n')
322
+ }
323
+ }
324
+ ) )
325
+ }
326
+
327
+ ${ opts.tlaCompat ? '' : `${await_}$init();`}`;
328
+ }
329
+
330
+ // Prepare the final generated code.
331
+ const outSource = `${importDirectives}
332
+
333
+ ${source}
177
334
 
178
335
  const asmInit = [${asms}];
179
336
 
180
- ${opts.tlaCompat ? 'export ' : ''}const $init = (async () => {
181
- let idx = 0;
182
- ({ ${exports.map(([name, ty]) => asmMangle(name) === name ? name : `'${name}': ${asmMangle(name)}`).join(',\n')} } = await instantiate(n => idx++, {
183
- ${imports.map((impt, i) => ` '${impt}': import${i},`).join('\n')}
184
- }, (i, imports) => ({ exports: asmInit[i](imports) })));
185
- })();${exports.length > 0 ? `\nexport { ${exports.map(([name]) => name === asmMangle(name) ? `${name}` : `${asmMangle(name)} as "${name}"`).join(', ')} }` : ''}
186
- ${opts.tlaCompat ? '' : '\nawait $init;\n'}`;
337
+ ${exportTrampolines}
338
+
339
+ ${instantiateFunction}
187
340
 
341
+ ${exportDirectives}
342
+
343
+ ${autoInstantiate}`;
344
+
345
+ // Save the final generated code.
188
346
  jsFile[1] = Buffer.from(outSource);
189
347
  }
190
348
  finally {
191
- if (spinner)
349
+ if (spinner) {
192
350
  spinner.stop();
351
+ }
193
352
  }
194
353
  }
195
354
 
@@ -215,10 +374,10 @@ ${opts.tlaCompat ? '' : '\nawait $init;\n'}`;
215
374
  function asmMangle (name) {
216
375
  if (name === '')
217
376
  return '$';
218
-
377
+
219
378
  let mightBeKeyword = true;
220
379
  let i = 1;
221
-
380
+
222
381
  // Names must start with a character, $ or _
223
382
  switch (name[0]) {
224
383
  case '0':
@@ -248,7 +407,7 @@ function asmMangle (name) {
248
407
  }
249
408
  }
250
409
  }
251
-
410
+
252
411
  // Names must contain only characters, digits, $ or _
253
412
  let len = name.length;
254
413
  for (; i < len; ++i) {
@@ -277,7 +436,7 @@ function asmMangle (name) {
277
436
  }
278
437
  }
279
438
  }
280
-
439
+
281
440
  // Names must not collide with keywords
282
441
  if (mightBeKeyword && len >= 2 && len <= 10) {
283
442
  switch (name[0]) {
@@ -0,0 +1,8 @@
1
+ export function parse(file: any, opts: any): Promise<void>;
2
+ export function print(file: any, opts: any): Promise<void>;
3
+ export function componentWit(file: any, opts: any): Promise<void>;
4
+ export function componentNew(file: any, opts: any): Promise<void>;
5
+ export function componentEmbed(file: any, opts: any): Promise<void>;
6
+ export function metadataAdd(file: any, opts: any): Promise<void>;
7
+ export function metadataShow(file: any, opts: any): Promise<void>;
8
+ //# sourceMappingURL=wasm-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasm-tools.d.ts","sourceRoot":"","sources":["wasm-tools.js"],"names":[],"mappings":"AAQA,2DAKC;AAED,2DASC;AAED,kEASC;AAED,kEAsBC;AAED,oEAaC;AAED,iEAUC;AAED,kEAiCC"}