@bytecodealliance/jco 0.13.2 → 0.14.0

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 (43) 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 +4 -9
  5. package/obj/interfaces/wasi-io-error.d.ts +6 -0
  6. package/obj/interfaces/wasi-io-streams.d.ts +2 -4
  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 +27 -18
  11. package/obj/js-component-bindgen-component.js +849 -784
  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 +18 -17
  16. package/obj/wasm-tools.js +779 -751
  17. package/package.json +3 -3
  18. package/src/api.d.ts +42 -0
  19. package/src/api.d.ts.map +1 -0
  20. package/src/browser.d.ts +4 -0
  21. package/src/browser.d.ts.map +1 -0
  22. package/src/cmd/componentize.d.ts +2 -0
  23. package/src/cmd/componentize.d.ts.map +1 -0
  24. package/src/cmd/componentize.js +1 -0
  25. package/src/cmd/opt.d.ts +15 -0
  26. package/src/cmd/opt.d.ts.map +1 -0
  27. package/src/cmd/run.d.ts +2 -0
  28. package/src/cmd/run.d.ts.map +1 -0
  29. package/src/cmd/run.js +23 -6
  30. package/src/cmd/transpile.d.ts +44 -0
  31. package/src/cmd/transpile.d.ts.map +1 -0
  32. package/src/cmd/transpile.js +206 -45
  33. package/src/cmd/wasm-tools.d.ts +8 -0
  34. package/src/cmd/wasm-tools.d.ts.map +1 -0
  35. package/src/cmd/wasm-tools.js +3 -2
  36. package/src/common.d.ts +16 -0
  37. package/src/common.d.ts.map +1 -0
  38. package/src/common.js +3 -0
  39. package/src/jco.d.ts +3 -0
  40. package/src/jco.d.ts.map +1 -0
  41. package/src/jco.js +9 -4
  42. package/src/ora-shim.d.ts +7 -0
  43. 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.2",
3
+ "version": "0.14.0",
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.20",
21
+ "@bytecodealliance/preview2-shim": "0.14.0",
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.0",
30
+ "@bytecodealliance/componentize-js": "^0.4.1",
31
31
  "@types/node": "^18.11.17",
32
32
  "@typescript-eslint/eslint-plugin": "^5.41.0",
33
33
  "@typescript-eslint/parser": "^5.41.0",
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,4 @@
1
+ import { generate } from "../obj/js-component-bindgen-component.js";
2
+ import { generateTypes } from "../obj/js-component-bindgen-component.js";
3
+ export { generate as transpile, generateTypes };
4
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["browser.js"],"names":[],"mappings":""}
@@ -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":"AAIA,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,14 +52,22 @@ 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
  }
56
69
  try {
70
+ process.argv[1] = "${name}";
57
71
  const mod = await import('./${name}.js');
58
72
  if (!mod.run || !mod.run.run) {
59
73
  logInvalidCommand();
@@ -61,6 +75,8 @@ export async function run (componentPath, args) {
61
75
  }
62
76
  try {
63
77
  mod.run.run();
78
+ // TODO: figure out stdout flush!
79
+ setTimeout(() => {});
64
80
  }
65
81
  catch (e) {
66
82
  console.error(e);
@@ -82,7 +98,8 @@ export async function run (componentPath, args) {
82
98
  }
83
99
  finally {
84
100
  try {
85
- await rm(outDir, { recursive: true });
101
+ if (!opts.jcoDir)
102
+ await rm(outDir, { recursive: true });
86
103
  } catch {}
87
104
  }
88
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
+ * noNodejsCompat?: bool,
12
+ * tlaCompat?: bool,
13
+ * base64Cutoff?: bool,
14
+ * js?: bool,
15
+ * minify?: bool,
16
+ * optimize?: bool,
17
+ * noNamespacedExports?: 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
+ noNodejsCompat?: bool;
29
+ tlaCompat?: bool;
30
+ base64Cutoff?: bool;
31
+ js?: bool;
32
+ minify?: bool;
33
+ optimize?: bool;
34
+ noNamespacedExports?: 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;GA4IhI"}
@@ -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 = {}) {
@@ -103,16 +104,28 @@ export async function transpileComponent (component, opts = {}) {
103
104
  }, opts.map || {});
104
105
  }
105
106
 
107
+ let instantiation = null;
108
+
109
+ // Let's define `instantiation` from `--instantiation` if it's present.
110
+ if (opts.instantiation) {
111
+ instantiation = { tag: opts.instantiation };
112
+ }
113
+ // Otherwise, if `--js` is present, an `instantiate` function is required.
114
+ else if (opts.js) {
115
+ instantiation = { tag: 'async' };
116
+ }
117
+
106
118
  let { files, imports, exports } = generate(component, {
107
119
  name: opts.name ?? 'component',
108
120
  map: Object.entries(opts.map ?? {}),
109
- instantiation: opts.instantiation || opts.js,
121
+ instantiation,
110
122
  validLiftingOptimization: opts.validLiftingOptimization ?? false,
111
123
  tracing: opts.tracing ?? false,
112
124
  noNodejsCompat: !(opts.nodejsCompat ?? true),
113
125
  noTypescript: opts.noTypescript || false,
114
126
  tlaCompat: opts.tlaCompat ?? false,
115
- base64Cutoff: opts.js ? 0 : opts.base64Cutoff ?? 5000
127
+ base64Cutoff: opts.js ? 0 : opts.base64Cutoff ?? 5000,
128
+ noNamespacedExports: opts.namespacedExports === false,
116
129
  });
117
130
 
118
131
  let outDir = (opts.outDir ?? '').replace(/\\/g, '/');
@@ -122,16 +135,67 @@ export async function transpileComponent (component, opts = {}) {
122
135
 
123
136
  const jsFile = files.find(([name]) => name.endsWith('.js'));
124
137
 
138
+ // Generate code for the `--js` option.
139
+ //
140
+ // `--js` can be called with or without `--instantiation`. The generated code
141
+ // isn't exactly the same!
142
+ //
143
+ // `--js` needs an `instantiate` function to work, so it might look like
144
+ // `--instantiation` is always implied, but actually no. It is correct
145
+ // that when `--js` is present, an `instantiate` function _is_ generated,
146
+ // but it doesn't mean that we expect the function to be used, it's simply
147
+ // not exported, plus `instantiate` is automatically called (if `--tla-compat`
148
+ // is `false`). When `--instantiation` is missing, functions are exported
149
+ // with the `export` directive, and imports are imported with the `import`
150
+ // directive. When `--instantiation` is present, there is no `export` and no
151
+ // `import`: only a single exported `instantiate` function.
152
+ //
153
+ // Basically, we get this:
154
+ //
155
+ // * `--js` only:
156
+ // * `instantiate` is renamed to `_instantiate`,
157
+ // * A new `instantiate` function is created, that calls `_instantiate` with
158
+ // the correct imports (which are ASM.js code) and returns the exports,
159
+ // * A new `$init` function is created, that calls `instantiate` and maps
160
+ // the returned exports to their respective trampolines,
161
+ // * Trampolines are exported,
162
+ // * `$init` is called automatically.
163
+ //
164
+ // * `--js` with `--tla-compat`:
165
+ // * Same as with `--js` only, except that `$init` is exported instead of
166
+ // being called immediately.
167
+ //
168
+ // * `--js` with `--instantiation[=async]`:
169
+ // * `instantiate` is renamed to `_instantiate`,
170
+ // * A new `instantiate` function is created, that calls `_instantiate` with
171
+ // the correct imports (which are ASM.js code) and returns the exports,
172
+ // * `instantiate` is exported.
173
+ //
174
+ // * `--js` with `--instantiation=sync`:
175
+ // * Same as `--js` with `--instantiation[=async]`, except that
176
+ // `_instantiate` and `instantiate` are non-async.
177
+ //
178
+ // Be careful with the variables: `opts.instantiation` reflects the presence
179
+ // or the absence of the `--instantiation` flag, whilst `instantiation`
180
+ // reflects how the `instantiate` function must be generated. We also use
181
+ // `instantiation` to know whether the generated code must be async or
182
+ // non-async.
125
183
  if (opts.js) {
184
+ const withInstantiation = opts.instantiation !== undefined;
185
+ const async_ = instantiation.tag == 'async' ? 'async ' : '';
186
+ const await_ = instantiation.tag == 'async' ? 'await ' : '';
187
+
188
+ // Format the previously generated code.
126
189
  const source = Buffer.from(jsFile[1]).toString('utf8')
127
190
  // update imports manging to match emscripten asm
128
- .replace(/exports(\d+)\['([^']+)']/g, (_, i, s) => `exports${i}['${asmMangle(s)}']`);
129
-
191
+ .replace(/exports(\d+)\['([^']+)']/g, (_, i, s) => `exports${i}['${asmMangle(s)}']`)
192
+ .replace(/export (async )?function instantiate/, '$1function _instantiate') ;
193
+
194
+ // Collect all Wasm files.
130
195
  const wasmFiles = files.filter(([name]) => name.endsWith('.wasm'));
131
196
  files = files.filter(([name]) => !name.endsWith('.wasm'));
132
197
 
133
- // TODO: imports as specifier list
134
-
198
+ // Configure the spinner.
135
199
  let completed = 0;
136
200
  const spinnerText = () => c`{cyan ${completed} / ${wasmFiles.length}} Running Binaryen wasm2js on Wasm core modules (this takes a while)...\n`;
137
201
  if (showSpinner) {
@@ -142,6 +206,7 @@ export async function transpileComponent (component, opts = {}) {
142
206
  spinner.text = spinnerText();
143
207
  }
144
208
 
209
+ // Compile all Wasm modules into ASM.js codes.
145
210
  try {
146
211
  const asmFiles = await Promise.all(wasmFiles.map(async ([, source]) => {
147
212
  const output = (await wasm2Js(source)).toString('utf8');
@@ -152,44 +217,140 @@ export async function transpileComponent (component, opts = {}) {
152
217
  return output;
153
218
  }));
154
219
 
155
- const asms = asmFiles.map((asm, i) =>`function asm${i}(imports) {
220
+ const asms = asmFiles.map((asm, nth) => `function asm${nth}(imports) {
156
221
  ${
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')}
222
+ // strip and replace the asm instantiation wrapper
223
+ asm
224
+ .replace(/import \* as [^ ]+ from '[^']*';/g, '')
225
+ .replace('function asmFunc(imports) {', '')
226
+ .replace(/export var ([^ ]+) = ([^. ]+)\.([^ ]+);/g, '')
227
+ .replace(/var retasmFunc = [\s\S]*$/, '')
228
+ .replace(/var memasmFunc = new ArrayBuffer\(0\);/g, '')
229
+ .replace('memory.grow = __wasm_memory_grow;', '')
230
+ .trim()
231
+ }`)
232
+ .join(',\n');
233
+
234
+ // The `instantiate` function.
235
+ const instantiateFunction =
236
+ `${
237
+ withInstantiation ? 'export ' : ''
238
+ }${async_}function instantiate(imports) {
239
+ const wasm_file_to_asm_index = {
240
+ ${wasmFiles.map(([path], nth) => `'${basename(path)}': ${nth}`).join(',\n ')}
241
+ };
242
+
243
+ return ${await_}_instantiate(
244
+ module_name => wasm_file_to_asm_index[module_name],
245
+ imports,
246
+ (module_index, imports) => ({ exports: asmInit[module_index](imports) })
247
+ );
248
+ }`;
249
+
250
+ // If `--js` is used without `--instantiation`.
251
+ let importDirectives = '';
252
+ let exportDirectives = '';
253
+ let exportTrampolines = '';
254
+ let autoInstantiate = '';
255
+
256
+ if (!withInstantiation) {
257
+ importDirectives = imports
258
+ .map((import_file, nth) => `import * as import${nth} from '${import_file}';`)
259
+ .join('\n');
260
+
261
+ if (exports.length > 0 || opts.tlaCompat) {
262
+ exportDirectives =
263
+ `export {
264
+ ${
265
+ // Exporting `$init` must come first to not break the transpiling tests.
266
+ (opts.tlaCompat) ? ' $init,\n' : ''
267
+ }${
268
+ exports
269
+ .map(([name]) => {
270
+ if (name === asmMangle(name)) {
271
+ return ` ${name},`;
272
+ } else {
273
+ return ` ${asmMangle(name)} as '${name}',`;
274
+ }
275
+ })
276
+ .join('\n')
277
+ }
278
+ }`
279
+ }
280
+
281
+ exportTrampolines =
282
+ `let ${
283
+ exports
284
+ .filter(([, ty]) => ty === 'function')
285
+ .map(([name]) => `_${asmMangle(name)}`)
286
+ .join(', ')
287
+ };
288
+ ${
289
+ exports
290
+ .map(([name, ty]) => {
291
+ if (ty === 'function') {
292
+ return `\nfunction ${asmMangle(name)} () {
293
+ return _${asmMangle(name)}.apply(this, arguments);
294
+ }`;
295
+ } else {
296
+ return `\nlet ${asmMangle(name)};`;
297
+ }
298
+ })
299
+ .join('\n')
300
+ }`;
301
+
302
+ autoInstantiate =
303
+ `${async_}function $init() {
304
+ ( {
305
+ ${
306
+ exports
307
+ .map( ([name, ty]) => {
308
+ if (ty === 'function') {
309
+ return ` '${ name }': _${ asmMangle(name) },`;
310
+ } else if (asmMangle(name) === name) {
311
+ return ` ${ name },`;
312
+ } else {
313
+ return ` '${ name }': ${ asmMangle(name) },`;
314
+ }
315
+ })
316
+ .join('\n')
317
+ }
318
+ } = ${await_}instantiate(
319
+ {
320
+ ${
321
+ imports
322
+ .map((import_file, nth) => ` '${import_file}': import${ nth },`)
323
+ .join('\n')
324
+ }
325
+ }
326
+ ) )
327
+ }
328
+
329
+ ${ opts.tlaCompat ? '' : `${await_}$init();`}`;
330
+ }
331
+
332
+ // Prepare the final generated code.
333
+ const outSource = `${importDirectives}
334
+
335
+ ${source}
177
336
 
178
337
  const asmInit = [${asms}];
179
338
 
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'}`;
339
+ ${exportTrampolines}
340
+
341
+ ${instantiateFunction}
187
342
 
343
+ ${exportDirectives}
344
+
345
+ ${autoInstantiate}`;
346
+
347
+ // Save the final generated code.
188
348
  jsFile[1] = Buffer.from(outSource);
189
349
  }
190
350
  finally {
191
- if (spinner)
351
+ if (spinner) {
192
352
  spinner.stop();
353
+ }
193
354
  }
194
355
  }
195
356
 
@@ -215,10 +376,10 @@ ${opts.tlaCompat ? '' : '\nawait $init;\n'}`;
215
376
  function asmMangle (name) {
216
377
  if (name === '')
217
378
  return '$';
218
-
379
+
219
380
  let mightBeKeyword = true;
220
381
  let i = 1;
221
-
382
+
222
383
  // Names must start with a character, $ or _
223
384
  switch (name[0]) {
224
385
  case '0':
@@ -248,7 +409,7 @@ function asmMangle (name) {
248
409
  }
249
410
  }
250
411
  }
251
-
412
+
252
413
  // Names must contain only characters, digits, $ or _
253
414
  let len = name.length;
254
415
  for (; i < len; ++i) {
@@ -277,7 +438,7 @@ function asmMangle (name) {
277
438
  }
278
439
  }
279
440
  }
280
-
441
+
281
442
  // Names must not collide with keywords
282
443
  if (mightBeKeyword && len >= 2 && len <= 10) {
283
444
  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":"AAOA,2DAKC;AAED,2DASC;AAED,kEASC;AAED,kEAsBC;AAED,oEAaC;AAED,iEAUC;AAED,kEAiCC"}
@@ -1,9 +1,10 @@
1
1
  import { writeFile } from "node:fs/promises";
2
- import { readFile } from '../common.js';
2
+ import { readFile, isWindows } from '../common.js';
3
3
  import { $init, tools } from "../../obj/wasm-tools.js";
4
4
  const { print: printFn, parse: parseFn, componentWit: componentWitFn, componentNew: componentNewFn, componentEmbed: componentEmbedFn, metadataAdd: metadataAddFn, metadataShow: metadataShowFn } = tools;
5
5
  import { resolve, basename, extname } from 'node:path';
6
6
  import c from 'chalk-template';
7
+ import { platform } from 'node:process';
7
8
 
8
9
  export async function parse(file, opts) {
9
10
  await $init;
@@ -68,7 +69,7 @@ export async function componentEmbed(file, opts) {
68
69
  });
69
70
  const source = file ? await readFile(file) : null;
70
71
  opts.binary = source;
71
- opts.witPath = resolve(opts.wit);
72
+ opts.witPath = (isWindows ? '//?/' : '') + resolve(opts.wit);
72
73
  const output = componentEmbedFn(opts);
73
74
  await writeFile(opts.output, output);
74
75
  }
@@ -0,0 +1,16 @@
1
+ export function setShowSpinner(val: any): void;
2
+ export function getShowSpinner(): boolean;
3
+ export function sizeStr(num: any): string;
4
+ export function fixedDigitDisplay(num: any, maxChars: any): string;
5
+ export function table(data: any, align?: any[]): string;
6
+ /**
7
+ * Securely creates a temporary directory and returns its path.
8
+ *
9
+ * The new directory is created using `fsPromises.mkdtemp()`.
10
+ */
11
+ export function getTmpDir(): Promise<string>;
12
+ export function spawnIOTmp(cmd: any, input: any, args: any): Promise<Buffer>;
13
+ export const isWindows: boolean;
14
+ export { readFileCli as readFile };
15
+ declare function readFileCli(file: any, encoding: any): Promise<Buffer>;
16
+ //# sourceMappingURL=common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["common.js"],"names":[],"mappings":"AAWA,+CAEC;AACD,0CAIC;AAED,0CAOC;AAED,mEAaC;AAED,wDAcC;AAED;;;;GAIG;AACH,6CAEC;AAYD,6EA8BC;AArGD,gCAA8C;;AA6D9C,wEAOC"}