@bytecodealliance/jco 1.24.1 → 1.24.3
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.
- package/package.json +4 -7
- package/src/api.js +9 -61
- package/src/cmd/componentize.js +2 -7
- package/src/cmd/opt.js +5 -7
- package/src/cmd/run.js +2 -2
- package/src/cmd/transpile.js +36 -604
- package/src/cmd/types.js +18 -9
- package/src/cmd/wasm-tools.js +17 -24
- package/src/jco.js +3 -3
- package/types/api.d.ts +1 -31
- package/types/api.d.ts.map +1 -1
- package/types/cmd/componentize.d.ts.map +1 -1
- package/types/cmd/opt.d.ts.map +1 -1
- package/types/cmd/transpile.d.ts +25 -15
- package/types/cmd/transpile.d.ts.map +1 -1
- package/types/cmd/types.d.ts.map +1 -1
- package/types/cmd/wasm-tools.d.ts.map +1 -1
- package/obj/interfaces/local-wasm-tools-tools.d.ts +0 -79
- package/obj/interfaces/wasi-cli-environment.d.ts +0 -2
- package/obj/interfaces/wasi-cli-exit.d.ts +0 -3
- package/obj/interfaces/wasi-cli-stderr.d.ts +0 -3
- package/obj/interfaces/wasi-cli-stdin.d.ts +0 -3
- package/obj/interfaces/wasi-cli-stdout.d.ts +0 -3
- package/obj/interfaces/wasi-cli-terminal-input.d.ts +0 -8
- package/obj/interfaces/wasi-cli-terminal-output.d.ts +0 -8
- package/obj/interfaces/wasi-cli-terminal-stderr.d.ts +0 -3
- package/obj/interfaces/wasi-cli-terminal-stdin.d.ts +0 -3
- package/obj/interfaces/wasi-cli-terminal-stdout.d.ts +0 -3
- package/obj/interfaces/wasi-clocks-wall-clock.d.ts +0 -5
- package/obj/interfaces/wasi-filesystem-preopens.d.ts +0 -3
- package/obj/interfaces/wasi-filesystem-types.d.ts +0 -165
- package/obj/interfaces/wasi-io-error.d.ts +0 -8
- package/obj/interfaces/wasi-io-streams.d.ts +0 -30
- package/obj/interfaces/wasi-random-random.d.ts +0 -2
- package/obj/js-component-bindgen-component.core.wasm +0 -0
- package/obj/js-component-bindgen-component.core2.wasm +0 -0
- package/obj/js-component-bindgen-component.d.ts +0 -120
- package/obj/js-component-bindgen-component.js +0 -13637
- package/obj/wasm-tools.core.wasm +0 -0
- package/obj/wasm-tools.core2.wasm +0 -0
- package/obj/wasm-tools.d.ts +0 -20
- package/obj/wasm-tools.js +0 -14389
package/src/cmd/transpile.js
CHANGED
|
@@ -1,100 +1,14 @@
|
|
|
1
1
|
/* global Buffer */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { transpile, transpileBytes } from "@bytecodealliance/jco-transpile";
|
|
5
4
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import { optimizeComponent } from "./opt.js";
|
|
9
|
-
|
|
10
|
-
import { $init, generate } from "../../obj/js-component-bindgen-component.js";
|
|
11
|
-
import {
|
|
12
|
-
readFile,
|
|
13
|
-
spawnIOTmp,
|
|
14
|
-
setShowSpinner,
|
|
15
|
-
getShowSpinner,
|
|
16
|
-
writeFiles,
|
|
17
|
-
styleText,
|
|
18
|
-
ASYNC_WASI_IMPORTS,
|
|
19
|
-
ASYNC_WASI_EXPORTS,
|
|
20
|
-
DEFAULT_ASYNC_MODE,
|
|
21
|
-
} from "../common.js";
|
|
22
|
-
import { $init as wasmToolsInit, tools } from "../../obj/wasm-tools.js";
|
|
23
|
-
const { componentEmbed, componentNew } = tools;
|
|
24
|
-
|
|
25
|
-
import ora from "#ora";
|
|
26
|
-
|
|
27
|
-
import { isWindows } from "../common.js";
|
|
5
|
+
import { setShowSpinner, writeFiles } from "../common.js";
|
|
28
6
|
|
|
29
7
|
// These re-exports exist to avoid breaking backwards compatibility
|
|
30
8
|
export { types, guestTypes, typesComponent } from "./types.js";
|
|
31
9
|
|
|
32
|
-
const SUPPORTED_P3_VERSIONS = ["0.3.0-rc-2026-03-15", "0.3.0"];
|
|
33
|
-
|
|
34
|
-
export async function transpile(witPath, opts, program) {
|
|
35
|
-
const varIdx = program?.parent.rawArgs.indexOf("--");
|
|
36
|
-
if (varIdx !== undefined && varIdx !== -1) {
|
|
37
|
-
opts.optArgs = program.parent.rawArgs.slice(varIdx + 1);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
let component;
|
|
41
|
-
if (!opts.stub) {
|
|
42
|
-
component = await readFile(witPath);
|
|
43
|
-
} else {
|
|
44
|
-
await wasmToolsInit;
|
|
45
|
-
component = componentNew(
|
|
46
|
-
componentEmbed({
|
|
47
|
-
dummy: true,
|
|
48
|
-
witPath: (isWindows ? "//?/" : "") + resolve(witPath),
|
|
49
|
-
}),
|
|
50
|
-
[],
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (!opts.quiet) {
|
|
55
|
-
setShowSpinner(true);
|
|
56
|
-
}
|
|
57
|
-
if (!opts.name) {
|
|
58
|
-
opts.name = basename(witPath.slice(0, -extname(witPath).length || Infinity));
|
|
59
|
-
}
|
|
60
|
-
if (opts.map) {
|
|
61
|
-
opts.map = Object.fromEntries(opts.map.map((mapping) => mapping.split("=")));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (opts.asyncWasiImports) {
|
|
65
|
-
opts.asyncImports = ASYNC_WASI_IMPORTS.concat(opts.asyncImports || []);
|
|
66
|
-
}
|
|
67
|
-
if (opts.asyncWasiExports) {
|
|
68
|
-
opts.asyncExports = ASYNC_WASI_EXPORTS.concat(opts.asyncExports || []);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const { files } = await transpileComponent(component, opts);
|
|
72
|
-
await writeFiles(files, opts.quiet ? false : "Transpiled JS Component Files");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
10
|
/**
|
|
76
|
-
* @
|
|
77
|
-
* @returns {Promise<Uint8Array>}
|
|
78
|
-
*/
|
|
79
|
-
async function wasm2Js(source) {
|
|
80
|
-
const wasm2jsPath = fileURLToPath(import.meta.resolve("binaryen/bin/wasm2js"));
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
return await spawnIOTmp(wasm2jsPath, source, ["-Oz", "-o"]);
|
|
84
|
-
} catch (e) {
|
|
85
|
-
if (e.toString().includes("BasicBlock requested")) {
|
|
86
|
-
return wasm2Js(source);
|
|
87
|
-
}
|
|
88
|
-
throw e;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Execute the bundled pre-transpiled component that can perform component transpilation,
|
|
94
|
-
* for the given component.
|
|
95
|
-
*
|
|
96
|
-
* @param {Uint8Array} component
|
|
97
|
-
* @param {{
|
|
11
|
+
* @typedef {{
|
|
98
12
|
* name: string,
|
|
99
13
|
* instantiation?: 'async' | 'sync',
|
|
100
14
|
* importBindings?: 'js' | 'optimized' | 'hybrid' | 'direct-optimized',
|
|
@@ -116,534 +30,52 @@ async function wasm2Js(source) {
|
|
|
116
30
|
* experimentalIdlImports?: bool,
|
|
117
31
|
* optArgs?: string[],
|
|
118
32
|
* wasmOptBin?: string[],
|
|
119
|
-
* }}
|
|
120
|
-
* @returns {Promise<{ files: { [filename: string]: Uint8Array }, imports: string[], exports: [string, 'function' | 'instance'][] }>}
|
|
33
|
+
* }} TranspileOpts
|
|
121
34
|
*/
|
|
122
|
-
export async function transpileComponent(component, opts = {}) {
|
|
123
|
-
await $init;
|
|
124
|
-
if (opts.instantiation) {
|
|
125
|
-
opts.wasiShim = false;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
let spinner;
|
|
129
|
-
const showSpinner = getShowSpinner();
|
|
130
|
-
|
|
131
|
-
if (opts.optimize) {
|
|
132
|
-
if (showSpinner) {
|
|
133
|
-
setShowSpinner(true);
|
|
134
|
-
}
|
|
135
|
-
({ component } = await optimizeComponent(component, opts));
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (opts.wasiShim !== false) {
|
|
139
|
-
const shims = {
|
|
140
|
-
"wasi:cli/*": "@bytecodealliance/preview2-shim/cli#*",
|
|
141
|
-
"wasi:clocks/*": "@bytecodealliance/preview2-shim/clocks#*",
|
|
142
|
-
"wasi:filesystem/*": "@bytecodealliance/preview2-shim/filesystem#*",
|
|
143
|
-
"wasi:http/*": "@bytecodealliance/preview2-shim/http#*",
|
|
144
|
-
"wasi:io/*": "@bytecodealliance/preview2-shim/io#*",
|
|
145
|
-
"wasi:random/*": "@bytecodealliance/preview2-shim/random#*",
|
|
146
|
-
"wasi:sockets/*": "@bytecodealliance/preview2-shim/sockets#*",
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
// To avoid breaking compatibility with earlier version of p3 (including draft versions),
|
|
150
|
-
// we over-populate the map with references to the *current* preview3-shim that has been
|
|
151
|
-
// imported.
|
|
152
|
-
//
|
|
153
|
-
// This implicitly upgrades versions of P3 in use (a component that asks for 0.3.0 will get 0.3.1 if that
|
|
154
|
-
// is the current version in preview3-shim0, but that should be acceptable as p3 should not have breaking
|
|
155
|
-
// changes going forward.
|
|
156
|
-
//
|
|
157
|
-
for (const version of SUPPORTED_P3_VERSIONS) {
|
|
158
|
-
Object.assign(shims, {
|
|
159
|
-
[`wasi:cli/*@${version}`]: "@bytecodealliance/preview3-shim/cli#*",
|
|
160
|
-
[`wasi:clocks/*@${version}`]: "@bytecodealliance/preview3-shim/clocks#*",
|
|
161
|
-
[`wasi:filesystem/*@${version}`]: "@bytecodealliance/preview3-shim/filesystem#*",
|
|
162
|
-
[`wasi:http/*@${version}`]: "@bytecodealliance/preview3-shim/http#*",
|
|
163
|
-
[`wasi:random/*@${version}`]: "@bytecodealliance/preview3-shim/random#*",
|
|
164
|
-
[`wasi:sockets/*@${version}`]: "@bytecodealliance/preview3-shim/sockets#*",
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
opts.map = Object.assign(shims, opts.map || {});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
let instantiation = null;
|
|
172
|
-
|
|
173
|
-
// Let's define `instantiation` from `--instantiation` if it's present.
|
|
174
|
-
if (opts.instantiation) {
|
|
175
|
-
instantiation = { tag: opts.instantiation };
|
|
176
|
-
} else if (opts.js) {
|
|
177
|
-
// Otherwise, if `--js` is present, an `instantiate` function is required.
|
|
178
|
-
instantiation = { tag: "async" };
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Get the configured async mode then transform it into what the types component expects
|
|
182
|
-
// Build list of async imports/exports
|
|
183
|
-
let asyncImports = new Set([...(opts.asyncImports ?? [])]);
|
|
184
|
-
let asyncExports = new Set([...(opts.asyncExports ?? [])]);
|
|
185
|
-
let asyncMode = opts.asyncMode ?? DEFAULT_ASYNC_MODE;
|
|
186
|
-
if (asyncMode === "sync" && asyncExports.size > 0) {
|
|
187
|
-
throw new Error("async exports cannot be specified in sync mode (consider adding --async-mode=jspi)");
|
|
188
|
-
}
|
|
189
|
-
if (asyncMode === "sync" && asyncImports.size > 0) {
|
|
190
|
-
throw new Error("async imports cannot be specified in sync mode (consider adding --async-mode=jspi)");
|
|
191
|
-
}
|
|
192
|
-
let asyncModeObj;
|
|
193
|
-
if (asyncMode === "sync") {
|
|
194
|
-
asyncModeObj = null;
|
|
195
|
-
} else if (asyncMode === "jspi") {
|
|
196
|
-
asyncModeObj = {
|
|
197
|
-
tag: "jspi",
|
|
198
|
-
val: {
|
|
199
|
-
imports: [...asyncImports],
|
|
200
|
-
exports: [...asyncExports],
|
|
201
|
-
},
|
|
202
|
-
};
|
|
203
|
-
} else {
|
|
204
|
-
throw new Error(`invalid/unrecognized async mode [${asyncMode}]`);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
let { files, imports, exports } = generate(component, {
|
|
208
|
-
name: opts.name ?? "component",
|
|
209
|
-
map: Object.entries(opts.map ?? {}),
|
|
210
|
-
instantiation,
|
|
211
|
-
asyncMode: asyncModeObj,
|
|
212
|
-
importBindings: opts.importBindings ? { tag: opts.importBindings } : null,
|
|
213
|
-
validLiftingOptimization: opts.validLiftingOptimization ?? false,
|
|
214
|
-
tracing: opts.tracing ?? false,
|
|
215
|
-
noNodejsCompat: opts.nodejsCompat === false,
|
|
216
|
-
noTypescript: opts.typescript === false,
|
|
217
|
-
tlaCompat: opts.tlaCompat ?? false,
|
|
218
|
-
base64Cutoff: opts.js ? 0 : (opts.base64Cutoff ?? 5000),
|
|
219
|
-
noNamespacedExports: opts.namespacedExports === false,
|
|
220
|
-
multiMemory: opts.multiMemory === true,
|
|
221
|
-
idlImports: opts.experimentalIdlImports === true,
|
|
222
|
-
strict: opts.strict === true,
|
|
223
|
-
asmjs: opts.js === true,
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
let outDir = (opts.outDir ?? "").replace(/\\/g, "/");
|
|
227
|
-
if (!outDir.endsWith("/") && outDir !== "") {
|
|
228
|
-
outDir += "/";
|
|
229
|
-
}
|
|
230
|
-
files = files.map(([name, source]) => [`${outDir}${name}`, source]);
|
|
231
|
-
|
|
232
|
-
const jsFile = files.find(([name]) => name.endsWith(".js"));
|
|
233
|
-
|
|
234
|
-
// Generate code for the `--js` option.
|
|
235
|
-
//
|
|
236
|
-
// `--js` can be called with or without `--instantiation`. The generated code
|
|
237
|
-
// isn't exactly the same!
|
|
238
|
-
//
|
|
239
|
-
// `--js` needs an `instantiate` function to work, so it might look like
|
|
240
|
-
// `--instantiation` is always implied, but actually no. It is correct
|
|
241
|
-
// that when `--js` is present, an `instantiate` function _is_ generated,
|
|
242
|
-
// but it doesn't mean that we expect the function to be used, it's simply
|
|
243
|
-
// not exported, plus `instantiate` is automatically called (if `--tla-compat`
|
|
244
|
-
// is `false`). When `--instantiation` is missing, functions are exported
|
|
245
|
-
// with the `export` directive, and imports are imported with the `import`
|
|
246
|
-
// directive. When `--instantiation` is present, there is no `export` and no
|
|
247
|
-
// `import`: only a single exported `instantiate` function.
|
|
248
|
-
//
|
|
249
|
-
// Basically, we get this:
|
|
250
|
-
//
|
|
251
|
-
// * `--js` only:
|
|
252
|
-
// * `instantiate` is renamed to `_instantiate`,
|
|
253
|
-
// * A new `instantiate` function is created, that calls `_instantiate` with
|
|
254
|
-
// the correct imports (which are ASM.js code) and returns the exports,
|
|
255
|
-
// * A new `$init` function is created, that calls `instantiate` and maps
|
|
256
|
-
// the returned exports to their respective trampolines,
|
|
257
|
-
// * Trampolines are exported,
|
|
258
|
-
// * `$init` is called automatically.
|
|
259
|
-
//
|
|
260
|
-
// * `--js` with `--tla-compat`:
|
|
261
|
-
// * Same as with `--js` only, except that `$init` is exported instead of
|
|
262
|
-
// being called immediately.
|
|
263
|
-
//
|
|
264
|
-
// * `--js` with `--instantiation[=async]`:
|
|
265
|
-
// * `instantiate` is renamed to `_instantiate`,
|
|
266
|
-
// * A new `instantiate` function is created, that calls `_instantiate` with
|
|
267
|
-
// the correct imports (which are ASM.js code) and returns the exports,
|
|
268
|
-
// * `instantiate` is exported.
|
|
269
|
-
//
|
|
270
|
-
// * `--js` with `--instantiation=sync`:
|
|
271
|
-
// * Same as `--js` with `--instantiation[=async]`, except that
|
|
272
|
-
// `_instantiate` and `instantiate` are non-async.
|
|
273
|
-
//
|
|
274
|
-
// Be careful with the variables: `opts.instantiation` reflects the presence
|
|
275
|
-
// or the absence of the `--instantiation` flag, whilst `instantiation`
|
|
276
|
-
// reflects how the `instantiate` function must be generated. We also use
|
|
277
|
-
// `instantiation` to know whether the generated code must be async or
|
|
278
|
-
// non-async.
|
|
279
|
-
if (opts.js) {
|
|
280
|
-
const withInstantiation = opts.instantiation !== undefined;
|
|
281
|
-
const async_ = instantiation.tag == "async" ? "async " : "";
|
|
282
|
-
const await_ = instantiation.tag == "async" ? "await " : "";
|
|
283
|
-
|
|
284
|
-
// Format the previously generated code.
|
|
285
|
-
const source = Buffer.from(jsFile[1])
|
|
286
|
-
.toString("utf8")
|
|
287
|
-
// update imports manging to match emscripten asm
|
|
288
|
-
.replace(/exports(\d+)\['([^']+)']/g, (_, i, s) => `exports${i}['${asmMangle(s)}']`)
|
|
289
|
-
.replace(/export (async )?function instantiate/, "$1function _instantiate");
|
|
290
|
-
|
|
291
|
-
// Collect all Wasm files.
|
|
292
|
-
const wasmFiles = files.filter(([name]) => name.endsWith(".wasm"));
|
|
293
|
-
files = files.filter(([name]) => !name.endsWith(".wasm"));
|
|
294
|
-
|
|
295
|
-
// Configure the spinner.
|
|
296
|
-
let completed = 0;
|
|
297
|
-
const spinnerText = () =>
|
|
298
|
-
`${styleText("cyan", `${completed} / ${wasmFiles.length}`)} Running Binaryen wasm2js on Wasm core modules (this takes a while)...\n`;
|
|
299
|
-
if (showSpinner) {
|
|
300
|
-
spinner = ora({
|
|
301
|
-
color: "cyan",
|
|
302
|
-
spinner: "bouncingBar",
|
|
303
|
-
}).start();
|
|
304
|
-
spinner.text = spinnerText();
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Compile all Wasm modules into ASM.js codes.
|
|
308
|
-
try {
|
|
309
|
-
const asmFiles = await Promise.all(
|
|
310
|
-
wasmFiles.map(async ([, source]) => {
|
|
311
|
-
const output = (await wasm2Js(source)).toString("utf8");
|
|
312
|
-
if (spinner) {
|
|
313
|
-
completed++;
|
|
314
|
-
spinner.text = spinnerText();
|
|
315
|
-
}
|
|
316
|
-
return output;
|
|
317
|
-
}),
|
|
318
|
-
);
|
|
319
|
-
|
|
320
|
-
const asms = asmFiles
|
|
321
|
-
.map(
|
|
322
|
-
(asm, nth) => `function asm${nth}(imports) {
|
|
323
|
-
${
|
|
324
|
-
// strip and replace the asm instantiation wrapper
|
|
325
|
-
asm
|
|
326
|
-
.replace(/import \* as [^ ]+ from '[^']*';/g, "")
|
|
327
|
-
.replace("function asmFunc(imports) {", "")
|
|
328
|
-
.replace(/export var ([^ ]+) = ([^. ]+)\.([^ ]+);/g, "")
|
|
329
|
-
.replace(/var retasmFunc = [\s\S]*$/, "")
|
|
330
|
-
.replace(/var memasmFunc = new ArrayBuffer\(0\);/g, "")
|
|
331
|
-
.replace("memory.grow = __wasm_memory_grow;", "")
|
|
332
|
-
.trim()
|
|
333
|
-
}`,
|
|
334
|
-
)
|
|
335
|
-
.join(",\n");
|
|
336
|
-
|
|
337
|
-
// The `instantiate` function.
|
|
338
|
-
const instantiateFunction = `${withInstantiation ? "export " : ""}${async_}function instantiate(imports) {
|
|
339
|
-
const wasm_file_to_asm_index = {
|
|
340
|
-
${wasmFiles.map(([path], nth) => `'${basename(path)}': ${nth}`).join(",\n ")}
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
return ${await_}_instantiate(
|
|
344
|
-
module_name => wasm_file_to_asm_index[module_name],
|
|
345
|
-
imports,
|
|
346
|
-
(module_index, imports) => ({ exports: asmInit[module_index](imports) })
|
|
347
|
-
);
|
|
348
|
-
}`;
|
|
349
|
-
|
|
350
|
-
// If `--js` is used without `--instantiation`.
|
|
351
|
-
let importDirectives = "";
|
|
352
|
-
let exportDirectives = "";
|
|
353
|
-
let exportTrampolines = "";
|
|
354
|
-
let autoInstantiate = "";
|
|
355
|
-
|
|
356
|
-
if (!withInstantiation) {
|
|
357
|
-
importDirectives = imports
|
|
358
|
-
.map((import_file, nth) => `import * as import${nth} from '${import_file}';`)
|
|
359
|
-
.join("\n");
|
|
360
|
-
|
|
361
|
-
if (exports.length > 0 || opts.tlaCompat) {
|
|
362
|
-
exportDirectives = `export {
|
|
363
|
-
${
|
|
364
|
-
// Exporting `$init` must come first to not break the transpiling tests.
|
|
365
|
-
opts.tlaCompat ? " $init,\n" : ""
|
|
366
|
-
}${exports
|
|
367
|
-
.map(([name]) => {
|
|
368
|
-
if (name === asmMangle(name)) {
|
|
369
|
-
return ` ${name},`;
|
|
370
|
-
} else {
|
|
371
|
-
return ` ${asmMangle(name)} as '${name}',`;
|
|
372
|
-
}
|
|
373
|
-
})
|
|
374
|
-
.join("\n")}
|
|
375
|
-
}`;
|
|
376
|
-
}
|
|
377
35
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
} else {
|
|
389
|
-
return `\nlet ${asmMangle(name)};`;
|
|
390
|
-
}
|
|
391
|
-
})
|
|
392
|
-
.join("\n")}`;
|
|
393
|
-
|
|
394
|
-
autoInstantiate = `${async_}function $init() {
|
|
395
|
-
( {
|
|
396
|
-
${exports
|
|
397
|
-
.map(([name, ty]) => {
|
|
398
|
-
if (ty === "function") {
|
|
399
|
-
return ` '${name}': _${asmMangle(name)},`;
|
|
400
|
-
} else if (asmMangle(name) === name) {
|
|
401
|
-
return ` ${name},`;
|
|
402
|
-
} else {
|
|
403
|
-
return ` '${name}': ${asmMangle(name)},`;
|
|
404
|
-
}
|
|
405
|
-
})
|
|
406
|
-
.join("\n")}
|
|
407
|
-
} = ${await_}instantiate(
|
|
408
|
-
{
|
|
409
|
-
${imports.map((import_file, nth) => ` '${import_file}': import${nth},`).join("\n")}
|
|
410
|
-
}
|
|
411
|
-
) )
|
|
36
|
+
/**
|
|
37
|
+
* Transpile a component, given a path.
|
|
38
|
+
*
|
|
39
|
+
* @param {string} componentPath
|
|
40
|
+
* @param {TranspileOpts} opts
|
|
41
|
+
* @param {object} comander `Program` object
|
|
42
|
+
*/
|
|
43
|
+
export async function transpileCmd(componentPath, opts, program) {
|
|
44
|
+
const { files } = await transpile(componentPath, prepOpts(opts, program));
|
|
45
|
+
await writeFiles(files, opts.quiet ? false : "Transpiled JS Component Files");
|
|
412
46
|
}
|
|
413
47
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
${exportTrampolines}
|
|
425
|
-
|
|
426
|
-
${instantiateFunction}
|
|
427
|
-
|
|
428
|
-
${exportDirectives}
|
|
429
|
-
|
|
430
|
-
${autoInstantiate}`;
|
|
431
|
-
|
|
432
|
-
// Save the final generated code.
|
|
433
|
-
jsFile[1] = Buffer.from(outSource);
|
|
434
|
-
} finally {
|
|
435
|
-
if (spinner) {
|
|
436
|
-
spinner.stop();
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
if (opts.minify) {
|
|
442
|
-
try {
|
|
443
|
-
({ code: jsFile[1] } = await minify(Buffer.from(jsFile[1]).toString("utf8"), {
|
|
444
|
-
module: true,
|
|
445
|
-
compress: {
|
|
446
|
-
ecma: 9,
|
|
447
|
-
unsafe: true,
|
|
448
|
-
},
|
|
449
|
-
mangle: {
|
|
450
|
-
keep_classnames: true,
|
|
451
|
-
},
|
|
452
|
-
}));
|
|
453
|
-
} catch (err) {
|
|
454
|
-
console.error(`error while minifying JS: ${err}`);
|
|
455
|
-
throw err;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
return { files: Object.fromEntries(files), imports, exports };
|
|
48
|
+
/**
|
|
49
|
+
* Transpile a component, given WebAssembly bytes.
|
|
50
|
+
*
|
|
51
|
+
* @param {Uint8Array} component
|
|
52
|
+
* @param {TranspileOpts} [opts]
|
|
53
|
+
* @returns {Promise<{ files: { [filename: string]: Uint8Array }, imports: string[], exports: [string, 'function' | 'instance'][] }>}
|
|
54
|
+
*/
|
|
55
|
+
export async function transpileComponent(component, opts = {}) {
|
|
56
|
+
return transpileBytes(component, prepOpts(opts));
|
|
460
57
|
}
|
|
461
58
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (name === "") {
|
|
467
|
-
return "$";
|
|
59
|
+
function prepOpts(opts, program) {
|
|
60
|
+
const varIdx = program?.parent.rawArgs.indexOf("--");
|
|
61
|
+
if (varIdx !== undefined && varIdx !== -1) {
|
|
62
|
+
opts.optArgs = program.parent.rawArgs.slice(varIdx + 1);
|
|
468
63
|
}
|
|
469
64
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
// Names must start with a character, $ or _
|
|
474
|
-
switch (name[0]) {
|
|
475
|
-
case "0":
|
|
476
|
-
case "1":
|
|
477
|
-
case "2":
|
|
478
|
-
case "3":
|
|
479
|
-
case "4":
|
|
480
|
-
case "5":
|
|
481
|
-
case "6":
|
|
482
|
-
case "7":
|
|
483
|
-
case "8":
|
|
484
|
-
case "9": {
|
|
485
|
-
name = "$" + name;
|
|
486
|
-
i = 2;
|
|
487
|
-
// fallthrough
|
|
488
|
-
}
|
|
489
|
-
case "$":
|
|
490
|
-
case "_": {
|
|
491
|
-
mightBeKeyword = false;
|
|
492
|
-
break;
|
|
493
|
-
}
|
|
494
|
-
default: {
|
|
495
|
-
let chNum = name.charCodeAt(0);
|
|
496
|
-
if (!(chNum >= 97 && chNum <= 122) && !(chNum >= 65 && chNum <= 90)) {
|
|
497
|
-
name = "$" + name.substr(1);
|
|
498
|
-
mightBeKeyword = false;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
65
|
+
if (!opts.quiet) {
|
|
66
|
+
setShowSpinner(true);
|
|
501
67
|
}
|
|
502
68
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
switch (name[i]) {
|
|
507
|
-
case "0":
|
|
508
|
-
case "1":
|
|
509
|
-
case "2":
|
|
510
|
-
case "3":
|
|
511
|
-
case "4":
|
|
512
|
-
case "5":
|
|
513
|
-
case "6":
|
|
514
|
-
case "7":
|
|
515
|
-
case "8":
|
|
516
|
-
case "9":
|
|
517
|
-
case "$":
|
|
518
|
-
case "_": {
|
|
519
|
-
mightBeKeyword = false;
|
|
520
|
-
break;
|
|
521
|
-
}
|
|
522
|
-
default: {
|
|
523
|
-
let chNum = name.charCodeAt(i);
|
|
524
|
-
if (!(chNum >= 97 && chNum <= 122) && !(chNum >= 65 && chNum <= 90)) {
|
|
525
|
-
name = name.substr(0, i) + "_" + name.substr(i + 1);
|
|
526
|
-
mightBeKeyword = false;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
69
|
+
if (opts.map) {
|
|
70
|
+
if (typeof opts.map === "string") {
|
|
71
|
+
opts.map = opts.map.split(",");
|
|
529
72
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
// Names must not collide with keywords
|
|
533
|
-
if (mightBeKeyword && len >= 2 && len <= 10) {
|
|
534
|
-
switch (name[0]) {
|
|
535
|
-
case "a": {
|
|
536
|
-
if (name == "arguments") {
|
|
537
|
-
return name + "_";
|
|
538
|
-
}
|
|
539
|
-
break;
|
|
540
|
-
}
|
|
541
|
-
case "b": {
|
|
542
|
-
if (name == "break") {
|
|
543
|
-
return name + "_";
|
|
544
|
-
}
|
|
545
|
-
break;
|
|
546
|
-
}
|
|
547
|
-
case "c": {
|
|
548
|
-
if (name == "case" || name == "continue" || name == "catch" || name == "const" || name == "class") {
|
|
549
|
-
return name + "_";
|
|
550
|
-
}
|
|
551
|
-
break;
|
|
552
|
-
}
|
|
553
|
-
case "d": {
|
|
554
|
-
if (name == "do" || name == "default" || name == "debugger") {
|
|
555
|
-
return name + "_";
|
|
556
|
-
}
|
|
557
|
-
break;
|
|
558
|
-
}
|
|
559
|
-
case "e": {
|
|
560
|
-
if (
|
|
561
|
-
name == "else" ||
|
|
562
|
-
name == "enum" ||
|
|
563
|
-
name == "eval" || // to be sure
|
|
564
|
-
name == "export" ||
|
|
565
|
-
name == "extends"
|
|
566
|
-
) {
|
|
567
|
-
return name + "_";
|
|
568
|
-
}
|
|
569
|
-
break;
|
|
570
|
-
}
|
|
571
|
-
case "f": {
|
|
572
|
-
if (name == "for" || name == "false" || name == "finally" || name == "function") {
|
|
573
|
-
return name + "_";
|
|
574
|
-
}
|
|
575
|
-
break;
|
|
576
|
-
}
|
|
577
|
-
case "i": {
|
|
578
|
-
if (
|
|
579
|
-
name == "if" ||
|
|
580
|
-
name == "in" ||
|
|
581
|
-
name == "import" ||
|
|
582
|
-
name == "interface" ||
|
|
583
|
-
name == "implements" ||
|
|
584
|
-
name == "instanceof"
|
|
585
|
-
) {
|
|
586
|
-
return name + "_";
|
|
587
|
-
}
|
|
588
|
-
break;
|
|
589
|
-
}
|
|
590
|
-
case "l": {
|
|
591
|
-
if (name == "let") {
|
|
592
|
-
return name + "_";
|
|
593
|
-
}
|
|
594
|
-
break;
|
|
595
|
-
}
|
|
596
|
-
case "n": {
|
|
597
|
-
if (name == "new" || name == "null") {
|
|
598
|
-
return name + "_";
|
|
599
|
-
}
|
|
600
|
-
break;
|
|
601
|
-
}
|
|
602
|
-
case "p": {
|
|
603
|
-
if (name == "public" || name == "package" || name == "private" || name == "protected") {
|
|
604
|
-
return name + "_";
|
|
605
|
-
}
|
|
606
|
-
break;
|
|
607
|
-
}
|
|
608
|
-
case "r": {
|
|
609
|
-
if (name == "return") {
|
|
610
|
-
return name + "_";
|
|
611
|
-
}
|
|
612
|
-
break;
|
|
613
|
-
}
|
|
614
|
-
case "s": {
|
|
615
|
-
if (name == "super" || name == "static" || name == "switch") {
|
|
616
|
-
return name + "_";
|
|
617
|
-
}
|
|
618
|
-
break;
|
|
619
|
-
}
|
|
620
|
-
case "t": {
|
|
621
|
-
if (name == "try" || name == "this" || name == "true" || name == "throw" || name == "typeof") {
|
|
622
|
-
return name + "_";
|
|
623
|
-
}
|
|
624
|
-
break;
|
|
625
|
-
}
|
|
626
|
-
case "v": {
|
|
627
|
-
if (name == "var" || name == "void") {
|
|
628
|
-
return name + "_";
|
|
629
|
-
}
|
|
630
|
-
break;
|
|
631
|
-
}
|
|
632
|
-
case "w": {
|
|
633
|
-
if (name == "with" || name == "while") {
|
|
634
|
-
return name + "_";
|
|
635
|
-
}
|
|
636
|
-
break;
|
|
637
|
-
}
|
|
638
|
-
case "y": {
|
|
639
|
-
if (name == "yield") {
|
|
640
|
-
return name + "_";
|
|
641
|
-
}
|
|
642
|
-
break;
|
|
643
|
-
}
|
|
73
|
+
if (Array.isArray(opts.map)) {
|
|
74
|
+
opts.map = Object.fromEntries(opts.map.map((s) => s.split("=")));
|
|
644
75
|
}
|
|
645
76
|
}
|
|
646
|
-
|
|
77
|
+
|
|
78
|
+
return opts;
|
|
647
79
|
}
|
|
648
80
|
|
|
649
81
|
// see: https://github.com/vitest-dev/vitest/issues/6953#issuecomment-2505310022
|