@stll/oxlint-config 1.5.2 → 1.6.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.
- package/README.md +89 -6
- package/dist/dependabot-cli.cjs +3 -1
- package/dist/dependabot-cli.cjs.map +1 -1
- package/dist/dependabot-cli.mjs +4 -2
- package/dist/dependabot-cli.mjs.map +1 -1
- package/dist/dependabot.cjs +2 -0
- package/dist/dependabot.d.cts +17 -2
- package/dist/dependabot.d.mts +17 -2
- package/dist/dependabot.mjs +2 -2
- package/dist/engine-support-cli.cjs +96 -0
- package/dist/engine-support-cli.cjs.map +1 -0
- package/dist/engine-support-cli.d.cts +1 -0
- package/dist/engine-support-cli.d.mts +1 -0
- package/dist/engine-support-cli.mjs +94 -0
- package/dist/engine-support-cli.mjs.map +1 -0
- package/dist/engine-support.cjs +29 -0
- package/dist/engine-support.cjs.map +1 -0
- package/dist/engine-support.d.cts +21 -0
- package/dist/engine-support.d.mts +21 -0
- package/dist/engine-support.mjs +26 -0
- package/dist/engine-support.mjs.map +1 -0
- package/dist/toolchain-dependabot.cjs +119 -13
- package/dist/toolchain-dependabot.cjs.map +1 -1
- package/dist/toolchain-dependabot.mjs +96 -14
- package/dist/toolchain-dependabot.mjs.map +1 -1
- package/dist/toolchain-guard.cjs +16 -4
- package/dist/toolchain-guard.cjs.map +1 -1
- package/dist/toolchain-guard.mjs +17 -5
- package/dist/toolchain-guard.mjs.map +1 -1
- package/dist/wasi-loader-normalizer-cli.cjs +290 -0
- package/dist/wasi-loader-normalizer-cli.cjs.map +1 -0
- package/dist/wasi-loader-normalizer-cli.d.cts +1 -0
- package/dist/wasi-loader-normalizer-cli.d.mts +1 -0
- package/dist/wasi-loader-normalizer-cli.mjs +290 -0
- package/dist/wasi-loader-normalizer-cli.mjs.map +1 -0
- package/package.json +19 -2
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
let node_fs_promises = require("node:fs/promises");
|
|
4
|
+
//#region src/wasi-loader-normalizer.ts
|
|
5
|
+
const GENERATOR_DIRECTIVE = /^\s*(?:\/\/\s*@ts-nocheck\b.*|\/\*\s*(?:eslint-disable(?:\s+[^*]*)?|prettier-ignore)\s*\*\/|\/\/\s*(?:eslint|prettier|biome)-disable\b.*)\r?\n?/gmu;
|
|
6
|
+
const GENERATED_TYPECHECK_OPT_OUT = "// @ts-nocheck -- generated by @napi-rs/cli";
|
|
7
|
+
const ARTIFACT_METADATA_PREFIX = "// napi-rs-artifact-metadata:";
|
|
8
|
+
const GENERATED_WASI_WORKER_FACTORY = `function __createWasiWorker(filename) {
|
|
9
|
+
let __workerExecArgv = __getWasiWorkerExecArgv()
|
|
10
|
+
while (true) {
|
|
11
|
+
try {
|
|
12
|
+
return new Worker(filename, {
|
|
13
|
+
env: process.env,
|
|
14
|
+
execArgv: __workerExecArgv,
|
|
15
|
+
workerData: {
|
|
16
|
+
hostRoot: __hostRoot,
|
|
17
|
+
rootDir: __rootDir,
|
|
18
|
+
crashFlag: __wasiThreadCrashFlag,
|
|
19
|
+
crashReport: __wasiThreadCrashReport,
|
|
20
|
+
addonCrashFlag: __wasiAddonCrashFlag,
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (!error || error.code !== 'ERR_WORKER_INVALID_EXEC_ARGV') {
|
|
25
|
+
throw error
|
|
26
|
+
}
|
|
27
|
+
const __nextWorkerExecArgv =
|
|
28
|
+
__removeInvalidWasiWorkerExecArgv(__workerExecArgv, error)
|
|
29
|
+
if (!__nextWorkerExecArgv) {
|
|
30
|
+
throw error
|
|
31
|
+
}
|
|
32
|
+
__workerExecArgv = __nextWorkerExecArgv
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}`;
|
|
36
|
+
const NORMALIZED_WASI_WORKER_FACTORY = `function __createWasiWorker(filename) {
|
|
37
|
+
const __workerData = {
|
|
38
|
+
hostRoot: __hostRoot,
|
|
39
|
+
rootDir: __rootDir,
|
|
40
|
+
crashFlag: __wasiThreadCrashFlag,
|
|
41
|
+
crashReport: __wasiThreadCrashReport,
|
|
42
|
+
addonCrashFlag: __wasiAddonCrashFlag,
|
|
43
|
+
}
|
|
44
|
+
const __workerOptions = {
|
|
45
|
+
env: process.env,
|
|
46
|
+
execArgv: __getWasiWorkerExecArgv(),
|
|
47
|
+
workerData: __workerData,
|
|
48
|
+
}
|
|
49
|
+
while (true) {
|
|
50
|
+
try {
|
|
51
|
+
return new Worker(filename, __workerOptions)
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (!error || error.code !== 'ERR_WORKER_INVALID_EXEC_ARGV') {
|
|
54
|
+
throw error
|
|
55
|
+
}
|
|
56
|
+
const __nextWorkerExecArgv = __removeInvalidWasiWorkerExecArgv(
|
|
57
|
+
__workerOptions.execArgv,
|
|
58
|
+
error,
|
|
59
|
+
)
|
|
60
|
+
if (!__nextWorkerExecArgv) {
|
|
61
|
+
throw error
|
|
62
|
+
}
|
|
63
|
+
__workerOptions.execArgv = __nextWorkerExecArgv
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}`;
|
|
67
|
+
const GENERATED_BROWSER_WORKER = `const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {
|
|
68
|
+
type: 'module',
|
|
69
|
+
})`;
|
|
70
|
+
const NORMALIZED_BROWSER_WORKER = `const __workerData = {
|
|
71
|
+
addonCrashFlag: __wasiAddonCrashFlag,
|
|
72
|
+
}
|
|
73
|
+
const __workerOptions = {
|
|
74
|
+
type: 'module',
|
|
75
|
+
workerData: __workerData,
|
|
76
|
+
}
|
|
77
|
+
const worker = new Worker(
|
|
78
|
+
new URL('./wasi-worker-browser.mjs', import.meta.url),
|
|
79
|
+
__workerOptions,
|
|
80
|
+
)`;
|
|
81
|
+
const SAFE_SCHEDULER_HELPER = `function __invokeWasmCleanupPollScheduler(schedule, settle, reject) {
|
|
82
|
+
let finishedDuringScheduling = false
|
|
83
|
+
let scheduling = true
|
|
84
|
+
const finish = () => {
|
|
85
|
+
if (scheduling) {
|
|
86
|
+
finishedDuringScheduling = true
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
settle()
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
schedule(finish)
|
|
93
|
+
} catch (error) {
|
|
94
|
+
reject(error)
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
scheduling = false
|
|
98
|
+
if (finishedDuringScheduling) {
|
|
99
|
+
settle()
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
`;
|
|
104
|
+
const RUNTIME_POLL_MARKER = "/**\n * One turn of the runtime-work poll.";
|
|
105
|
+
const UNSAFE_CLEANUP_HANDSHAKE = `await new Promise((resolve) => {
|
|
106
|
+
__scheduleMacrotask(resolve)
|
|
107
|
+
})`;
|
|
108
|
+
const SAFE_CLEANUP_HANDSHAKE = `await new Promise((resolve, reject) => {
|
|
109
|
+
__invokeWasmCleanupPollScheduler(
|
|
110
|
+
__scheduleMacrotask,
|
|
111
|
+
resolve,
|
|
112
|
+
reject,
|
|
113
|
+
)
|
|
114
|
+
})`;
|
|
115
|
+
const UNSAFE_RUNTIME_POLL_PROMISE = `return new Promise((resolve) => {
|
|
116
|
+
let settled = false`;
|
|
117
|
+
const SAFE_RUNTIME_POLL_PROMISE = `return new Promise((resolve, reject) => {
|
|
118
|
+
let settled = false`;
|
|
119
|
+
const UNSAFE_RUNTIME_POLL_TIMER = `__scheduleTimer(() => {
|
|
120
|
+
pace.arrivals++
|
|
121
|
+
settle()
|
|
122
|
+
}, __WASM_RUNTIME_WORK_POLL_INTERVAL_MS)`;
|
|
123
|
+
const SAFE_RUNTIME_POLL_TIMER = `__invokeWasmCleanupPollScheduler(
|
|
124
|
+
(finish) => {
|
|
125
|
+
__scheduleTimer(() => {
|
|
126
|
+
pace.arrivals++
|
|
127
|
+
finish()
|
|
128
|
+
}, __WASM_RUNTIME_WORK_POLL_INTERVAL_MS)
|
|
129
|
+
},
|
|
130
|
+
settle,
|
|
131
|
+
reject,
|
|
132
|
+
)`;
|
|
133
|
+
const UNSAFE_RUNTIME_POLL_MACROTASK = `if (pace.arrivals < __WASM_RUNTIME_WORK_POLL_TRUSTED_ARRIVALS) {
|
|
134
|
+
__scheduleMacrotask(settle)
|
|
135
|
+
return
|
|
136
|
+
}`;
|
|
137
|
+
const SAFE_RUNTIME_POLL_MACROTASK = `if (pace.arrivals < __WASM_RUNTIME_WORK_POLL_TRUSTED_ARRIVALS) {
|
|
138
|
+
__invokeWasmCleanupPollScheduler(
|
|
139
|
+
__scheduleMacrotask,
|
|
140
|
+
settle,
|
|
141
|
+
reject,
|
|
142
|
+
)
|
|
143
|
+
return
|
|
144
|
+
}`;
|
|
145
|
+
const UNSAFE_ASYNC_WORK_POLL = `await new Promise((resolve) => {
|
|
146
|
+
__scheduleTimer(resolve, __WASI_ASYNC_WORK_POLL_INTERVAL_MS)
|
|
147
|
+
})`;
|
|
148
|
+
const SAFE_ASYNC_WORK_POLL = `await new Promise((resolve, reject) => {
|
|
149
|
+
__invokeWasmCleanupPollScheduler(
|
|
150
|
+
(finish) => {
|
|
151
|
+
__scheduleTimer(finish, __WASI_ASYNC_WORK_POLL_INTERVAL_MS)
|
|
152
|
+
},
|
|
153
|
+
resolve,
|
|
154
|
+
reject,
|
|
155
|
+
)
|
|
156
|
+
})`;
|
|
157
|
+
const LOADER_KINDS_BY_SUFFIX = {
|
|
158
|
+
".wasi-browser.js": "browser",
|
|
159
|
+
".wasi.cjs": "commonjs"
|
|
160
|
+
};
|
|
161
|
+
const BOTH_LOADERS = {
|
|
162
|
+
browser: 1,
|
|
163
|
+
commonjs: 1
|
|
164
|
+
};
|
|
165
|
+
const WASI_LOADER_TRANSFORMATIONS = [
|
|
166
|
+
{
|
|
167
|
+
name: "cleanup handshake",
|
|
168
|
+
anchor: UNSAFE_CLEANUP_HANDSHAKE,
|
|
169
|
+
replacement: SAFE_CLEANUP_HANDSHAKE,
|
|
170
|
+
expectedOccurrences: BOTH_LOADERS
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "runtime poll promise",
|
|
174
|
+
anchor: UNSAFE_RUNTIME_POLL_PROMISE,
|
|
175
|
+
replacement: SAFE_RUNTIME_POLL_PROMISE,
|
|
176
|
+
expectedOccurrences: BOTH_LOADERS
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: "runtime poll timer",
|
|
180
|
+
anchor: UNSAFE_RUNTIME_POLL_TIMER,
|
|
181
|
+
replacement: SAFE_RUNTIME_POLL_TIMER,
|
|
182
|
+
expectedOccurrences: BOTH_LOADERS
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "runtime poll macrotask",
|
|
186
|
+
anchor: UNSAFE_RUNTIME_POLL_MACROTASK,
|
|
187
|
+
replacement: SAFE_RUNTIME_POLL_MACROTASK,
|
|
188
|
+
expectedOccurrences: BOTH_LOADERS
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: "async work poll",
|
|
192
|
+
anchor: UNSAFE_ASYNC_WORK_POLL,
|
|
193
|
+
replacement: SAFE_ASYNC_WORK_POLL,
|
|
194
|
+
expectedOccurrences: BOTH_LOADERS
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "worker construction",
|
|
198
|
+
anchor: GENERATED_WASI_WORKER_FACTORY,
|
|
199
|
+
replacement: NORMALIZED_WASI_WORKER_FACTORY,
|
|
200
|
+
expectedOccurrences: {
|
|
201
|
+
browser: 0,
|
|
202
|
+
commonjs: 1
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: "worker construction",
|
|
207
|
+
anchor: GENERATED_BROWSER_WORKER,
|
|
208
|
+
replacement: NORMALIZED_BROWSER_WORKER,
|
|
209
|
+
expectedOccurrences: {
|
|
210
|
+
browser: 1,
|
|
211
|
+
commonjs: 0
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "scheduler helper",
|
|
216
|
+
anchor: RUNTIME_POLL_MARKER,
|
|
217
|
+
replacement: `${SAFE_SCHEDULER_HELPER}${RUNTIME_POLL_MARKER}`,
|
|
218
|
+
expectedOccurrences: BOTH_LOADERS
|
|
219
|
+
}
|
|
220
|
+
];
|
|
221
|
+
const countOccurrences = (source, value) => source.split(value).length - 1;
|
|
222
|
+
const loaderKindFromFile = (file) => {
|
|
223
|
+
if (file.endsWith(".wasi-browser.js")) return "browser";
|
|
224
|
+
if (file.endsWith(".wasi.cjs")) return "commonjs";
|
|
225
|
+
throw new Error(`Unsupported WASI loader file ${file}: expected a name ending in ${Object.keys(LOADER_KINDS_BY_SUFFIX).join(" or ")}`);
|
|
226
|
+
};
|
|
227
|
+
const applyTransformations = (source, file, loaderKind) => {
|
|
228
|
+
let result = source;
|
|
229
|
+
for (const transformation of WASI_LOADER_TRANSFORMATIONS) {
|
|
230
|
+
const expected = transformation.expectedOccurrences[loaderKind];
|
|
231
|
+
const replacementCount = countOccurrences(result, transformation.replacement);
|
|
232
|
+
const anchorsPerReplacement = countOccurrences(transformation.replacement, transformation.anchor);
|
|
233
|
+
const anchorCount = countOccurrences(result, transformation.anchor) - replacementCount * anchorsPerReplacement;
|
|
234
|
+
if (expected === 0 && anchorCount === 0 && replacementCount === 0) continue;
|
|
235
|
+
if (anchorCount === 0 && replacementCount === expected) continue;
|
|
236
|
+
if (anchorCount !== expected || replacementCount !== 0) throw new Error(`WASI loader transformation "${transformation.name}" did not match ${file}: expected ${expected}, found anchors=${anchorCount}, replacements=${replacementCount}`);
|
|
237
|
+
result = result.replaceAll(transformation.anchor, transformation.replacement);
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
};
|
|
241
|
+
const addTypecheckHeader = (source) => {
|
|
242
|
+
if (!source.startsWith(ARTIFACT_METADATA_PREFIX)) return `${GENERATED_TYPECHECK_OPT_OUT}\n${source}`;
|
|
243
|
+
const lineEnd = source.indexOf("\n");
|
|
244
|
+
if (lineEnd < 0) return `${source}\n${GENERATED_TYPECHECK_OPT_OUT}\n`;
|
|
245
|
+
return `${source.slice(0, lineEnd + 1)}${GENERATED_TYPECHECK_OPT_OUT}\n${source.slice(lineEnd + 1)}`;
|
|
246
|
+
};
|
|
247
|
+
/** Preserve generated scheduling and add only targeted safety guards. */
|
|
248
|
+
const normalizeGeneratedLoader = (source, { keepGeneratedTypecheckOptOut = false, file = "<input>" } = {}) => {
|
|
249
|
+
if (source.includes("\r\n")) throw new Error(`WASI loader transformation "LF line endings" did not match ${file}`);
|
|
250
|
+
const withoutDirective = source.replace(GENERATOR_DIRECTIVE, "");
|
|
251
|
+
const normalized = applyTransformations(withoutDirective, file, loaderKindFromFile(file)).replace(/[ \t]+$/gmu, "");
|
|
252
|
+
return keepGeneratedTypecheckOptOut ? addTypecheckHeader(normalized) : normalized;
|
|
253
|
+
};
|
|
254
|
+
const usage = "Usage: stll-normalize-wasi-loaders [--check] <browser-loader> <commonjs-loader>";
|
|
255
|
+
const runWasiLoaderNormalizer = async (args) => {
|
|
256
|
+
const check = args.at(0) === "--check";
|
|
257
|
+
const paths = check ? args.slice(1) : args;
|
|
258
|
+
if (paths.length !== 2 || paths.some((path) => path.startsWith("--"))) throw new Error(usage);
|
|
259
|
+
const loaders = await Promise.all(paths.map(async (path) => {
|
|
260
|
+
const source = await (0, node_fs_promises.readFile)(path, "utf8");
|
|
261
|
+
return {
|
|
262
|
+
normalized: normalizeGeneratedLoader(source, {
|
|
263
|
+
keepGeneratedTypecheckOptOut: true,
|
|
264
|
+
file: path
|
|
265
|
+
}),
|
|
266
|
+
path,
|
|
267
|
+
source
|
|
268
|
+
};
|
|
269
|
+
}));
|
|
270
|
+
let drifted = false;
|
|
271
|
+
for (const { normalized, path, source } of loaders) {
|
|
272
|
+
if (source === normalized) continue;
|
|
273
|
+
if (check) {
|
|
274
|
+
process.stderr.write(`${path} is not normalized\n`);
|
|
275
|
+
drifted = true;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
await (0, node_fs_promises.writeFile)(path, normalized);
|
|
279
|
+
}
|
|
280
|
+
if (drifted) throw new Error("generated WASI loaders have drifted");
|
|
281
|
+
};
|
|
282
|
+
//#endregion
|
|
283
|
+
//#region src/wasi-loader-normalizer-cli.ts
|
|
284
|
+
runWasiLoaderNormalizer(process.argv.slice(2)).catch((error) => {
|
|
285
|
+
process.stderr.write(`wasi-loader-normalizer: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
286
|
+
process.exitCode = 1;
|
|
287
|
+
});
|
|
288
|
+
//#endregion
|
|
289
|
+
|
|
290
|
+
//# sourceMappingURL=wasi-loader-normalizer-cli.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasi-loader-normalizer-cli.cjs","names":["readFile","writeFile"],"sources":["../src/wasi-loader-normalizer.ts","../src/wasi-loader-normalizer-cli.ts"],"sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\n\nconst GENERATOR_DIRECTIVE =\n /^\\s*(?:\\/\\/\\s*@ts-nocheck\\b.*|\\/\\*\\s*(?:eslint-disable(?:\\s+[^*]*)?|prettier-ignore)\\s*\\*\\/|\\/\\/\\s*(?:eslint|prettier|biome)-disable\\b.*)\\r?\\n?/gmu;\n\nconst GENERATED_TYPECHECK_OPT_OUT =\n \"// @ts-nocheck -- generated by @napi-rs/cli\";\nconst ARTIFACT_METADATA_PREFIX = \"// napi-rs-artifact-metadata:\";\nconst GENERATED_WASI_WORKER_FACTORY = `function __createWasiWorker(filename) {\n let __workerExecArgv = __getWasiWorkerExecArgv()\n while (true) {\n try {\n return new Worker(filename, {\n env: process.env,\n execArgv: __workerExecArgv,\n workerData: {\n hostRoot: __hostRoot,\n rootDir: __rootDir,\n crashFlag: __wasiThreadCrashFlag,\n crashReport: __wasiThreadCrashReport,\n addonCrashFlag: __wasiAddonCrashFlag,\n },\n })\n } catch (error) {\n if (!error || error.code !== 'ERR_WORKER_INVALID_EXEC_ARGV') {\n throw error\n }\n const __nextWorkerExecArgv =\n __removeInvalidWasiWorkerExecArgv(__workerExecArgv, error)\n if (!__nextWorkerExecArgv) {\n throw error\n }\n __workerExecArgv = __nextWorkerExecArgv\n }\n }\n}`;\nconst NORMALIZED_WASI_WORKER_FACTORY = `function __createWasiWorker(filename) {\n const __workerData = {\n hostRoot: __hostRoot,\n rootDir: __rootDir,\n crashFlag: __wasiThreadCrashFlag,\n crashReport: __wasiThreadCrashReport,\n addonCrashFlag: __wasiAddonCrashFlag,\n }\n const __workerOptions = {\n env: process.env,\n execArgv: __getWasiWorkerExecArgv(),\n workerData: __workerData,\n }\n while (true) {\n try {\n return new Worker(filename, __workerOptions)\n } catch (error) {\n if (!error || error.code !== 'ERR_WORKER_INVALID_EXEC_ARGV') {\n throw error\n }\n const __nextWorkerExecArgv = __removeInvalidWasiWorkerExecArgv(\n __workerOptions.execArgv,\n error,\n )\n if (!__nextWorkerExecArgv) {\n throw error\n }\n __workerOptions.execArgv = __nextWorkerExecArgv\n }\n }\n}`;\nconst GENERATED_BROWSER_WORKER = `const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {\n type: 'module',\n })`;\n\nconst NORMALIZED_BROWSER_WORKER = `const __workerData = {\n addonCrashFlag: __wasiAddonCrashFlag,\n }\n const __workerOptions = {\n type: 'module',\n workerData: __workerData,\n }\n const worker = new Worker(\n new URL('./wasi-worker-browser.mjs', import.meta.url),\n __workerOptions,\n )`;\nconst SAFE_SCHEDULER_HELPER = `function __invokeWasmCleanupPollScheduler(schedule, settle, reject) {\n let finishedDuringScheduling = false\n let scheduling = true\n const finish = () => {\n if (scheduling) {\n finishedDuringScheduling = true\n return\n }\n settle()\n }\n try {\n schedule(finish)\n } catch (error) {\n reject(error)\n return\n }\n scheduling = false\n if (finishedDuringScheduling) {\n settle()\n }\n}\n\n`;\nconst RUNTIME_POLL_MARKER = \"/**\\n * One turn of the runtime-work poll.\";\nconst UNSAFE_CLEANUP_HANDSHAKE = `await new Promise((resolve) => {\n __scheduleMacrotask(resolve)\n })`;\nconst SAFE_CLEANUP_HANDSHAKE = `await new Promise((resolve, reject) => {\n __invokeWasmCleanupPollScheduler(\n __scheduleMacrotask,\n resolve,\n reject,\n )\n })`;\nconst UNSAFE_RUNTIME_POLL_PROMISE = `return new Promise((resolve) => {\n let settled = false`;\nconst SAFE_RUNTIME_POLL_PROMISE = `return new Promise((resolve, reject) => {\n let settled = false`;\nconst UNSAFE_RUNTIME_POLL_TIMER = `__scheduleTimer(() => {\n pace.arrivals++\n settle()\n }, __WASM_RUNTIME_WORK_POLL_INTERVAL_MS)`;\nconst SAFE_RUNTIME_POLL_TIMER = `__invokeWasmCleanupPollScheduler(\n (finish) => {\n __scheduleTimer(() => {\n pace.arrivals++\n finish()\n }, __WASM_RUNTIME_WORK_POLL_INTERVAL_MS)\n },\n settle,\n reject,\n )`;\nconst UNSAFE_RUNTIME_POLL_MACROTASK = `if (pace.arrivals < __WASM_RUNTIME_WORK_POLL_TRUSTED_ARRIVALS) {\n __scheduleMacrotask(settle)\n return\n }`;\nconst SAFE_RUNTIME_POLL_MACROTASK = `if (pace.arrivals < __WASM_RUNTIME_WORK_POLL_TRUSTED_ARRIVALS) {\n __invokeWasmCleanupPollScheduler(\n __scheduleMacrotask,\n settle,\n reject,\n )\n return\n }`;\nconst UNSAFE_ASYNC_WORK_POLL = `await new Promise((resolve) => {\n __scheduleTimer(resolve, __WASI_ASYNC_WORK_POLL_INTERVAL_MS)\n })`;\nconst SAFE_ASYNC_WORK_POLL = `await new Promise((resolve, reject) => {\n __invokeWasmCleanupPollScheduler(\n (finish) => {\n __scheduleTimer(finish, __WASI_ASYNC_WORK_POLL_INTERVAL_MS)\n },\n resolve,\n reject,\n )\n })`;\ntype Transformation = {\n name: string;\n anchor: string;\n replacement: string;\n expectedOccurrences: Record<LoaderKind, number>;\n};\n\nconst LOADER_KINDS_BY_SUFFIX = {\n \".wasi-browser.js\": \"browser\",\n \".wasi.cjs\": \"commonjs\",\n} as const;\n\ntype LoaderKind = (typeof LOADER_KINDS_BY_SUFFIX)[keyof typeof LOADER_KINDS_BY_SUFFIX];\n\nconst BOTH_LOADERS = { browser: 1, commonjs: 1 } as const;\nconst BROWSER_LOADER = { browser: 1, commonjs: 0 } as const;\nconst COMMONJS_LOADER = { browser: 0, commonjs: 1 } as const;\n\nexport const WASI_LOADER_TRANSFORMATIONS = [\n {\n name: \"cleanup handshake\",\n anchor: UNSAFE_CLEANUP_HANDSHAKE,\n replacement: SAFE_CLEANUP_HANDSHAKE,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"runtime poll promise\",\n anchor: UNSAFE_RUNTIME_POLL_PROMISE,\n replacement: SAFE_RUNTIME_POLL_PROMISE,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"runtime poll timer\",\n anchor: UNSAFE_RUNTIME_POLL_TIMER,\n replacement: SAFE_RUNTIME_POLL_TIMER,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"runtime poll macrotask\",\n anchor: UNSAFE_RUNTIME_POLL_MACROTASK,\n replacement: SAFE_RUNTIME_POLL_MACROTASK,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"async work poll\",\n anchor: UNSAFE_ASYNC_WORK_POLL,\n replacement: SAFE_ASYNC_WORK_POLL,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"worker construction\",\n anchor: GENERATED_WASI_WORKER_FACTORY,\n replacement: NORMALIZED_WASI_WORKER_FACTORY,\n expectedOccurrences: COMMONJS_LOADER,\n },\n {\n name: \"worker construction\",\n anchor: GENERATED_BROWSER_WORKER,\n replacement: NORMALIZED_BROWSER_WORKER,\n expectedOccurrences: BROWSER_LOADER,\n },\n {\n name: \"scheduler helper\",\n anchor: RUNTIME_POLL_MARKER,\n replacement: `${SAFE_SCHEDULER_HELPER}${RUNTIME_POLL_MARKER}`,\n expectedOccurrences: BOTH_LOADERS,\n },\n] satisfies Transformation[];\n\nconst countOccurrences = (source: string, value: string) =>\n source.split(value).length - 1;\n\nconst loaderKindFromFile = (file: string): LoaderKind => {\n if (file.endsWith(\".wasi-browser.js\")) return \"browser\";\n if (file.endsWith(\".wasi.cjs\")) return \"commonjs\";\n throw new Error(\n `Unsupported WASI loader file ${file}: expected a name ending in ${Object.keys(LOADER_KINDS_BY_SUFFIX).join(\" or \")}`,\n );\n};\n\nconst applyTransformations = (\n source: string,\n file: string,\n loaderKind: LoaderKind,\n) => {\n let result = source;\n for (const transformation of WASI_LOADER_TRANSFORMATIONS) {\n const expected = transformation.expectedOccurrences[loaderKind];\n const replacementCount = countOccurrences(\n result,\n transformation.replacement,\n );\n const anchorsPerReplacement = countOccurrences(\n transformation.replacement,\n transformation.anchor,\n );\n const anchorCount =\n countOccurrences(result, transformation.anchor) -\n replacementCount * anchorsPerReplacement;\n\n if (expected === 0 && anchorCount === 0 && replacementCount === 0) continue;\n if (anchorCount === 0 && replacementCount === expected) continue;\n if (anchorCount !== expected || replacementCount !== 0)\n throw new Error(\n `WASI loader transformation \"${transformation.name}\" did not match ${file}: expected ${expected}, found anchors=${anchorCount}, replacements=${replacementCount}`,\n );\n result = result.replaceAll(\n transformation.anchor,\n transformation.replacement,\n );\n }\n return result;\n};\nconst addTypecheckHeader = (source: string) => {\n if (!source.startsWith(ARTIFACT_METADATA_PREFIX)) {\n return `${GENERATED_TYPECHECK_OPT_OUT}\\n${source}`;\n }\n const lineEnd = source.indexOf(\"\\n\");\n if (lineEnd < 0) {\n return `${source}\\n${GENERATED_TYPECHECK_OPT_OUT}\\n`;\n }\n return `${source.slice(0, lineEnd + 1)}${GENERATED_TYPECHECK_OPT_OUT}\\n${source.slice(lineEnd + 1)}`;\n};\n/** Preserve generated scheduling and add only targeted safety guards. */\nexport const normalizeGeneratedLoader = (\n source: string,\n {\n keepGeneratedTypecheckOptOut = false,\n file = \"<input>\",\n }: {\n keepGeneratedTypecheckOptOut?: boolean;\n file?: string;\n } = {},\n) => {\n if (source.includes(\"\\r\\n\"))\n throw new Error(\n `WASI loader transformation \"LF line endings\" did not match ${file}`,\n );\n\n const withoutDirective = source.replace(GENERATOR_DIRECTIVE, \"\");\n const normalized = applyTransformations(\n withoutDirective,\n file,\n loaderKindFromFile(file),\n ).replace(/[ \\t]+$/gmu, \"\");\n\n return keepGeneratedTypecheckOptOut\n ? addTypecheckHeader(normalized)\n : normalized;\n};\n\nconst usage =\n \"Usage: stll-normalize-wasi-loaders [--check] <browser-loader> <commonjs-loader>\";\n\nexport const runWasiLoaderNormalizer = async (args: string[]) => {\n const check = args.at(0) === \"--check\";\n const paths = check ? args.slice(1) : args;\n if (paths.length !== 2 || paths.some((path) => path.startsWith(\"--\")))\n throw new Error(usage);\n\n const loaders = await Promise.all(\n paths.map(async (path) => {\n const source = await readFile(path, \"utf8\");\n const normalized = normalizeGeneratedLoader(source, {\n keepGeneratedTypecheckOptOut: true,\n file: path,\n });\n return { normalized, path, source };\n }),\n );\n\n let drifted = false;\n for (const { normalized, path, source } of loaders) {\n if (source === normalized) continue;\n if (check) {\n process.stderr.write(`${path} is not normalized\\n`);\n drifted = true;\n continue;\n }\n await writeFile(path, normalized);\n }\n if (drifted) throw new Error(\"generated WASI loaders have drifted\");\n};\n","#!/usr/bin/env node\nimport { runWasiLoaderNormalizer } from \"./wasi-loader-normalizer\";\n\nrunWasiLoaderNormalizer(process.argv.slice(2)).catch((error: unknown) => {\n process.stderr.write(\n `wasi-loader-normalizer: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
//#region src/wasi-loader-normalizer.ts
|
|
4
|
+
const GENERATOR_DIRECTIVE = /^\s*(?:\/\/\s*@ts-nocheck\b.*|\/\*\s*(?:eslint-disable(?:\s+[^*]*)?|prettier-ignore)\s*\*\/|\/\/\s*(?:eslint|prettier|biome)-disable\b.*)\r?\n?/gmu;
|
|
5
|
+
const GENERATED_TYPECHECK_OPT_OUT = "// @ts-nocheck -- generated by @napi-rs/cli";
|
|
6
|
+
const ARTIFACT_METADATA_PREFIX = "// napi-rs-artifact-metadata:";
|
|
7
|
+
const GENERATED_WASI_WORKER_FACTORY = `function __createWasiWorker(filename) {
|
|
8
|
+
let __workerExecArgv = __getWasiWorkerExecArgv()
|
|
9
|
+
while (true) {
|
|
10
|
+
try {
|
|
11
|
+
return new Worker(filename, {
|
|
12
|
+
env: process.env,
|
|
13
|
+
execArgv: __workerExecArgv,
|
|
14
|
+
workerData: {
|
|
15
|
+
hostRoot: __hostRoot,
|
|
16
|
+
rootDir: __rootDir,
|
|
17
|
+
crashFlag: __wasiThreadCrashFlag,
|
|
18
|
+
crashReport: __wasiThreadCrashReport,
|
|
19
|
+
addonCrashFlag: __wasiAddonCrashFlag,
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (!error || error.code !== 'ERR_WORKER_INVALID_EXEC_ARGV') {
|
|
24
|
+
throw error
|
|
25
|
+
}
|
|
26
|
+
const __nextWorkerExecArgv =
|
|
27
|
+
__removeInvalidWasiWorkerExecArgv(__workerExecArgv, error)
|
|
28
|
+
if (!__nextWorkerExecArgv) {
|
|
29
|
+
throw error
|
|
30
|
+
}
|
|
31
|
+
__workerExecArgv = __nextWorkerExecArgv
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}`;
|
|
35
|
+
const NORMALIZED_WASI_WORKER_FACTORY = `function __createWasiWorker(filename) {
|
|
36
|
+
const __workerData = {
|
|
37
|
+
hostRoot: __hostRoot,
|
|
38
|
+
rootDir: __rootDir,
|
|
39
|
+
crashFlag: __wasiThreadCrashFlag,
|
|
40
|
+
crashReport: __wasiThreadCrashReport,
|
|
41
|
+
addonCrashFlag: __wasiAddonCrashFlag,
|
|
42
|
+
}
|
|
43
|
+
const __workerOptions = {
|
|
44
|
+
env: process.env,
|
|
45
|
+
execArgv: __getWasiWorkerExecArgv(),
|
|
46
|
+
workerData: __workerData,
|
|
47
|
+
}
|
|
48
|
+
while (true) {
|
|
49
|
+
try {
|
|
50
|
+
return new Worker(filename, __workerOptions)
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (!error || error.code !== 'ERR_WORKER_INVALID_EXEC_ARGV') {
|
|
53
|
+
throw error
|
|
54
|
+
}
|
|
55
|
+
const __nextWorkerExecArgv = __removeInvalidWasiWorkerExecArgv(
|
|
56
|
+
__workerOptions.execArgv,
|
|
57
|
+
error,
|
|
58
|
+
)
|
|
59
|
+
if (!__nextWorkerExecArgv) {
|
|
60
|
+
throw error
|
|
61
|
+
}
|
|
62
|
+
__workerOptions.execArgv = __nextWorkerExecArgv
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}`;
|
|
66
|
+
const GENERATED_BROWSER_WORKER = `const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {
|
|
67
|
+
type: 'module',
|
|
68
|
+
})`;
|
|
69
|
+
const NORMALIZED_BROWSER_WORKER = `const __workerData = {
|
|
70
|
+
addonCrashFlag: __wasiAddonCrashFlag,
|
|
71
|
+
}
|
|
72
|
+
const __workerOptions = {
|
|
73
|
+
type: 'module',
|
|
74
|
+
workerData: __workerData,
|
|
75
|
+
}
|
|
76
|
+
const worker = new Worker(
|
|
77
|
+
new URL('./wasi-worker-browser.mjs', import.meta.url),
|
|
78
|
+
__workerOptions,
|
|
79
|
+
)`;
|
|
80
|
+
const SAFE_SCHEDULER_HELPER = `function __invokeWasmCleanupPollScheduler(schedule, settle, reject) {
|
|
81
|
+
let finishedDuringScheduling = false
|
|
82
|
+
let scheduling = true
|
|
83
|
+
const finish = () => {
|
|
84
|
+
if (scheduling) {
|
|
85
|
+
finishedDuringScheduling = true
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
settle()
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
schedule(finish)
|
|
92
|
+
} catch (error) {
|
|
93
|
+
reject(error)
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
scheduling = false
|
|
97
|
+
if (finishedDuringScheduling) {
|
|
98
|
+
settle()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
`;
|
|
103
|
+
const RUNTIME_POLL_MARKER = "/**\n * One turn of the runtime-work poll.";
|
|
104
|
+
const UNSAFE_CLEANUP_HANDSHAKE = `await new Promise((resolve) => {
|
|
105
|
+
__scheduleMacrotask(resolve)
|
|
106
|
+
})`;
|
|
107
|
+
const SAFE_CLEANUP_HANDSHAKE = `await new Promise((resolve, reject) => {
|
|
108
|
+
__invokeWasmCleanupPollScheduler(
|
|
109
|
+
__scheduleMacrotask,
|
|
110
|
+
resolve,
|
|
111
|
+
reject,
|
|
112
|
+
)
|
|
113
|
+
})`;
|
|
114
|
+
const UNSAFE_RUNTIME_POLL_PROMISE = `return new Promise((resolve) => {
|
|
115
|
+
let settled = false`;
|
|
116
|
+
const SAFE_RUNTIME_POLL_PROMISE = `return new Promise((resolve, reject) => {
|
|
117
|
+
let settled = false`;
|
|
118
|
+
const UNSAFE_RUNTIME_POLL_TIMER = `__scheduleTimer(() => {
|
|
119
|
+
pace.arrivals++
|
|
120
|
+
settle()
|
|
121
|
+
}, __WASM_RUNTIME_WORK_POLL_INTERVAL_MS)`;
|
|
122
|
+
const SAFE_RUNTIME_POLL_TIMER = `__invokeWasmCleanupPollScheduler(
|
|
123
|
+
(finish) => {
|
|
124
|
+
__scheduleTimer(() => {
|
|
125
|
+
pace.arrivals++
|
|
126
|
+
finish()
|
|
127
|
+
}, __WASM_RUNTIME_WORK_POLL_INTERVAL_MS)
|
|
128
|
+
},
|
|
129
|
+
settle,
|
|
130
|
+
reject,
|
|
131
|
+
)`;
|
|
132
|
+
const UNSAFE_RUNTIME_POLL_MACROTASK = `if (pace.arrivals < __WASM_RUNTIME_WORK_POLL_TRUSTED_ARRIVALS) {
|
|
133
|
+
__scheduleMacrotask(settle)
|
|
134
|
+
return
|
|
135
|
+
}`;
|
|
136
|
+
const SAFE_RUNTIME_POLL_MACROTASK = `if (pace.arrivals < __WASM_RUNTIME_WORK_POLL_TRUSTED_ARRIVALS) {
|
|
137
|
+
__invokeWasmCleanupPollScheduler(
|
|
138
|
+
__scheduleMacrotask,
|
|
139
|
+
settle,
|
|
140
|
+
reject,
|
|
141
|
+
)
|
|
142
|
+
return
|
|
143
|
+
}`;
|
|
144
|
+
const UNSAFE_ASYNC_WORK_POLL = `await new Promise((resolve) => {
|
|
145
|
+
__scheduleTimer(resolve, __WASI_ASYNC_WORK_POLL_INTERVAL_MS)
|
|
146
|
+
})`;
|
|
147
|
+
const SAFE_ASYNC_WORK_POLL = `await new Promise((resolve, reject) => {
|
|
148
|
+
__invokeWasmCleanupPollScheduler(
|
|
149
|
+
(finish) => {
|
|
150
|
+
__scheduleTimer(finish, __WASI_ASYNC_WORK_POLL_INTERVAL_MS)
|
|
151
|
+
},
|
|
152
|
+
resolve,
|
|
153
|
+
reject,
|
|
154
|
+
)
|
|
155
|
+
})`;
|
|
156
|
+
const LOADER_KINDS_BY_SUFFIX = {
|
|
157
|
+
".wasi-browser.js": "browser",
|
|
158
|
+
".wasi.cjs": "commonjs"
|
|
159
|
+
};
|
|
160
|
+
const BOTH_LOADERS = {
|
|
161
|
+
browser: 1,
|
|
162
|
+
commonjs: 1
|
|
163
|
+
};
|
|
164
|
+
const WASI_LOADER_TRANSFORMATIONS = [
|
|
165
|
+
{
|
|
166
|
+
name: "cleanup handshake",
|
|
167
|
+
anchor: UNSAFE_CLEANUP_HANDSHAKE,
|
|
168
|
+
replacement: SAFE_CLEANUP_HANDSHAKE,
|
|
169
|
+
expectedOccurrences: BOTH_LOADERS
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "runtime poll promise",
|
|
173
|
+
anchor: UNSAFE_RUNTIME_POLL_PROMISE,
|
|
174
|
+
replacement: SAFE_RUNTIME_POLL_PROMISE,
|
|
175
|
+
expectedOccurrences: BOTH_LOADERS
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "runtime poll timer",
|
|
179
|
+
anchor: UNSAFE_RUNTIME_POLL_TIMER,
|
|
180
|
+
replacement: SAFE_RUNTIME_POLL_TIMER,
|
|
181
|
+
expectedOccurrences: BOTH_LOADERS
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: "runtime poll macrotask",
|
|
185
|
+
anchor: UNSAFE_RUNTIME_POLL_MACROTASK,
|
|
186
|
+
replacement: SAFE_RUNTIME_POLL_MACROTASK,
|
|
187
|
+
expectedOccurrences: BOTH_LOADERS
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: "async work poll",
|
|
191
|
+
anchor: UNSAFE_ASYNC_WORK_POLL,
|
|
192
|
+
replacement: SAFE_ASYNC_WORK_POLL,
|
|
193
|
+
expectedOccurrences: BOTH_LOADERS
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: "worker construction",
|
|
197
|
+
anchor: GENERATED_WASI_WORKER_FACTORY,
|
|
198
|
+
replacement: NORMALIZED_WASI_WORKER_FACTORY,
|
|
199
|
+
expectedOccurrences: {
|
|
200
|
+
browser: 0,
|
|
201
|
+
commonjs: 1
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: "worker construction",
|
|
206
|
+
anchor: GENERATED_BROWSER_WORKER,
|
|
207
|
+
replacement: NORMALIZED_BROWSER_WORKER,
|
|
208
|
+
expectedOccurrences: {
|
|
209
|
+
browser: 1,
|
|
210
|
+
commonjs: 0
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
name: "scheduler helper",
|
|
215
|
+
anchor: RUNTIME_POLL_MARKER,
|
|
216
|
+
replacement: `${SAFE_SCHEDULER_HELPER}${RUNTIME_POLL_MARKER}`,
|
|
217
|
+
expectedOccurrences: BOTH_LOADERS
|
|
218
|
+
}
|
|
219
|
+
];
|
|
220
|
+
const countOccurrences = (source, value) => source.split(value).length - 1;
|
|
221
|
+
const loaderKindFromFile = (file) => {
|
|
222
|
+
if (file.endsWith(".wasi-browser.js")) return "browser";
|
|
223
|
+
if (file.endsWith(".wasi.cjs")) return "commonjs";
|
|
224
|
+
throw new Error(`Unsupported WASI loader file ${file}: expected a name ending in ${Object.keys(LOADER_KINDS_BY_SUFFIX).join(" or ")}`);
|
|
225
|
+
};
|
|
226
|
+
const applyTransformations = (source, file, loaderKind) => {
|
|
227
|
+
let result = source;
|
|
228
|
+
for (const transformation of WASI_LOADER_TRANSFORMATIONS) {
|
|
229
|
+
const expected = transformation.expectedOccurrences[loaderKind];
|
|
230
|
+
const replacementCount = countOccurrences(result, transformation.replacement);
|
|
231
|
+
const anchorsPerReplacement = countOccurrences(transformation.replacement, transformation.anchor);
|
|
232
|
+
const anchorCount = countOccurrences(result, transformation.anchor) - replacementCount * anchorsPerReplacement;
|
|
233
|
+
if (expected === 0 && anchorCount === 0 && replacementCount === 0) continue;
|
|
234
|
+
if (anchorCount === 0 && replacementCount === expected) continue;
|
|
235
|
+
if (anchorCount !== expected || replacementCount !== 0) throw new Error(`WASI loader transformation "${transformation.name}" did not match ${file}: expected ${expected}, found anchors=${anchorCount}, replacements=${replacementCount}`);
|
|
236
|
+
result = result.replaceAll(transformation.anchor, transformation.replacement);
|
|
237
|
+
}
|
|
238
|
+
return result;
|
|
239
|
+
};
|
|
240
|
+
const addTypecheckHeader = (source) => {
|
|
241
|
+
if (!source.startsWith(ARTIFACT_METADATA_PREFIX)) return `${GENERATED_TYPECHECK_OPT_OUT}\n${source}`;
|
|
242
|
+
const lineEnd = source.indexOf("\n");
|
|
243
|
+
if (lineEnd < 0) return `${source}\n${GENERATED_TYPECHECK_OPT_OUT}\n`;
|
|
244
|
+
return `${source.slice(0, lineEnd + 1)}${GENERATED_TYPECHECK_OPT_OUT}\n${source.slice(lineEnd + 1)}`;
|
|
245
|
+
};
|
|
246
|
+
/** Preserve generated scheduling and add only targeted safety guards. */
|
|
247
|
+
const normalizeGeneratedLoader = (source, { keepGeneratedTypecheckOptOut = false, file = "<input>" } = {}) => {
|
|
248
|
+
if (source.includes("\r\n")) throw new Error(`WASI loader transformation "LF line endings" did not match ${file}`);
|
|
249
|
+
const withoutDirective = source.replace(GENERATOR_DIRECTIVE, "");
|
|
250
|
+
const normalized = applyTransformations(withoutDirective, file, loaderKindFromFile(file)).replace(/[ \t]+$/gmu, "");
|
|
251
|
+
return keepGeneratedTypecheckOptOut ? addTypecheckHeader(normalized) : normalized;
|
|
252
|
+
};
|
|
253
|
+
const usage = "Usage: stll-normalize-wasi-loaders [--check] <browser-loader> <commonjs-loader>";
|
|
254
|
+
const runWasiLoaderNormalizer = async (args) => {
|
|
255
|
+
const check = args.at(0) === "--check";
|
|
256
|
+
const paths = check ? args.slice(1) : args;
|
|
257
|
+
if (paths.length !== 2 || paths.some((path) => path.startsWith("--"))) throw new Error(usage);
|
|
258
|
+
const loaders = await Promise.all(paths.map(async (path) => {
|
|
259
|
+
const source = await readFile(path, "utf8");
|
|
260
|
+
return {
|
|
261
|
+
normalized: normalizeGeneratedLoader(source, {
|
|
262
|
+
keepGeneratedTypecheckOptOut: true,
|
|
263
|
+
file: path
|
|
264
|
+
}),
|
|
265
|
+
path,
|
|
266
|
+
source
|
|
267
|
+
};
|
|
268
|
+
}));
|
|
269
|
+
let drifted = false;
|
|
270
|
+
for (const { normalized, path, source } of loaders) {
|
|
271
|
+
if (source === normalized) continue;
|
|
272
|
+
if (check) {
|
|
273
|
+
process.stderr.write(`${path} is not normalized\n`);
|
|
274
|
+
drifted = true;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
await writeFile(path, normalized);
|
|
278
|
+
}
|
|
279
|
+
if (drifted) throw new Error("generated WASI loaders have drifted");
|
|
280
|
+
};
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/wasi-loader-normalizer-cli.ts
|
|
283
|
+
runWasiLoaderNormalizer(process.argv.slice(2)).catch((error) => {
|
|
284
|
+
process.stderr.write(`wasi-loader-normalizer: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
285
|
+
process.exitCode = 1;
|
|
286
|
+
});
|
|
287
|
+
//#endregion
|
|
288
|
+
export {};
|
|
289
|
+
|
|
290
|
+
//# sourceMappingURL=wasi-loader-normalizer-cli.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasi-loader-normalizer-cli.mjs","names":[],"sources":["../src/wasi-loader-normalizer.ts","../src/wasi-loader-normalizer-cli.ts"],"sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\n\nconst GENERATOR_DIRECTIVE =\n /^\\s*(?:\\/\\/\\s*@ts-nocheck\\b.*|\\/\\*\\s*(?:eslint-disable(?:\\s+[^*]*)?|prettier-ignore)\\s*\\*\\/|\\/\\/\\s*(?:eslint|prettier|biome)-disable\\b.*)\\r?\\n?/gmu;\n\nconst GENERATED_TYPECHECK_OPT_OUT =\n \"// @ts-nocheck -- generated by @napi-rs/cli\";\nconst ARTIFACT_METADATA_PREFIX = \"// napi-rs-artifact-metadata:\";\nconst GENERATED_WASI_WORKER_FACTORY = `function __createWasiWorker(filename) {\n let __workerExecArgv = __getWasiWorkerExecArgv()\n while (true) {\n try {\n return new Worker(filename, {\n env: process.env,\n execArgv: __workerExecArgv,\n workerData: {\n hostRoot: __hostRoot,\n rootDir: __rootDir,\n crashFlag: __wasiThreadCrashFlag,\n crashReport: __wasiThreadCrashReport,\n addonCrashFlag: __wasiAddonCrashFlag,\n },\n })\n } catch (error) {\n if (!error || error.code !== 'ERR_WORKER_INVALID_EXEC_ARGV') {\n throw error\n }\n const __nextWorkerExecArgv =\n __removeInvalidWasiWorkerExecArgv(__workerExecArgv, error)\n if (!__nextWorkerExecArgv) {\n throw error\n }\n __workerExecArgv = __nextWorkerExecArgv\n }\n }\n}`;\nconst NORMALIZED_WASI_WORKER_FACTORY = `function __createWasiWorker(filename) {\n const __workerData = {\n hostRoot: __hostRoot,\n rootDir: __rootDir,\n crashFlag: __wasiThreadCrashFlag,\n crashReport: __wasiThreadCrashReport,\n addonCrashFlag: __wasiAddonCrashFlag,\n }\n const __workerOptions = {\n env: process.env,\n execArgv: __getWasiWorkerExecArgv(),\n workerData: __workerData,\n }\n while (true) {\n try {\n return new Worker(filename, __workerOptions)\n } catch (error) {\n if (!error || error.code !== 'ERR_WORKER_INVALID_EXEC_ARGV') {\n throw error\n }\n const __nextWorkerExecArgv = __removeInvalidWasiWorkerExecArgv(\n __workerOptions.execArgv,\n error,\n )\n if (!__nextWorkerExecArgv) {\n throw error\n }\n __workerOptions.execArgv = __nextWorkerExecArgv\n }\n }\n}`;\nconst GENERATED_BROWSER_WORKER = `const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {\n type: 'module',\n })`;\n\nconst NORMALIZED_BROWSER_WORKER = `const __workerData = {\n addonCrashFlag: __wasiAddonCrashFlag,\n }\n const __workerOptions = {\n type: 'module',\n workerData: __workerData,\n }\n const worker = new Worker(\n new URL('./wasi-worker-browser.mjs', import.meta.url),\n __workerOptions,\n )`;\nconst SAFE_SCHEDULER_HELPER = `function __invokeWasmCleanupPollScheduler(schedule, settle, reject) {\n let finishedDuringScheduling = false\n let scheduling = true\n const finish = () => {\n if (scheduling) {\n finishedDuringScheduling = true\n return\n }\n settle()\n }\n try {\n schedule(finish)\n } catch (error) {\n reject(error)\n return\n }\n scheduling = false\n if (finishedDuringScheduling) {\n settle()\n }\n}\n\n`;\nconst RUNTIME_POLL_MARKER = \"/**\\n * One turn of the runtime-work poll.\";\nconst UNSAFE_CLEANUP_HANDSHAKE = `await new Promise((resolve) => {\n __scheduleMacrotask(resolve)\n })`;\nconst SAFE_CLEANUP_HANDSHAKE = `await new Promise((resolve, reject) => {\n __invokeWasmCleanupPollScheduler(\n __scheduleMacrotask,\n resolve,\n reject,\n )\n })`;\nconst UNSAFE_RUNTIME_POLL_PROMISE = `return new Promise((resolve) => {\n let settled = false`;\nconst SAFE_RUNTIME_POLL_PROMISE = `return new Promise((resolve, reject) => {\n let settled = false`;\nconst UNSAFE_RUNTIME_POLL_TIMER = `__scheduleTimer(() => {\n pace.arrivals++\n settle()\n }, __WASM_RUNTIME_WORK_POLL_INTERVAL_MS)`;\nconst SAFE_RUNTIME_POLL_TIMER = `__invokeWasmCleanupPollScheduler(\n (finish) => {\n __scheduleTimer(() => {\n pace.arrivals++\n finish()\n }, __WASM_RUNTIME_WORK_POLL_INTERVAL_MS)\n },\n settle,\n reject,\n )`;\nconst UNSAFE_RUNTIME_POLL_MACROTASK = `if (pace.arrivals < __WASM_RUNTIME_WORK_POLL_TRUSTED_ARRIVALS) {\n __scheduleMacrotask(settle)\n return\n }`;\nconst SAFE_RUNTIME_POLL_MACROTASK = `if (pace.arrivals < __WASM_RUNTIME_WORK_POLL_TRUSTED_ARRIVALS) {\n __invokeWasmCleanupPollScheduler(\n __scheduleMacrotask,\n settle,\n reject,\n )\n return\n }`;\nconst UNSAFE_ASYNC_WORK_POLL = `await new Promise((resolve) => {\n __scheduleTimer(resolve, __WASI_ASYNC_WORK_POLL_INTERVAL_MS)\n })`;\nconst SAFE_ASYNC_WORK_POLL = `await new Promise((resolve, reject) => {\n __invokeWasmCleanupPollScheduler(\n (finish) => {\n __scheduleTimer(finish, __WASI_ASYNC_WORK_POLL_INTERVAL_MS)\n },\n resolve,\n reject,\n )\n })`;\ntype Transformation = {\n name: string;\n anchor: string;\n replacement: string;\n expectedOccurrences: Record<LoaderKind, number>;\n};\n\nconst LOADER_KINDS_BY_SUFFIX = {\n \".wasi-browser.js\": \"browser\",\n \".wasi.cjs\": \"commonjs\",\n} as const;\n\ntype LoaderKind = (typeof LOADER_KINDS_BY_SUFFIX)[keyof typeof LOADER_KINDS_BY_SUFFIX];\n\nconst BOTH_LOADERS = { browser: 1, commonjs: 1 } as const;\nconst BROWSER_LOADER = { browser: 1, commonjs: 0 } as const;\nconst COMMONJS_LOADER = { browser: 0, commonjs: 1 } as const;\n\nexport const WASI_LOADER_TRANSFORMATIONS = [\n {\n name: \"cleanup handshake\",\n anchor: UNSAFE_CLEANUP_HANDSHAKE,\n replacement: SAFE_CLEANUP_HANDSHAKE,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"runtime poll promise\",\n anchor: UNSAFE_RUNTIME_POLL_PROMISE,\n replacement: SAFE_RUNTIME_POLL_PROMISE,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"runtime poll timer\",\n anchor: UNSAFE_RUNTIME_POLL_TIMER,\n replacement: SAFE_RUNTIME_POLL_TIMER,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"runtime poll macrotask\",\n anchor: UNSAFE_RUNTIME_POLL_MACROTASK,\n replacement: SAFE_RUNTIME_POLL_MACROTASK,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"async work poll\",\n anchor: UNSAFE_ASYNC_WORK_POLL,\n replacement: SAFE_ASYNC_WORK_POLL,\n expectedOccurrences: BOTH_LOADERS,\n },\n {\n name: \"worker construction\",\n anchor: GENERATED_WASI_WORKER_FACTORY,\n replacement: NORMALIZED_WASI_WORKER_FACTORY,\n expectedOccurrences: COMMONJS_LOADER,\n },\n {\n name: \"worker construction\",\n anchor: GENERATED_BROWSER_WORKER,\n replacement: NORMALIZED_BROWSER_WORKER,\n expectedOccurrences: BROWSER_LOADER,\n },\n {\n name: \"scheduler helper\",\n anchor: RUNTIME_POLL_MARKER,\n replacement: `${SAFE_SCHEDULER_HELPER}${RUNTIME_POLL_MARKER}`,\n expectedOccurrences: BOTH_LOADERS,\n },\n] satisfies Transformation[];\n\nconst countOccurrences = (source: string, value: string) =>\n source.split(value).length - 1;\n\nconst loaderKindFromFile = (file: string): LoaderKind => {\n if (file.endsWith(\".wasi-browser.js\")) return \"browser\";\n if (file.endsWith(\".wasi.cjs\")) return \"commonjs\";\n throw new Error(\n `Unsupported WASI loader file ${file}: expected a name ending in ${Object.keys(LOADER_KINDS_BY_SUFFIX).join(\" or \")}`,\n );\n};\n\nconst applyTransformations = (\n source: string,\n file: string,\n loaderKind: LoaderKind,\n) => {\n let result = source;\n for (const transformation of WASI_LOADER_TRANSFORMATIONS) {\n const expected = transformation.expectedOccurrences[loaderKind];\n const replacementCount = countOccurrences(\n result,\n transformation.replacement,\n );\n const anchorsPerReplacement = countOccurrences(\n transformation.replacement,\n transformation.anchor,\n );\n const anchorCount =\n countOccurrences(result, transformation.anchor) -\n replacementCount * anchorsPerReplacement;\n\n if (expected === 0 && anchorCount === 0 && replacementCount === 0) continue;\n if (anchorCount === 0 && replacementCount === expected) continue;\n if (anchorCount !== expected || replacementCount !== 0)\n throw new Error(\n `WASI loader transformation \"${transformation.name}\" did not match ${file}: expected ${expected}, found anchors=${anchorCount}, replacements=${replacementCount}`,\n );\n result = result.replaceAll(\n transformation.anchor,\n transformation.replacement,\n );\n }\n return result;\n};\nconst addTypecheckHeader = (source: string) => {\n if (!source.startsWith(ARTIFACT_METADATA_PREFIX)) {\n return `${GENERATED_TYPECHECK_OPT_OUT}\\n${source}`;\n }\n const lineEnd = source.indexOf(\"\\n\");\n if (lineEnd < 0) {\n return `${source}\\n${GENERATED_TYPECHECK_OPT_OUT}\\n`;\n }\n return `${source.slice(0, lineEnd + 1)}${GENERATED_TYPECHECK_OPT_OUT}\\n${source.slice(lineEnd + 1)}`;\n};\n/** Preserve generated scheduling and add only targeted safety guards. */\nexport const normalizeGeneratedLoader = (\n source: string,\n {\n keepGeneratedTypecheckOptOut = false,\n file = \"<input>\",\n }: {\n keepGeneratedTypecheckOptOut?: boolean;\n file?: string;\n } = {},\n) => {\n if (source.includes(\"\\r\\n\"))\n throw new Error(\n `WASI loader transformation \"LF line endings\" did not match ${file}`,\n );\n\n const withoutDirective = source.replace(GENERATOR_DIRECTIVE, \"\");\n const normalized = applyTransformations(\n withoutDirective,\n file,\n loaderKindFromFile(file),\n ).replace(/[ \\t]+$/gmu, \"\");\n\n return keepGeneratedTypecheckOptOut\n ? addTypecheckHeader(normalized)\n : normalized;\n};\n\nconst usage =\n \"Usage: stll-normalize-wasi-loaders [--check] <browser-loader> <commonjs-loader>\";\n\nexport const runWasiLoaderNormalizer = async (args: string[]) => {\n const check = args.at(0) === \"--check\";\n const paths = check ? args.slice(1) : args;\n if (paths.length !== 2 || paths.some((path) => path.startsWith(\"--\")))\n throw new Error(usage);\n\n const loaders = await Promise.all(\n paths.map(async (path) => {\n const source = await readFile(path, \"utf8\");\n const normalized = normalizeGeneratedLoader(source, {\n keepGeneratedTypecheckOptOut: true,\n file: path,\n });\n return { normalized, path, source };\n }),\n );\n\n let drifted = false;\n for (const { normalized, path, source } of loaders) {\n if (source === normalized) continue;\n if (check) {\n process.stderr.write(`${path} is not normalized\\n`);\n drifted = true;\n continue;\n }\n await writeFile(path, normalized);\n }\n if (drifted) throw new Error(\"generated WASI loaders have drifted\");\n};\n","#!/usr/bin/env node\nimport { runWasiLoaderNormalizer } from \"./wasi-loader-normalizer\";\n\nrunWasiLoaderNormalizer(process.argv.slice(2)).catch((error: unknown) => {\n process.stderr.write(\n `wasi-loader-normalizer: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
|