emsdk-env 0.10.0 → 0.12.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 (41) hide show
  1. package/dist/build-BAcPqsVO.js +1379 -0
  2. package/dist/build-BAcPqsVO.js.map +1 -0
  3. package/dist/build-TpHGBYTu.cjs +1388 -0
  4. package/dist/build-TpHGBYTu.cjs.map +1 -0
  5. package/dist/build.d.ts +22 -0
  6. package/dist/build.d.ts.map +1 -0
  7. package/dist/commands.d.ts +14 -0
  8. package/dist/commands.d.ts.map +1 -0
  9. package/dist/emsdk.d.ts +22 -0
  10. package/dist/emsdk.d.ts.map +1 -0
  11. package/dist/env.d.ts +16 -0
  12. package/dist/env.d.ts.map +1 -0
  13. package/dist/fs-utils.d.ts +13 -0
  14. package/dist/fs-utils.d.ts.map +1 -0
  15. package/dist/generated/packageMetadata.d.ts +18 -0
  16. package/dist/generated/packageMetadata.d.ts.map +1 -0
  17. package/dist/index.cjs +11 -14
  18. package/dist/index.d.ts +17 -338
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.mjs +10 -15
  21. package/dist/logger.d.ts +13 -0
  22. package/dist/logger.d.ts.map +1 -0
  23. package/dist/{vite.d.ts → types.d.ts} +299 -268
  24. package/dist/types.d.ts.map +1 -0
  25. package/dist/vite/index.d.ts +24 -0
  26. package/dist/vite/index.d.ts.map +1 -0
  27. package/dist/vite/logger.d.ts +14 -0
  28. package/dist/vite/logger.d.ts.map +1 -0
  29. package/dist/vite/types.d.ts +17 -0
  30. package/dist/vite/types.d.ts.map +1 -0
  31. package/dist/vite.cjs +735 -712
  32. package/dist/vite.cjs.map +1 -1
  33. package/dist/vite.mjs +729 -712
  34. package/dist/vite.mjs.map +1 -1
  35. package/package.json +22 -21
  36. package/dist/build-BE9Z95iJ.js +0 -1668
  37. package/dist/build-BE9Z95iJ.js.map +0 -1
  38. package/dist/build-BGtsNe6D.cjs +0 -1689
  39. package/dist/build-BGtsNe6D.cjs.map +0 -1
  40. package/dist/index.cjs.map +0 -1
  41. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,1379 @@
1
+ /*!
2
+ * name: emsdk-env
3
+ * version: 0.12.0
4
+ * description: Emscripten environment builder
5
+ * author: Kouji Matsui (@kekyo@mi.kekyo.net)
6
+ * license: MIT
7
+ * repository.url: https://github.com/kekyo/emsdk-env
8
+ * git.commit.hash: 13e3966455dae312e6e85f6470003bf7619ec02d
9
+ */
10
+ import { access, constants, mkdir, mkdtemp, readFile, rename, rm, writeFile } from "fs/promises";
11
+ import { homedir, tmpdir } from "os";
12
+ import { dirname, isAbsolute, join, parse, relative, resolve } from "path";
13
+ import { spawn } from "child_process";
14
+ import { glob } from "glob";
15
+ //#region node_modules/async-primitives/dist/index.mjs
16
+ /*!
17
+ * name: async-primitives
18
+ * version: 1.7.0
19
+ * description: A collection of primitive functions for asynchronous operations
20
+ * author: Kouji Matsui (@kekyo@mi.kekyo.net)
21
+ * license: MIT
22
+ * repository.url: https://github.com/kekyo/async-primitives.git
23
+ * git.commit.hash: 9472fbd5310b92690d84aaafb897429a04c013c5
24
+ */
25
+ /**
26
+ * A no-op Releasable object that does nothing when released or disposed
27
+ */
28
+ var __NOOP_HANDLER = () => {};
29
+ var __NOOP_RELEASABLE = {
30
+ release: __NOOP_HANDLER,
31
+ [Symbol.dispose]: __NOOP_HANDLER
32
+ };
33
+ var toAbortError = (reason) => {
34
+ if (reason instanceof Error) return reason;
35
+ if (typeof reason === "string") return new Error(reason);
36
+ return /* @__PURE__ */ new Error("Operation aborted");
37
+ };
38
+ /**
39
+ * Hooks up an abort handler to an AbortSignal and returns a handle for early cleanup
40
+ * @param signal - The AbortSignal to hook up to
41
+ * @param callback - The callback to call when the signal is aborted
42
+ * @returns A Releasable handle that can be used to remove the abort listener early
43
+ */
44
+ var onAbort = (signal, callback) => {
45
+ if (!signal) return __NOOP_RELEASABLE;
46
+ if (signal.aborted) {
47
+ try {
48
+ callback(toAbortError(signal.reason));
49
+ } catch (error) {
50
+ console.warn("AbortHook callback error: ", error);
51
+ }
52
+ return __NOOP_RELEASABLE;
53
+ }
54
+ let abortHandler = () => {
55
+ if (abortHandler) {
56
+ const reason = signal.reason;
57
+ signal.removeEventListener("abort", abortHandler);
58
+ abortHandler = void 0;
59
+ try {
60
+ callback(toAbortError(reason));
61
+ } catch (error) {
62
+ console.warn("AbortHook callback error: ", error);
63
+ }
64
+ }
65
+ };
66
+ const release = () => {
67
+ if (abortHandler) {
68
+ signal.removeEventListener("abort", abortHandler);
69
+ abortHandler = void 0;
70
+ }
71
+ };
72
+ signal.addEventListener("abort", abortHandler, { once: true });
73
+ return {
74
+ release,
75
+ [Symbol.dispose]: release
76
+ };
77
+ };
78
+ var runtimeGlobal$1 = globalThis;
79
+ var defer = (fn) => {
80
+ const setImmediateHandler = runtimeGlobal$1.setImmediate;
81
+ if (typeof setImmediateHandler === "function") {
82
+ setImmediateHandler(fn);
83
+ return;
84
+ }
85
+ globalThis.setTimeout(fn, 0);
86
+ };
87
+ var ABORTED_ERROR$2 = () => /* @__PURE__ */ new Error("Lock acquisition was aborted");
88
+ /**
89
+ * Creates a new LockHandle instance
90
+ * @param releaseCallback Callback function to release the lock
91
+ * @returns A LockHandle object with release and dispose functionality
92
+ */
93
+ var createLockHandle = (releaseCallback) => {
94
+ let isActive = true;
95
+ const release = () => {
96
+ if (!isActive) return;
97
+ isActive = false;
98
+ releaseCallback();
99
+ };
100
+ return {
101
+ get isActive() {
102
+ return isActive;
103
+ },
104
+ release,
105
+ [Symbol.dispose]: release
106
+ };
107
+ };
108
+ /**
109
+ * Creates a new Mutex instance
110
+ * @param maxConsecutiveCalls - The maximum number of consecutive calls to the lockAsync method before yielding control to the next item in the queue
111
+ * @returns A new Mutex for promise-based mutex operations
112
+ */
113
+ var createMutex = (maxConsecutiveCalls = 20) => {
114
+ let isLocked = false;
115
+ const queue = [];
116
+ let count = 0;
117
+ const processQueue = () => {
118
+ var _item$signal;
119
+ if (isLocked || queue.length === 0) return;
120
+ const item = queue.shift();
121
+ if ((_item$signal = item.signal) === null || _item$signal === void 0 ? void 0 : _item$signal.aborted) {
122
+ item.reject(ABORTED_ERROR$2());
123
+ scheduleNextProcess();
124
+ return;
125
+ }
126
+ isLocked = true;
127
+ const lockHandle = createLockHandle(releaseLock);
128
+ item.resolve(lockHandle);
129
+ };
130
+ const scheduleNextProcess = () => {
131
+ count++;
132
+ if (count >= maxConsecutiveCalls) {
133
+ count = 0;
134
+ defer(processQueue);
135
+ } else processQueue();
136
+ };
137
+ const releaseLock = () => {
138
+ if (!isLocked) return;
139
+ isLocked = false;
140
+ scheduleNextProcess();
141
+ };
142
+ const removeFromQueue = (item) => {
143
+ const index = queue.indexOf(item);
144
+ if (index !== -1) queue.splice(index, 1);
145
+ };
146
+ const lock = async (signal) => {
147
+ if (signal) {
148
+ if (signal.aborted) throw ABORTED_ERROR$2();
149
+ return new Promise((resolve, reject) => {
150
+ const queueItem = {
151
+ resolve: void 0,
152
+ reject: void 0,
153
+ signal
154
+ };
155
+ const abortHandle = onAbort(signal, () => {
156
+ removeFromQueue(queueItem);
157
+ reject(ABORTED_ERROR$2());
158
+ });
159
+ queueItem.resolve = (handle) => {
160
+ abortHandle.release();
161
+ resolve(handle);
162
+ };
163
+ queueItem.reject = (error) => {
164
+ abortHandle.release();
165
+ reject(error);
166
+ };
167
+ queue.push(queueItem);
168
+ processQueue();
169
+ });
170
+ } else return new Promise((resolve, reject) => {
171
+ queue.push({
172
+ resolve,
173
+ reject
174
+ });
175
+ processQueue();
176
+ });
177
+ };
178
+ return {
179
+ lock,
180
+ waiter: { wait: lock },
181
+ get isLocked() {
182
+ return isLocked;
183
+ },
184
+ get pendingCount() {
185
+ return queue.length;
186
+ }
187
+ };
188
+ };
189
+ var createLogicalContext = (id) => {
190
+ return {
191
+ id,
192
+ data: /* @__PURE__ */ new Map()
193
+ };
194
+ };
195
+ createLogicalContext(Symbol("[root]"));
196
+ //#endregion
197
+ //#region src/commands.ts
198
+ var createAbortError = () => {
199
+ const error = /* @__PURE__ */ new Error("The operation was aborted.");
200
+ error.name = "AbortError";
201
+ return error;
202
+ };
203
+ var runCommand = async (command, args, cwd, signal) => {
204
+ signal === null || signal === void 0 || signal.throwIfAborted();
205
+ return new Promise((resolvePromise, rejectPromise) => {
206
+ const child = spawn(command, args, {
207
+ cwd,
208
+ stdio: "inherit"
209
+ });
210
+ let settled = false;
211
+ const onAbort = () => {
212
+ if (settled) return;
213
+ settled = true;
214
+ child.kill();
215
+ rejectPromise(createAbortError());
216
+ };
217
+ signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true });
218
+ const cleanup = () => {
219
+ signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
220
+ };
221
+ child.once("error", (error) => {
222
+ if (settled) return;
223
+ settled = true;
224
+ cleanup();
225
+ rejectPromise(error);
226
+ });
227
+ child.once("close", (code) => {
228
+ if (settled) return;
229
+ settled = true;
230
+ cleanup();
231
+ if (code === 0) {
232
+ resolvePromise();
233
+ return;
234
+ }
235
+ rejectPromise(/* @__PURE__ */ new Error(`Command failed: ${command} ${args.join(" ")} (exit code ${code})`));
236
+ });
237
+ });
238
+ };
239
+ var runCommandWithEnv = async (command, args, cwd, env, signal) => {
240
+ signal === null || signal === void 0 || signal.throwIfAborted();
241
+ return new Promise((resolvePromise, rejectPromise) => {
242
+ const child = spawn(command, args, {
243
+ cwd,
244
+ env,
245
+ stdio: "inherit"
246
+ });
247
+ let settled = false;
248
+ const onAbort = () => {
249
+ if (settled) return;
250
+ settled = true;
251
+ child.kill();
252
+ rejectPromise(createAbortError());
253
+ };
254
+ signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true });
255
+ const cleanup = () => {
256
+ signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
257
+ };
258
+ child.once("error", (error) => {
259
+ if (settled) return;
260
+ settled = true;
261
+ cleanup();
262
+ rejectPromise(error);
263
+ });
264
+ child.once("close", (code) => {
265
+ if (settled) return;
266
+ settled = true;
267
+ cleanup();
268
+ if (code === 0) {
269
+ resolvePromise();
270
+ return;
271
+ }
272
+ rejectPromise(/* @__PURE__ */ new Error(`Command failed: ${command} ${args.join(" ")} (exit code ${code})`));
273
+ });
274
+ });
275
+ };
276
+ var runCommandCapture = async (command, args, cwd, signal) => {
277
+ signal === null || signal === void 0 || signal.throwIfAborted();
278
+ return new Promise((resolvePromise, rejectPromise) => {
279
+ const stdoutChunks = [];
280
+ const stderrChunks = [];
281
+ const child = spawn(command, args, {
282
+ cwd,
283
+ stdio: [
284
+ "ignore",
285
+ "pipe",
286
+ "pipe"
287
+ ]
288
+ });
289
+ let settled = false;
290
+ const onAbort = () => {
291
+ if (settled) return;
292
+ settled = true;
293
+ child.kill();
294
+ rejectPromise(createAbortError());
295
+ };
296
+ signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true });
297
+ const cleanup = () => {
298
+ signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
299
+ };
300
+ child.stdout.on("data", (chunk) => {
301
+ stdoutChunks.push(chunk);
302
+ });
303
+ child.stderr.on("data", (chunk) => {
304
+ stderrChunks.push(chunk);
305
+ });
306
+ child.once("error", (error) => {
307
+ if (settled) return;
308
+ settled = true;
309
+ cleanup();
310
+ rejectPromise(error);
311
+ });
312
+ child.once("close", (code) => {
313
+ if (settled) return;
314
+ settled = true;
315
+ cleanup();
316
+ if (code === 0) {
317
+ resolvePromise(Buffer.concat(stdoutChunks));
318
+ return;
319
+ }
320
+ const stderrText = Buffer.concat(stderrChunks).toString("utf8");
321
+ rejectPromise(/* @__PURE__ */ new Error(`Command failed: ${command} ${args.join(" ")} (exit code ${code})${stderrText ? `\n${stderrText}` : ""}`));
322
+ });
323
+ });
324
+ };
325
+ //#endregion
326
+ //#region src/fs-utils.ts
327
+ var pathExists = async (targetPath) => {
328
+ try {
329
+ await access(targetPath, constants.F_OK);
330
+ return true;
331
+ } catch (_unused) {
332
+ return false;
333
+ }
334
+ };
335
+ var ensureDirectory = async (targetPath) => {
336
+ await mkdir(targetPath, { recursive: true });
337
+ };
338
+ //#endregion
339
+ //#region src/emsdk.ts
340
+ var DEFAULT_REPO_URL = "https://github.com/emscripten-core/emsdk.git";
341
+ var DEFAULT_GIT_REF = "main";
342
+ var DEFAULT_CACHE_DIR = join(homedir(), ".cache", "emsdk-env");
343
+ var DEFAULT_TARGET_VERSION = "latest";
344
+ var versionMutexes = /* @__PURE__ */ new Map();
345
+ var getVersionMutex = (key) => {
346
+ let mutex = versionMutexes.get(key);
347
+ if (!mutex) {
348
+ mutex = createMutex();
349
+ versionMutexes.set(key, mutex);
350
+ }
351
+ return mutex;
352
+ };
353
+ var ensureNonEmpty = (value, label) => {
354
+ if (value.trim().length === 0) throw new TypeError(`${label} must be a non-empty string.`);
355
+ };
356
+ var sanitizeSegment = (value) => {
357
+ const trimmed = value.trim();
358
+ ensureNonEmpty(trimmed, "targetVersion");
359
+ const sanitized = trimmed.replace(/[^A-Za-z0-9._-]/g, "_");
360
+ if (sanitized === "." || sanitized === ".." || sanitized.length === 0) throw new TypeError("targetVersion results in an unsafe path segment.");
361
+ return sanitized;
362
+ };
363
+ var resolveEmsdkCommand = () => process.platform === "win32" ? "emsdk.bat" : "./emsdk";
364
+ var runEmsdk = async (repoDir, args, signal) => {
365
+ if (process.platform === "win32") {
366
+ await runCommand("cmd", [
367
+ "/c",
368
+ "emsdk.bat",
369
+ ...args
370
+ ], repoDir, signal);
371
+ return;
372
+ }
373
+ await runCommand(resolveEmsdkCommand(), args, repoDir, signal);
374
+ };
375
+ var runGitClone = async (gitPath, repoUrl, targetDir, cwd, signal) => {
376
+ await runCommand(gitPath, [
377
+ "clone",
378
+ repoUrl,
379
+ targetDir,
380
+ "--depth",
381
+ "1",
382
+ "--branch",
383
+ DEFAULT_GIT_REF
384
+ ], cwd, signal);
385
+ };
386
+ var isAlreadyExistsError = (error) => error instanceof Error && "code" in error && error.code !== void 0 && [
387
+ "EEXIST",
388
+ "ENOTEMPTY",
389
+ "EISDIR"
390
+ ].includes(String(error.code));
391
+ /**
392
+ * Prepare the Emscripten SDK in the local cache and return the SDK root path.
393
+ *
394
+ * Clones the emsdk repository if needed, installs the requested version,
395
+ * and activates it in the cache directory.
396
+ *
397
+ * @param options - SDK preparation options.
398
+ * @returns Absolute path to the prepared SDK root.
399
+ */
400
+ var prepareEmsdk = async (options) => {
401
+ var _options$targetVersio, _options$signal, _options$cacheDir, _options$repoUrl, _options$gitPath;
402
+ if (!options) throw new TypeError("options must be provided.");
403
+ if (options.targetVersion !== void 0 && typeof options.targetVersion !== "string") throw new TypeError("targetVersion must be a string.");
404
+ const targetVersion = (_options$targetVersio = options.targetVersion) !== null && _options$targetVersio !== void 0 ? _options$targetVersio : DEFAULT_TARGET_VERSION;
405
+ ensureNonEmpty(targetVersion, "targetVersion");
406
+ (_options$signal = options.signal) === null || _options$signal === void 0 || _options$signal.throwIfAborted();
407
+ const cacheDir = resolve((_options$cacheDir = options.cacheDir) !== null && _options$cacheDir !== void 0 ? _options$cacheDir : DEFAULT_CACHE_DIR);
408
+ const repoUrl = (_options$repoUrl = options.repoUrl) !== null && _options$repoUrl !== void 0 ? _options$repoUrl : DEFAULT_REPO_URL;
409
+ const gitPath = (_options$gitPath = options.gitPath) !== null && _options$gitPath !== void 0 ? _options$gitPath : "git";
410
+ const finalDir = resolve(cacheDir, sanitizeSegment(targetVersion));
411
+ const lock = await getVersionMutex(finalDir).lock(options.signal);
412
+ try {
413
+ var _options$signal2, _options$signal4;
414
+ (_options$signal2 = options.signal) === null || _options$signal2 === void 0 || _options$signal2.throwIfAborted();
415
+ if (await pathExists(finalDir)) return finalDir;
416
+ await ensureDirectory(cacheDir);
417
+ const tempRoot = await mkdtemp(join(cacheDir, ".tmp-"));
418
+ const tempRepoDir = join(tempRoot, "emsdk");
419
+ try {
420
+ var _options$signal3;
421
+ await runGitClone(gitPath, repoUrl, tempRepoDir, cacheDir, options.signal);
422
+ (_options$signal3 = options.signal) === null || _options$signal3 === void 0 || _options$signal3.throwIfAborted();
423
+ await runEmsdk(tempRepoDir, ["install", targetVersion], options.signal);
424
+ try {
425
+ await rename(tempRepoDir, finalDir);
426
+ } catch (error) {
427
+ if (isAlreadyExistsError(error)) return finalDir;
428
+ throw error;
429
+ }
430
+ } finally {
431
+ await rm(tempRoot, {
432
+ recursive: true,
433
+ force: true
434
+ });
435
+ }
436
+ (_options$signal4 = options.signal) === null || _options$signal4 === void 0 || _options$signal4.throwIfAborted();
437
+ await runEmsdk(finalDir, ["activate", targetVersion], options.signal);
438
+ return finalDir;
439
+ } finally {
440
+ lock.release();
441
+ }
442
+ };
443
+ //#endregion
444
+ //#region src/env.ts
445
+ var shellQuote = (value) => `'${String(value).replace(/'/g, `'\"'\"'`)}'`;
446
+ var parseEnvBuffer = (buffer) => {
447
+ const entries = buffer.toString("utf8").split("\0");
448
+ const env = {};
449
+ for (const entry of entries) {
450
+ if (!entry) continue;
451
+ const delimiterIndex = entry.indexOf("=");
452
+ if (delimiterIndex <= 0) continue;
453
+ const key = entry.slice(0, delimiterIndex);
454
+ env[key] = entry.slice(delimiterIndex + 1);
455
+ }
456
+ return env;
457
+ };
458
+ var loadEmsdkEnv = async (emsdkRoot, logger, signal) => {
459
+ if (process.platform === "win32") throw new Error("Emscripten environment extraction on Windows is not implemented yet.");
460
+ const envScript = resolve(emsdkRoot, "emsdk_env.sh");
461
+ if (!await pathExists(envScript)) throw new Error(`emsdk_env.sh not found: ${envScript}`);
462
+ const command = `. ${shellQuote(envScript)} >/dev/null 2>&1; env -0`;
463
+ logger.debug(`Loading emsdk environment: ${envScript}`);
464
+ return parseEnvBuffer(await runCommandCapture("bash", ["-lc", command], emsdkRoot, signal));
465
+ };
466
+ var resolveEmccCommand = async (env, emsdkRoot) => {
467
+ if (env.EMCC) return env.EMCC;
468
+ if (env.EMSCRIPTEN) {
469
+ const candidate = join(env.EMSCRIPTEN, "emcc");
470
+ if (await pathExists(candidate)) return candidate;
471
+ }
472
+ const fallback = join(emsdkRoot, "upstream", "emscripten", "emcc");
473
+ if (await pathExists(fallback)) return fallback;
474
+ return "emcc";
475
+ };
476
+ var resolveEmarCommand = async (env, emsdkRoot) => {
477
+ if (env.EMAR) return env.EMAR;
478
+ if (env.EMSCRIPTEN) {
479
+ const candidate = join(env.EMSCRIPTEN, "emar");
480
+ if (await pathExists(candidate)) return candidate;
481
+ }
482
+ const fallback = join(emsdkRoot, "upstream", "emscripten", "emar");
483
+ if (await pathExists(fallback)) return fallback;
484
+ return "emar";
485
+ };
486
+ var resolveWasmOptCommand = async (env, emsdkRoot) => {
487
+ var _env$BINARYEN_ROOT;
488
+ if (env.WASM_OPT) return env.WASM_OPT;
489
+ const binaryenRoot = (_env$BINARYEN_ROOT = env.BINARYEN_ROOT) !== null && _env$BINARYEN_ROOT !== void 0 ? _env$BINARYEN_ROOT : env.BINARYEN;
490
+ if (binaryenRoot) {
491
+ const candidate = join(binaryenRoot, "bin", "wasm-opt");
492
+ if (await pathExists(candidate)) return candidate;
493
+ }
494
+ const fallback = join(emsdkRoot, "upstream", "bin", "wasm-opt");
495
+ if (await pathExists(fallback)) return fallback;
496
+ return "wasm-opt";
497
+ };
498
+ //#endregion
499
+ //#region src/logger.ts
500
+ var createConsoleLogger = (prefix) => {
501
+ return {
502
+ debug: (msg) => console.debug(`[${prefix}]: ${msg}`),
503
+ info: (msg) => console.info(`[${prefix}]: ${msg}`),
504
+ warn: (msg) => console.warn(`[${prefix}]: ${msg}`),
505
+ error: (msg) => console.error(`[${prefix}]: ${msg}`)
506
+ };
507
+ };
508
+ //#endregion
509
+ //#region src/build.ts
510
+ var DEFAULT_WASM_SRC_DIR = "wasm";
511
+ var DEFAULT_WASM_INCLUDE_DIR = "include";
512
+ var DEFAULT_WASM_OUT_DIR = join("src", "wasm");
513
+ var DEFAULT_WASM_LIB_DIR = "lib";
514
+ var DEFAULT_IMPORT_INCLUDE_DIR = "include";
515
+ var DEFAULT_IMPORT_LIB_DIR = "lib";
516
+ var DEFAULT_WASM_BUILD_DIR = join(tmpdir(), "emsdk-env");
517
+ var DEFAULT_EMSDK_TARGET_VERSION = "latest";
518
+ var DEFAULT_WASM_OPT_ARGS = ["-Oz"];
519
+ var DEFAULT_GENERATED_LOADER_OUT_FILE = join("src", "generated", "wasm-loader.ts");
520
+ var buildSequence = 0;
521
+ var padNumber = (value, length = 2) => String(value).padStart(length, "0");
522
+ var formatTimestamp = (date) => {
523
+ return `${date.getFullYear()}${padNumber(date.getMonth() + 1)}${padNumber(date.getDate())}_${padNumber(date.getHours())}${padNumber(date.getMinutes())}${padNumber(date.getSeconds())}`;
524
+ };
525
+ var createBuildId = () => {
526
+ buildSequence += 1;
527
+ return `${formatTimestamp(/* @__PURE__ */ new Date())}_${String(buildSequence).padStart(4, "0")}_${process.pid}`;
528
+ };
529
+ var ensureArray = (value) => value !== null && value !== void 0 ? value : [];
530
+ var resolveTargetType = (value) => value !== null && value !== void 0 ? value : "wasm";
531
+ var normalizePrepareOptions = (options) => {
532
+ const { targetVersion, ...rest } = options !== null && options !== void 0 ? options : {};
533
+ return {
534
+ targetVersion: targetVersion !== null && targetVersion !== void 0 ? targetVersion : DEFAULT_EMSDK_TARGET_VERSION,
535
+ ...rest
536
+ };
537
+ };
538
+ var parseStringKeyValueInput = (values) => {
539
+ const parsed = {};
540
+ for (const entry of values) {
541
+ const index = entry.indexOf("=");
542
+ if (index === -1) {
543
+ parsed[entry] = void 0;
544
+ continue;
545
+ }
546
+ const key = entry.slice(0, index);
547
+ parsed[key] = entry.slice(index + 1);
548
+ }
549
+ return parsed;
550
+ };
551
+ var isDefineMap = (input) => input instanceof Map;
552
+ var normalizeDefineInput = (input) => {
553
+ if (!input) return {};
554
+ if (Array.isArray(input)) return parseStringKeyValueInput(input);
555
+ if (isDefineMap(input)) return Object.fromEntries(input);
556
+ return { ...input };
557
+ };
558
+ var isLinkDirectiveMap = (input) => input instanceof Map;
559
+ var normalizeLinkDirectiveInput = (input) => {
560
+ if (!input) return {};
561
+ if (Array.isArray(input)) return parseStringKeyValueInput(input);
562
+ if (isLinkDirectiveMap(input)) return Object.fromEntries(input);
563
+ return { ...input };
564
+ };
565
+ var mergeDefines = (common, target) => ({
566
+ ...normalizeDefineInput(common),
567
+ ...normalizeDefineInput(target)
568
+ });
569
+ var mergeLinkDirectives = (common, target) => ({
570
+ ...normalizeLinkDirectiveInput(common),
571
+ ...normalizeLinkDirectiveInput(target)
572
+ });
573
+ var resolveWasmOptEnabled = (common, target) => {
574
+ var _ref, _target$enable;
575
+ return (_ref = (_target$enable = target === null || target === void 0 ? void 0 : target.enable) !== null && _target$enable !== void 0 ? _target$enable : common === null || common === void 0 ? void 0 : common.enable) !== null && _ref !== void 0 ? _ref : false;
576
+ };
577
+ var resolveWasmOptArgs = (common, target, env) => {
578
+ var _common$options, _target$options;
579
+ const commonArgs = (_common$options = common === null || common === void 0 ? void 0 : common.options) !== null && _common$options !== void 0 ? _common$options : DEFAULT_WASM_OPT_ARGS;
580
+ const targetArgs = (_target$options = target === null || target === void 0 ? void 0 : target.options) !== null && _target$options !== void 0 ? _target$options : [];
581
+ return expandArray([...commonArgs, ...targetArgs], env, "wasmOpt.options");
582
+ };
583
+ var stripOuterQuotes = (value) => {
584
+ const trimmed = value.trim();
585
+ if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
586
+ return trimmed;
587
+ };
588
+ var extractWasmBinaryFile = (value) => {
589
+ if (value.startsWith("WASM_BINARY_FILE=")) return value.slice(17);
590
+ const match = value.match(/^(?:-s|--settings)(?:=)?WASM_BINARY_FILE=(.+)$/);
591
+ if (match) return match[1];
592
+ };
593
+ var resolveWasmBinaryFileFromLinkOptions = (linkOptions) => {
594
+ for (let index = 0; index < linkOptions.length; index += 1) {
595
+ const option = linkOptions[index];
596
+ if (!option) continue;
597
+ if (option === "-s" || option === "--settings") {
598
+ const next = linkOptions[index + 1];
599
+ if (!next) continue;
600
+ const extracted = extractWasmBinaryFile(next);
601
+ if (extracted) return stripOuterQuotes(extracted);
602
+ }
603
+ const extracted = extractWasmBinaryFile(option);
604
+ if (extracted) return stripOuterQuotes(extracted);
605
+ }
606
+ };
607
+ var resolveWasmOptInputFile = (resolvedOutFile, resolvedLinkOptions) => {
608
+ const wasmBinaryFile = resolveWasmBinaryFileFromLinkOptions(resolvedLinkOptions);
609
+ if (wasmBinaryFile) return isAbsolute(wasmBinaryFile) ? wasmBinaryFile : resolve(dirname(resolvedOutFile), wasmBinaryFile);
610
+ const parsed = parse(resolvedOutFile);
611
+ if (parsed.ext.toLowerCase() === ".wasm") return resolvedOutFile;
612
+ const baseName = parsed.name.toLowerCase().endsWith(".wasm") ? parsed.name : `${parsed.name}.wasm`;
613
+ return join(parsed.dir, baseName);
614
+ };
615
+ var resolvePath = (rootDir, value) => isAbsolute(value) ? value : resolve(rootDir, value);
616
+ var expandPlaceholders = (value, env, label) => value.replace(/\{([A-Z0-9_]+)\}/g, (_match, key) => {
617
+ const replacement = env[key];
618
+ if (replacement === void 0) throw new Error(`Unknown placeholder {${key}} in ${label}.`);
619
+ return replacement;
620
+ });
621
+ var expandArray = (values, env, label) => values.map((value) => expandPlaceholders(value, env, label));
622
+ var resolveDefines = (defines, env) => {
623
+ const resolved = {};
624
+ for (const [key, value] of Object.entries(defines)) if (typeof value === "string") resolved[key] = expandPlaceholders(value, env, `defines.${key}`);
625
+ else resolved[key] = value;
626
+ return resolved;
627
+ };
628
+ var resolveLinkDirectiveValue = (value, env, label) => {
629
+ if (typeof value === "string") return expandPlaceholders(value, env, label);
630
+ if (Array.isArray(value)) return value.map((entry, index) => expandPlaceholders(entry, env, `${label}[${index}]`));
631
+ return value;
632
+ };
633
+ var resolveLinkDirectives = (directives, env) => {
634
+ const resolved = {};
635
+ for (const [key, value] of Object.entries(directives)) resolved[key] = resolveLinkDirectiveValue(value, env, `linkDirectives.${key}`);
636
+ return resolved;
637
+ };
638
+ var resolveIncludeDirs = (includeDirs, env, rootDir) => {
639
+ return expandArray(includeDirs, env, "includeDirs").map((value) => resolvePath(rootDir, value));
640
+ };
641
+ var resolveOutFile = (outFile, env, outDir) => {
642
+ return resolvePath(outDir, expandPlaceholders(outFile, env, "outFile"));
643
+ };
644
+ var resolveSourcesFromPatterns = async (patterns, env, srcDir, label) => {
645
+ const resolvedPatterns = expandArray(patterns, env, label).map((value) => resolvePath(srcDir, value));
646
+ const sources = (await Promise.all(resolvedPatterns.map((pattern) => glob(pattern, { nodir: true })))).flat();
647
+ sources.sort();
648
+ return sources;
649
+ };
650
+ var buildDefineFlags = (defines) => Object.entries(defines).flatMap(([key, value]) => value === null || value === void 0 ? [`-D${key}`] : [`-D${key}=${String(value)}`]);
651
+ var serializeLinkDirectiveValue = (value) => Array.isArray(value) ? JSON.stringify(value) : String(value);
652
+ var buildLinkDirectiveFlags = (directives) => {
653
+ if (Object.keys(directives).length === 0) return [];
654
+ return Object.entries(directives).flatMap(([key, value]) => value === null || value === void 0 ? ["-s", key] : ["-s", `${key}=${serializeLinkDirectiveValue(value)}`]);
655
+ };
656
+ var buildExportFlags = (exports) => {
657
+ if (exports.length === 0) return [];
658
+ return ["-s", `EXPORTED_FUNCTIONS=${JSON.stringify(exports)}`];
659
+ };
660
+ var createEnvForBuild = (baseEnv, overrides) => ({
661
+ ...process.env,
662
+ ...baseEnv,
663
+ ...overrides
664
+ });
665
+ var resolveTargetOutFile = (targetName, targetOutFile, env, baseDir, extension) => {
666
+ if (targetOutFile) return resolveOutFile(targetOutFile, env, baseDir);
667
+ return resolve(baseDir, `${targetName}.${extension}`);
668
+ };
669
+ var resolveTargetSources = async (targetSources, env, srcDir) => {
670
+ return resolveSourcesFromPatterns(targetSources && targetSources.length > 0 ? targetSources : [join(srcDir, "**", "*.c"), join(srcDir, "**", "*.cpp")], env, srcDir, "sources");
671
+ };
672
+ var toSafeObjectName = (rootDir, sourcePath, groupIndex) => {
673
+ const baseName = relative(rootDir, sourcePath).replace(/[\\/]/g, "_").replace(/[^A-Za-z0-9._-]/g, "_");
674
+ if (groupIndex === void 0) return baseName;
675
+ return `${baseName}__g${groupIndex}`;
676
+ };
677
+ var dedupeSources = (sources) => {
678
+ const seen = /* @__PURE__ */ new Set();
679
+ const deduped = [];
680
+ for (const source of sources) {
681
+ if (seen.has(source)) continue;
682
+ seen.add(source);
683
+ deduped.push(source);
684
+ }
685
+ return deduped;
686
+ };
687
+ var dedupeValues = (values) => {
688
+ const seen = /* @__PURE__ */ new Set();
689
+ const deduped = [];
690
+ for (const value of values) {
691
+ if (seen.has(value)) continue;
692
+ seen.add(value);
693
+ deduped.push(value);
694
+ }
695
+ return deduped;
696
+ };
697
+ var isSubPath = (parentDir, targetPath) => {
698
+ const rel = relative(parentDir, targetPath);
699
+ if (rel === "") return true;
700
+ return !rel.startsWith("..") && !isAbsolute(rel);
701
+ };
702
+ var readTextIfExists = async (filePath) => {
703
+ try {
704
+ return await readFile(filePath, "utf8");
705
+ } catch (error) {
706
+ if (error.code === "ENOENT") return;
707
+ throw error;
708
+ }
709
+ };
710
+ var writeTextIfChanged = async (filePath, content) => {
711
+ if (await readTextIfExists(filePath) === content) return false;
712
+ await ensureDirectory(dirname(filePath));
713
+ await writeFile(filePath, content, "utf8");
714
+ return true;
715
+ };
716
+ var toPascalCaseIdentifier = (value) => {
717
+ const tokens = value.split(/[^A-Za-z0-9]+/).map((token) => token.trim()).filter((token) => token.length > 0);
718
+ if (tokens.length === 0) throw new Error(`Cannot derive loader function name from target: ${value}`);
719
+ const pascal = tokens.map((token) => token.charAt(0).toUpperCase() + token.slice(1)).join("");
720
+ return /^[0-9]/.test(pascal) ? `Target${pascal}` : pascal;
721
+ };
722
+ var toRelativeImportSpecifier = (fromFile, toFile) => {
723
+ const rel = relative(dirname(fromFile), toFile).replace(/\\/g, "/");
724
+ return rel.startsWith(".") ? rel : `./${rel}`;
725
+ };
726
+ var buildGeneratedLoaderContent = (generatedLoaderFile, targets) => {
727
+ return `// Generated by emsdk-env. DO NOT EDIT.
728
+
729
+ /**
730
+ * Supported input sources for loading a WASM binary.
731
+ */
732
+ export type WasmSource =
733
+ | string
734
+ | URL
735
+ | ArrayBuffer
736
+ | ArrayBufferView
737
+ | Response;
738
+
739
+ /**
740
+ * Options for instantiating a WASM module.
741
+ */
742
+ export interface WasmLoadOptions {
743
+ /**
744
+ * Imports passed to WebAssembly.instantiate().
745
+ */
746
+ readonly imports?: WebAssembly.Imports;
747
+ }
748
+
749
+ /**
750
+ * Options for loading a generated WASM target.
751
+ */
752
+ export interface TargetWasmLoadOptions extends WasmLoadOptions {
753
+ /**
754
+ * Override the generated default source for the target.
755
+ */
756
+ readonly source?: WasmSource;
757
+ }
758
+
759
+ const isResponse = (value: WasmSource): value is Response =>
760
+ typeof Response !== 'undefined' && value instanceof Response;
761
+
762
+ const createWasmLoadOptions = (
763
+ imports: WebAssembly.Imports | undefined
764
+ ): WasmLoadOptions | undefined => (imports ? { imports } : undefined);
765
+
766
+ /**
767
+ * Instantiated WASM module with typed export helpers.
768
+ *
769
+ * @typeParam TExports Function exports exposed through the exports property.
770
+ * @typeParam TAllExports Full WebAssembly export map exposed through the allExports property.
771
+ */
772
+ export interface WasmInstance<
773
+ TExports extends object = Record<string, (...args: unknown[]) => unknown>,
774
+ TAllExports extends WebAssembly.Exports = WebAssembly.Exports> {
775
+ /**
776
+ * Exported functions only.
777
+ */
778
+ readonly exports: TExports;
779
+ /**
780
+ * All exported values with caller-provided typing.
781
+ */
782
+ readonly allExports: TAllExports;
783
+ /**
784
+ * Resolved linear memory used by the module.
785
+ */
786
+ readonly memory: WebAssembly.Memory;
787
+ /**
788
+ * Resolved function table when the module uses one.
789
+ */
790
+ readonly table: WebAssembly.Table | undefined;
791
+ /**
792
+ * Raw exports object returned by WebAssembly.instantiate().
793
+ */
794
+ readonly rawExports: WebAssembly.Exports;
795
+ /**
796
+ * Compiled WebAssembly module.
797
+ */
798
+ readonly module: WebAssembly.Module;
799
+ /**
800
+ * Instantiated WebAssembly instance.
801
+ */
802
+ readonly instance: WebAssembly.Instance;
803
+ /**
804
+ * Optional Emscripten _initialize export.
805
+ */
806
+ readonly initialize: (() => unknown) | undefined;
807
+ /**
808
+ * Optional WASI _start export.
809
+ */
810
+ readonly start: (() => unknown) | undefined;
811
+ }
812
+
813
+ const resolveWasmBytes = async (source: WasmSource): Promise<ArrayBuffer> => {
814
+ if (isResponse(source)) {
815
+ return await source.arrayBuffer();
816
+ }
817
+ if (source instanceof URL || typeof source === 'string') {
818
+ const response = await fetch(source);
819
+ if (!response.ok) {
820
+ throw new Error(\`Failed to fetch wasm: \${response.url}\`);
821
+ }
822
+ return await response.arrayBuffer();
823
+ }
824
+ if (source instanceof ArrayBuffer) {
825
+ return source;
826
+ }
827
+ if (ArrayBuffer.isView(source)) {
828
+ const view = new Uint8Array(
829
+ source.buffer,
830
+ source.byteOffset,
831
+ source.byteLength
832
+ );
833
+ return view.slice().buffer;
834
+ }
835
+ throw new TypeError('Unsupported wasm source.');
836
+ };
837
+
838
+ const getImportValue = (
839
+ imports: WebAssembly.Imports | undefined,
840
+ moduleName: string,
841
+ name: string
842
+ ) => {
843
+ const moduleImports = imports?.[moduleName];
844
+ if (!moduleImports || typeof moduleImports !== 'object') {
845
+ return undefined;
846
+ }
847
+ return (moduleImports as Record<string, unknown>)[name];
848
+ };
849
+
850
+ const resolveMemory = (
851
+ module: WebAssembly.Module,
852
+ instance: WebAssembly.Instance,
853
+ imports: WebAssembly.Imports | undefined
854
+ ) => {
855
+ let memory: WebAssembly.Memory | undefined;
856
+ for (const entry of WebAssembly.Module.exports(module)) {
857
+ if (entry.kind !== 'memory') {
858
+ continue;
859
+ }
860
+ if (memory) {
861
+ throw new Error('Multiple wasm memories are not supported.');
862
+ }
863
+ const value = instance.exports[entry.name];
864
+ if (!(value instanceof WebAssembly.Memory)) {
865
+ throw new Error(\`Export is not a WebAssembly.Memory: \${entry.name}\`);
866
+ }
867
+ memory = value;
868
+ }
869
+ if (memory) {
870
+ return memory;
871
+ }
872
+ for (const entry of WebAssembly.Module.imports(module)) {
873
+ if (entry.kind !== 'memory') {
874
+ continue;
875
+ }
876
+ if (memory) {
877
+ throw new Error('Multiple wasm memories are not supported.');
878
+ }
879
+ const value = getImportValue(imports, entry.module, entry.name);
880
+ if (!(value instanceof WebAssembly.Memory)) {
881
+ throw new Error(
882
+ \`Imported value is not a WebAssembly.Memory: \${entry.module}.\${entry.name}\`
883
+ );
884
+ }
885
+ memory = value;
886
+ }
887
+ if (!memory) {
888
+ throw new Error('WASM memory export/import was not resolved.');
889
+ }
890
+ return memory;
891
+ };
892
+
893
+ const resolveTable = (
894
+ module: WebAssembly.Module,
895
+ instance: WebAssembly.Instance,
896
+ imports: WebAssembly.Imports | undefined
897
+ ) => {
898
+ let table: WebAssembly.Table | undefined;
899
+ for (const entry of WebAssembly.Module.exports(module)) {
900
+ if (entry.kind !== 'table') {
901
+ continue;
902
+ }
903
+ if (table) {
904
+ throw new Error('Multiple wasm tables are not supported.');
905
+ }
906
+ const value = instance.exports[entry.name];
907
+ if (!(value instanceof WebAssembly.Table)) {
908
+ throw new Error(\`Export is not a WebAssembly.Table: \${entry.name}\`);
909
+ }
910
+ table = value;
911
+ }
912
+ if (table) {
913
+ return table;
914
+ }
915
+ for (const entry of WebAssembly.Module.imports(module)) {
916
+ if (entry.kind !== 'table') {
917
+ continue;
918
+ }
919
+ if (table) {
920
+ throw new Error('Multiple wasm tables are not supported.');
921
+ }
922
+ const value = getImportValue(imports, entry.module, entry.name);
923
+ if (!(value instanceof WebAssembly.Table)) {
924
+ throw new Error(
925
+ \`Imported value is not a WebAssembly.Table: \${entry.module}.\${entry.name}\`
926
+ );
927
+ }
928
+ table = value;
929
+ }
930
+ return table;
931
+ };
932
+
933
+ /**
934
+ * Load and instantiate a WASM module from the provided source.
935
+ *
936
+ * @typeParam TExports Function exports exposed through the exports property.
937
+ * @typeParam TAllExports Full WebAssembly export map exposed through the allExports property.
938
+ * @param source WASM source to load.
939
+ * @param options WebAssembly instantiation options.
940
+ * @returns The instantiated WASM module and resolved runtime handles.
941
+ */
942
+ export const loadWasm = async <
943
+ TExports extends object = Record<string, (...args: unknown[]) => unknown>,
944
+ TAllExports extends WebAssembly.Exports = WebAssembly.Exports>(
945
+ source: WasmSource,
946
+ options?: WasmLoadOptions
947
+ ): Promise<WasmInstance<TExports, TAllExports>> => {
948
+ const bytes = await resolveWasmBytes(source);
949
+ const module = await WebAssembly.compile(bytes);
950
+ const instance = await WebAssembly.instantiate(module, options?.imports ?? {});
951
+
952
+ const functionExports: Record<string, (...args: unknown[]) => unknown> = {};
953
+ for (const entry of WebAssembly.Module.exports(module)) {
954
+ if (entry.kind !== 'function') {
955
+ continue;
956
+ }
957
+ const value = instance.exports[entry.name];
958
+ if (typeof value !== 'function') {
959
+ throw new Error(\`Export is not a function: \${entry.name}\`);
960
+ }
961
+ functionExports[entry.name] = value as (...args: unknown[]) => unknown;
962
+ }
963
+
964
+ const initialize =
965
+ typeof instance.exports._initialize === 'function'
966
+ ? (instance.exports._initialize as () => unknown)
967
+ : undefined;
968
+ const start =
969
+ typeof instance.exports._start === 'function'
970
+ ? (instance.exports._start as () => unknown)
971
+ : undefined;
972
+
973
+ return {
974
+ exports: functionExports as TExports,
975
+ allExports: instance.exports as TAllExports,
976
+ memory: resolveMemory(module, instance, options?.imports),
977
+ table: resolveTable(module, instance, options?.imports),
978
+ rawExports: instance.exports,
979
+ module,
980
+ instance,
981
+ initialize,
982
+ start,
983
+ };
984
+ };
985
+
986
+ ${targets.map((target) => {
987
+ const defaultSourceSpecifier = toRelativeImportSpecifier(generatedLoaderFile, target.outFile);
988
+ const specifier = JSON.stringify(defaultSourceSpecifier);
989
+ return `/**
990
+ * Load and instantiate the generated "${target.targetName}" WASM target.
991
+ *
992
+ * @typeParam TExports Function exports exposed through the exports property.
993
+ * @typeParam TAllExports Full WebAssembly export map exposed through the allExports property.
994
+ * @param options Override the target source or WebAssembly imports.
995
+ * @returns The instantiated WASM target and resolved runtime handles.
996
+ * @remarks When options.source is omitted, the loader resolves "${defaultSourceSpecifier}" relative to this file.
997
+ */
998
+ export const ${target.functionName} = async <
999
+ TExports extends object = Record<string, (...args: unknown[]) => unknown>,
1000
+ TAllExports extends WebAssembly.Exports = WebAssembly.Exports>(
1001
+ options?: TargetWasmLoadOptions
1002
+ ): Promise<WasmInstance<TExports, TAllExports>> => {
1003
+ const source = options?.source ?? new URL(${specifier}, import.meta.url);
1004
+ return await loadWasm<TExports, TAllExports>(source, createWasmLoadOptions(options?.imports));
1005
+ };`;
1006
+ }).join("\n\n")}
1007
+ `;
1008
+ };
1009
+ var isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1010
+ var resolvePackageJsonPath = async (startPath, packageName) => {
1011
+ let current = dirname(startPath);
1012
+ for (;;) {
1013
+ const candidate = join(current, "package.json");
1014
+ if (await pathExists(candidate)) return candidate;
1015
+ const parent = dirname(current);
1016
+ if (parent === current) throw new Error(`package.json not found for import: ${packageName}`);
1017
+ current = parent;
1018
+ }
1019
+ };
1020
+ var loadPackageJson = async (packageJsonPath, packageName) => {
1021
+ try {
1022
+ const raw = await readFile(packageJsonPath, "utf8");
1023
+ const parsed = JSON.parse(raw);
1024
+ if (!isRecord(parsed)) throw new Error("package.json must be an object.");
1025
+ return parsed;
1026
+ } catch (error) {
1027
+ const message = error instanceof Error ? error.message : String(error);
1028
+ throw new Error(`Failed to read package.json for import ${packageName}: ${message}`);
1029
+ }
1030
+ };
1031
+ var resolveImportPaths = async (resolver, packageName) => {
1032
+ let resolvedEntry;
1033
+ try {
1034
+ resolvedEntry = resolver.resolve(packageName);
1035
+ } catch (error) {
1036
+ const message = error instanceof Error ? error.message : String(error);
1037
+ throw new Error(`Failed to resolve import ${packageName}: ${message}`);
1038
+ }
1039
+ const packageJsonPath = await resolvePackageJsonPath(resolvedEntry, packageName);
1040
+ const packageRoot = dirname(packageJsonPath);
1041
+ const emsdkConfigRaw = (await loadPackageJson(packageJsonPath, packageName))["emsdk-env"];
1042
+ if (emsdkConfigRaw !== void 0 && !isRecord(emsdkConfigRaw)) throw new Error(`Invalid emsdk-env config for import ${packageName}: expected an object.`);
1043
+ const includeRaw = isRecord(emsdkConfigRaw) ? emsdkConfigRaw.include : void 0;
1044
+ if (includeRaw !== void 0 && typeof includeRaw !== "string") throw new Error(`Invalid emsdk-env include for import ${packageName}: expected a string.`);
1045
+ const libRaw = isRecord(emsdkConfigRaw) ? emsdkConfigRaw.lib : void 0;
1046
+ if (libRaw !== void 0 && typeof libRaw !== "string") throw new Error(`Invalid emsdk-env lib for import ${packageName}: expected a string.`);
1047
+ const includeRel = includeRaw !== null && includeRaw !== void 0 ? includeRaw : DEFAULT_IMPORT_INCLUDE_DIR;
1048
+ const libRel = libRaw !== null && libRaw !== void 0 ? libRaw : DEFAULT_IMPORT_LIB_DIR;
1049
+ const includeDir = resolve(packageRoot, includeRel);
1050
+ const libDir = resolve(packageRoot, libRel);
1051
+ const includeExists = await pathExists(includeDir);
1052
+ const libExists = await pathExists(libDir);
1053
+ if (!includeExists && !libExists) throw new Error(`Import ${packageName} does not provide include or lib directories.`);
1054
+ return {
1055
+ includeDir: includeExists ? includeDir : void 0,
1056
+ libDir: libExists ? libDir : void 0
1057
+ };
1058
+ };
1059
+ var resolveImportDirectories = async (rootDir, imports) => {
1060
+ if (imports.length === 0) return {
1061
+ includeDirs: [],
1062
+ libDirs: []
1063
+ };
1064
+ const resolver = (await import("node:module")).createRequire(resolve(rootDir, "package.json"));
1065
+ const includeDirs = [];
1066
+ const libDirs = [];
1067
+ for (const packageName of imports) {
1068
+ const resolved = await resolveImportPaths(resolver, packageName);
1069
+ if (resolved.includeDir) includeDirs.push(resolved.includeDir);
1070
+ if (resolved.libDir) libDirs.push(resolved.libDir);
1071
+ }
1072
+ return {
1073
+ includeDirs: dedupeValues(includeDirs),
1074
+ libDirs: dedupeValues(libDirs)
1075
+ };
1076
+ };
1077
+ var resolveGeneratedLoaderOutFile = (rootDir, env, generatedLoader) => {
1078
+ var _generatedLoader$outF;
1079
+ if (!(generatedLoader === null || generatedLoader === void 0 ? void 0 : generatedLoader.enable)) return;
1080
+ return resolvePath(rootDir, expandPlaceholders((_generatedLoader$outF = generatedLoader.outFile) !== null && _generatedLoader$outF !== void 0 ? _generatedLoader$outF : DEFAULT_GENERATED_LOADER_OUT_FILE, env, "generatedLoader.outFile"));
1081
+ };
1082
+ var resolveGeneratedLoaderWatchDirs = (rootDir, srcDir, commonIncludeDirs, env, targetEntries, importIncludeDirs) => {
1083
+ const dirs = [srcDir, ...resolveIncludeDirs(commonIncludeDirs, env, rootDir)];
1084
+ for (const [targetName, target] of targetEntries) {
1085
+ if (!target.includeDirs || target.includeDirs.length === 0) continue;
1086
+ const targetEnv = {
1087
+ ...env,
1088
+ TARGET_NAME: targetName
1089
+ };
1090
+ dirs.push(...resolveIncludeDirs(target.includeDirs, targetEnv, rootDir));
1091
+ }
1092
+ dirs.push(...importIncludeDirs);
1093
+ return dedupeValues(dirs);
1094
+ };
1095
+ var validateGeneratedLoaderOutFile = (generatedLoaderFile, watchDirs) => {
1096
+ for (const dir of watchDirs) if (isSubPath(dir, generatedLoaderFile)) throw new Error(`generatedLoader.outFile must not be placed under watched directory: ${generatedLoaderFile}`);
1097
+ };
1098
+ var buildCompileArgs = (options, includeDirs, defines, env, rootDir) => {
1099
+ return {
1100
+ resolvedOptions: expandArray(options, env, "options"),
1101
+ includeArgs: resolveIncludeDirs(includeDirs, env, rootDir).map((dir) => `-I${dir}`),
1102
+ defineArgs: buildDefineFlags(resolveDefines(defines, env))
1103
+ };
1104
+ };
1105
+ /**
1106
+ * Build WASM binaries (and optional archives) from C/C++ sources using emsdk.
1107
+ *
1108
+ * Resolves the SDK via prepareEmsdk, expands build paths, compiles sources,
1109
+ * links targets, and returns output paths keyed by target name.
1110
+ *
1111
+ * @param options - Build options including rule definitions and shared settings.
1112
+ * @returns Build result with the resolved SDK root and output file paths.
1113
+ */
1114
+ var buildWasm = async (options) => {
1115
+ var _options$logger, _options$root, _options$srcDir, _options$includeDir, _options$outDir, _options$libDir, _options$buildDir, _options$cleanupBuild, _options$parallel, _options$rule$common;
1116
+ if (!options) throw new TypeError("options must be provided.");
1117
+ if (!options.rule || !options.rule.targets) throw new TypeError("rule targets must be provided.");
1118
+ const targetEntries = Object.entries(options.rule.targets);
1119
+ if (targetEntries.length === 0) throw new TypeError("rule targets must not be empty.");
1120
+ const logger = (_options$logger = options.logger) !== null && _options$logger !== void 0 ? _options$logger : createConsoleLogger("emsdk-env");
1121
+ const rootDir = resolve((_options$root = options.root) !== null && _options$root !== void 0 ? _options$root : process.cwd());
1122
+ const emsdkOptions = normalizePrepareOptions(options.emsdk);
1123
+ const emsdkRoot = await prepareEmsdk(emsdkOptions);
1124
+ const emsdkEnv = await loadEmsdkEnv(emsdkRoot, logger, emsdkOptions.signal);
1125
+ const baseEnv = {
1126
+ ...emsdkEnv,
1127
+ ROOT: rootDir
1128
+ };
1129
+ const rawSrcDir = expandPlaceholders((_options$srcDir = options.srcDir) !== null && _options$srcDir !== void 0 ? _options$srcDir : DEFAULT_WASM_SRC_DIR, baseEnv, "srcDir");
1130
+ const rawIncludeDir = expandPlaceholders((_options$includeDir = options.includeDir) !== null && _options$includeDir !== void 0 ? _options$includeDir : DEFAULT_WASM_INCLUDE_DIR, baseEnv, "includeDir");
1131
+ const rawOutDir = expandPlaceholders((_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : DEFAULT_WASM_OUT_DIR, baseEnv, "outDir");
1132
+ const rawLibDir = expandPlaceholders((_options$libDir = options.libDir) !== null && _options$libDir !== void 0 ? _options$libDir : DEFAULT_WASM_LIB_DIR, baseEnv, "libDir");
1133
+ const rawBuildDir = expandPlaceholders((_options$buildDir = options.buildDir) !== null && _options$buildDir !== void 0 ? _options$buildDir : DEFAULT_WASM_BUILD_DIR, baseEnv, "buildDir");
1134
+ const srcDir = resolvePath(rootDir, rawSrcDir);
1135
+ const includeDir = resolvePath(rootDir, rawIncludeDir);
1136
+ const outDir = resolvePath(rootDir, rawOutDir);
1137
+ const libDir = resolvePath(rootDir, rawLibDir);
1138
+ const buildDir = resolvePath(rootDir, rawBuildDir);
1139
+ const buildId = createBuildId();
1140
+ const buildRunDir = resolve(buildDir, buildId);
1141
+ const cleanupBuildDir = (_options$cleanupBuild = options.cleanupBuildDir) !== null && _options$cleanupBuild !== void 0 ? _options$cleanupBuild : true;
1142
+ const parallel = (_options$parallel = options.parallel) !== null && _options$parallel !== void 0 ? _options$parallel : true;
1143
+ const envWithDirs = {
1144
+ ...emsdkEnv,
1145
+ ROOT: rootDir,
1146
+ SRC_DIR: srcDir,
1147
+ INCLUDE_DIR: includeDir,
1148
+ OUT_DIR: outDir,
1149
+ LIB_DIR: libDir,
1150
+ BUILD_DIR: buildDir
1151
+ };
1152
+ const emccCommand = await resolveEmccCommand(envWithDirs, emsdkRoot);
1153
+ const common = (_options$rule$common = options.rule.common) !== null && _options$rule$common !== void 0 ? _options$rule$common : {};
1154
+ const commonIncludeDirs = common.includeDirs === void 0 ? [includeDir] : common.includeDirs;
1155
+ const importDirectories = await resolveImportDirectories(rootDir, ensureArray(options.imports));
1156
+ const importIncludeDirs = importDirectories.includeDirs;
1157
+ const importLibDirs = importDirectories.libDirs;
1158
+ const linkLibDirs = dedupeValues([libDir, ...importLibDirs]);
1159
+ const generatedLoaderFile = resolveGeneratedLoaderOutFile(rootDir, envWithDirs, options.generatedLoader);
1160
+ if (generatedLoaderFile) validateGeneratedLoaderOutFile(generatedLoaderFile, resolveGeneratedLoaderWatchDirs(rootDir, srcDir, commonIncludeDirs, envWithDirs, targetEntries, importIncludeDirs));
1161
+ logger.debug(`Detected rootDir: '${rootDir}'`);
1162
+ logger.debug(`Detected srcDir: '${srcDir}'`);
1163
+ logger.debug(`Detected outDir: '${outDir}'`);
1164
+ logger.debug(`Detected libDir: '${libDir}'`);
1165
+ logger.debug(`Detected buildDir: '${buildDir}'`);
1166
+ logger.debug(`Detected buildId: '${buildId}'`);
1167
+ logger.debug(`Detected buildRunDir: '${buildRunDir}'`);
1168
+ logger.debug(`Detected cleanupBuildDir: ${cleanupBuildDir}`);
1169
+ logger.debug(`Detected parallel: ${parallel}`);
1170
+ logger.debug(`Detected emccCommand: '${emccCommand}'`);
1171
+ logger.debug(`Detected importIncludeDirs: [${importIncludeDirs.map((p) => `'${p}'`).join(",")}]`);
1172
+ logger.debug(`Detected importLibDirs: [${importLibDirs.map((p) => `'${p}'`).join(",")}]`);
1173
+ if (generatedLoaderFile) logger.debug(`Detected generatedLoaderFile: '${generatedLoaderFile}'`);
1174
+ await ensureDirectory(outDir);
1175
+ await ensureDirectory(libDir);
1176
+ await ensureDirectory(buildDir);
1177
+ await rm(buildRunDir, {
1178
+ recursive: true,
1179
+ force: true
1180
+ });
1181
+ await ensureDirectory(buildRunDir);
1182
+ const emarCommand = targetEntries.some(([, target]) => resolveTargetType(target.type) === "archive") ? await resolveEmarCommand(envWithDirs, emsdkRoot) : void 0;
1183
+ if (emarCommand) logger.debug(`Detected emarCommand: '${emarCommand}'`);
1184
+ let wasmOptCommand;
1185
+ const getWasmOptCommand = async () => {
1186
+ if (wasmOptCommand) return wasmOptCommand;
1187
+ wasmOptCommand = await resolveWasmOptCommand(envWithDirs, emsdkRoot);
1188
+ logger.debug(`Detected wasmOptCommand: '${wasmOptCommand}'`);
1189
+ return wasmOptCommand;
1190
+ };
1191
+ const outFiles = {};
1192
+ let resultGeneratedLoaderFile;
1193
+ const buildTargets = async (expectedType) => {
1194
+ for (const [targetName, target] of targetEntries) {
1195
+ var _target$sourceGroups;
1196
+ const targetType = resolveTargetType(target.type);
1197
+ if (targetType !== expectedType) continue;
1198
+ if (targetType === "archive") {
1199
+ if (target.linkOptions !== void 0) throw new Error(`linkOptions is not supported for archive target: ${targetName}`);
1200
+ if (target.linkDirectives !== void 0) throw new Error(`linkDirectives is not supported for archive target: ${targetName}`);
1201
+ if (target.exports !== void 0) throw new Error(`exports is not supported for archive target: ${targetName}`);
1202
+ if (target.wasmOpt !== void 0) throw new Error(`wasmOpt is not supported for archive target: ${targetName}`);
1203
+ }
1204
+ const mergedLinkOptions = targetType === "archive" ? [] : [...ensureArray(common.linkOptions), ...ensureArray(target.linkOptions)];
1205
+ const mergedLinkDirectives = targetType === "archive" ? {} : mergeLinkDirectives(common.linkDirectives, target.linkDirectives);
1206
+ const mergedExports = targetType === "archive" ? [] : [...ensureArray(common.exports), ...ensureArray(target.exports)];
1207
+ const wasmOptEnabled = targetType === "archive" ? false : resolveWasmOptEnabled(common.wasmOpt, target.wasmOpt);
1208
+ const baseCompileOptions = [...ensureArray(common.options), ...ensureArray(target.options)];
1209
+ const baseIncludeDirs = [
1210
+ ...ensureArray(commonIncludeDirs),
1211
+ ...ensureArray(target.includeDirs),
1212
+ ...importIncludeDirs
1213
+ ];
1214
+ const baseDefines = mergeDefines(common.defines, target.defines);
1215
+ const sourceGroups = (_target$sourceGroups = target.sourceGroups) !== null && _target$sourceGroups !== void 0 ? _target$sourceGroups : [];
1216
+ const targetEnv = {
1217
+ ...envWithDirs,
1218
+ TARGET_NAME: targetName
1219
+ };
1220
+ const buildEnv = createEnvForBuild(targetEnv, {});
1221
+ const resolvedOutFile = resolveTargetOutFile(targetName, target.outFile, targetEnv, targetType === "archive" ? libDir : outDir, targetType === "archive" ? "a" : "wasm");
1222
+ const sources = await resolveTargetSources(target.sources, targetEnv, srcDir);
1223
+ const groupSources = sourceGroups.map(() => []);
1224
+ const groupSourceSet = /* @__PURE__ */ new Set();
1225
+ for (let index = 0; index < sourceGroups.length; index += 1) {
1226
+ const group = sourceGroups[index];
1227
+ if (!group) continue;
1228
+ const deduped = dedupeSources(await resolveSourcesFromPatterns(group.sources, targetEnv, srcDir, `sourceGroups[${index}].sources`));
1229
+ groupSources[index] = deduped;
1230
+ for (const source of deduped) groupSourceSet.add(source);
1231
+ }
1232
+ const baseSources = sources.filter((source) => !groupSourceSet.has(source));
1233
+ const groupedSources = groupSources.flat();
1234
+ if (baseSources.length + groupedSources.length === 0) throw new Error(`No sources matched for target: ${targetName}`);
1235
+ const targetBuildDir = resolve(buildRunDir, targetName);
1236
+ await rm(targetBuildDir, {
1237
+ recursive: true,
1238
+ force: true
1239
+ });
1240
+ await ensureDirectory(targetBuildDir);
1241
+ const linkDirectiveArgs = buildLinkDirectiveFlags(targetType === "archive" ? {} : resolveLinkDirectives(mergedLinkDirectives, targetEnv));
1242
+ const resolvedLinkOptions = targetType === "archive" ? [] : [...linkDirectiveArgs, ...expandArray(mergedLinkOptions, targetEnv, "linkOptions")];
1243
+ const exportArgs = buildExportFlags(targetType === "archive" ? [] : expandArray(mergedExports, targetEnv, "exports"));
1244
+ const resolvedWasmOptArgs = wasmOptEnabled ? resolveWasmOptArgs(common.wasmOpt, target.wasmOpt, targetEnv) : [];
1245
+ const baseCompileArgs = buildCompileArgs(baseCompileOptions, baseIncludeDirs, baseDefines, targetEnv, rootDir);
1246
+ const groupCompileArgs = sourceGroups.map((group) => {
1247
+ return buildCompileArgs([...baseCompileOptions, ...ensureArray(group === null || group === void 0 ? void 0 : group.options)], [...baseIncludeDirs, ...ensureArray(group === null || group === void 0 ? void 0 : group.includeDirs)], mergeDefines(baseDefines, group === null || group === void 0 ? void 0 : group.defines), targetEnv, rootDir);
1248
+ });
1249
+ const compileSource = async (source, args, groupIndex) => {
1250
+ const objectName = toSafeObjectName(rootDir, source, groupIndex);
1251
+ const outputObject = resolve(targetBuildDir, `${objectName}.o`);
1252
+ const compileArgs = [
1253
+ "-c",
1254
+ source,
1255
+ "-o",
1256
+ outputObject,
1257
+ ...args.resolvedOptions,
1258
+ ...args.includeArgs,
1259
+ ...args.defineArgs
1260
+ ];
1261
+ const sourcePath = relative(rootDir, source);
1262
+ logger.info(`Compiling source: ${sourcePath} --> $tmp/${objectName}.o`);
1263
+ logger.debug(`emcc ${compileArgs.join(" ")}`);
1264
+ await runCommandWithEnv(emccCommand, compileArgs, rootDir, buildEnv, emsdkOptions.signal);
1265
+ return outputObject;
1266
+ };
1267
+ const buildObjectsSequential = async () => {
1268
+ const objectFiles = [];
1269
+ for (const source of baseSources) objectFiles.push(await compileSource(source, baseCompileArgs, void 0));
1270
+ for (let index = 0; index < groupSources.length; index += 1) {
1271
+ const sourcesInGroup = groupSources[index];
1272
+ if (!sourcesInGroup) continue;
1273
+ const groupArgs = groupCompileArgs[index];
1274
+ if (!groupArgs) continue;
1275
+ for (const source of sourcesInGroup) objectFiles.push(await compileSource(source, groupArgs, index));
1276
+ }
1277
+ return objectFiles;
1278
+ };
1279
+ const compileJobs = [];
1280
+ for (const source of baseSources) compileJobs.push({
1281
+ source,
1282
+ args: baseCompileArgs,
1283
+ groupIndex: void 0
1284
+ });
1285
+ for (let index = 0; index < groupSources.length; index += 1) {
1286
+ const sourcesInGroup = groupSources[index];
1287
+ if (!sourcesInGroup) continue;
1288
+ const groupArgs = groupCompileArgs[index];
1289
+ if (!groupArgs) continue;
1290
+ for (const source of sourcesInGroup) compileJobs.push({
1291
+ source,
1292
+ args: groupArgs,
1293
+ groupIndex: index
1294
+ });
1295
+ }
1296
+ logger.info(parallel ? `Building target: '${targetName}' [${compileJobs.length} files, in parallel]` : `Building target: '${targetName}' [${compileJobs.length} files]`);
1297
+ const objectFiles = parallel ? await Promise.all(compileJobs.map((job) => compileSource(job.source, job.args, job.groupIndex))) : await buildObjectsSequential();
1298
+ if (targetType === "archive") {
1299
+ if (!emarCommand) throw new Error("emar command is required for archive targets.");
1300
+ logger.info(`Archiving target: ${targetName}.a`);
1301
+ const archiveArgs = [
1302
+ "rcs",
1303
+ resolvedOutFile,
1304
+ ...objectFiles
1305
+ ];
1306
+ logger.debug(`emar ${archiveArgs.join(" ")}`);
1307
+ await runCommandWithEnv(emarCommand, archiveArgs, rootDir, buildEnv, emsdkOptions.signal);
1308
+ } else {
1309
+ logger.info(`Linking target: ${targetName}.wasm`);
1310
+ const linkArgs = [
1311
+ ...objectFiles,
1312
+ "-o",
1313
+ resolvedOutFile,
1314
+ ...linkLibDirs.map((dir) => `-L${dir}`),
1315
+ ...resolvedLinkOptions,
1316
+ ...exportArgs
1317
+ ];
1318
+ logger.debug(`emcc ${linkArgs.join(" ")}`);
1319
+ await runCommandWithEnv(emccCommand, linkArgs, rootDir, buildEnv, emsdkOptions.signal);
1320
+ if (wasmOptEnabled) {
1321
+ const wasmOptInput = resolveWasmOptInputFile(resolvedOutFile, resolvedLinkOptions);
1322
+ if (!await pathExists(wasmOptInput)) throw new Error(`wasm-opt enabled but wasm binary not found: ${wasmOptInput}`);
1323
+ const tempOutFile = `${wasmOptInput}.opt`;
1324
+ const wasmOptArgs = [
1325
+ wasmOptInput,
1326
+ "-o",
1327
+ tempOutFile,
1328
+ ...resolvedWasmOptArgs
1329
+ ];
1330
+ const wasmOptCommand = await getWasmOptCommand();
1331
+ logger.info(`Optimizing target: ${targetName}.wasm`);
1332
+ logger.debug(`wasm-opt ${wasmOptArgs.join(" ")}`);
1333
+ await runCommandWithEnv(wasmOptCommand, wasmOptArgs, rootDir, buildEnv, emsdkOptions.signal);
1334
+ await rm(wasmOptInput, { force: true });
1335
+ await rename(tempOutFile, wasmOptInput);
1336
+ }
1337
+ }
1338
+ outFiles[targetName] = resolvedOutFile;
1339
+ }
1340
+ };
1341
+ try {
1342
+ await buildTargets("archive");
1343
+ await buildTargets("wasm");
1344
+ if (generatedLoaderFile) {
1345
+ const generatedTargets = [];
1346
+ const functionNames = /* @__PURE__ */ new Set();
1347
+ for (const [targetName, target] of targetEntries) {
1348
+ if (resolveTargetType(target.type) !== "wasm") continue;
1349
+ const outFile = outFiles[targetName];
1350
+ if (!outFile) continue;
1351
+ const functionName = `load${toPascalCaseIdentifier(targetName)}Wasm`;
1352
+ if (functionNames.has(functionName)) throw new Error(`Generated loader function name collision: ${functionName}`);
1353
+ functionNames.add(functionName);
1354
+ generatedTargets.push({
1355
+ targetName,
1356
+ functionName,
1357
+ outFile
1358
+ });
1359
+ }
1360
+ const didWrite = await writeTextIfChanged(generatedLoaderFile, buildGeneratedLoaderContent(generatedLoaderFile, generatedTargets));
1361
+ logger.info(didWrite ? `Generated loader: ${relative(rootDir, generatedLoaderFile)}` : `Generated loader unchanged: ${relative(rootDir, generatedLoaderFile)}`);
1362
+ resultGeneratedLoaderFile = generatedLoaderFile;
1363
+ }
1364
+ } finally {
1365
+ if (cleanupBuildDir) await rm(buildRunDir, {
1366
+ recursive: true,
1367
+ force: true
1368
+ });
1369
+ }
1370
+ return {
1371
+ emsdkRoot,
1372
+ outFiles,
1373
+ ...resultGeneratedLoaderFile ? { generatedLoaderFile: resultGeneratedLoaderFile } : {}
1374
+ };
1375
+ };
1376
+ //#endregion
1377
+ export { createConsoleLogger as n, prepareEmsdk as r, buildWasm as t };
1378
+
1379
+ //# sourceMappingURL=build-BAcPqsVO.js.map