webmystran-wasm 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/PATCHING.md +358 -0
- package/README.md +177 -0
- package/SOURCES.md +48 -0
- package/THIRD_PARTY_NOTICES.md +22 -0
- package/dist/mystran.js +14 -0
- package/dist/mystran.wasm +0 -0
- package/index.js +3 -0
- package/package.json +54 -0
- package/scripts/build.ps1 +19 -0
- package/scripts/fetch_deps.ps1 +157 -0
- package/scripts/smoke_test.ps1 +19 -0
- package/src/mystran_input.js +117 -0
- package/src/output_parser.js +57 -0
- package/src/web_mystran.js +247 -0
- package/tools/build.js +4840 -0
- package/tools/smoke_test.js +978 -0
- package/tools/wasm_runner.js +349 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
function isNode() {
|
|
4
|
+
return (
|
|
5
|
+
typeof process !== "undefined" &&
|
|
6
|
+
process.versions &&
|
|
7
|
+
process.versions.node
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function toPosixPath(value) {
|
|
12
|
+
return String(value).replace(/\\/g, "/");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function joinPath(base, rel) {
|
|
16
|
+
const b = toPosixPath(base || "");
|
|
17
|
+
const r = toPosixPath(rel || "");
|
|
18
|
+
if (!b) return r;
|
|
19
|
+
if (!r) return b;
|
|
20
|
+
if (r.startsWith("/")) return r;
|
|
21
|
+
return `${b.replace(/\/$/, "")}/${r}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function dirname(pathValue) {
|
|
25
|
+
const normalized = toPosixPath(pathValue || "");
|
|
26
|
+
const idx = normalized.lastIndexOf("/");
|
|
27
|
+
if (idx <= 0) return "/";
|
|
28
|
+
return normalized.slice(0, idx);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ensureDir(fs, dirPath) {
|
|
32
|
+
const normalized = toPosixPath(dirPath || "");
|
|
33
|
+
if (!normalized || normalized === "/") return;
|
|
34
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
35
|
+
let current = "";
|
|
36
|
+
for (const part of parts) {
|
|
37
|
+
current += `/${part}`;
|
|
38
|
+
if (!fs.analyzePath(current).exists) {
|
|
39
|
+
fs.mkdir(current);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function toBytes(data) {
|
|
45
|
+
if (data == null) return new Uint8Array(0);
|
|
46
|
+
if (typeof data === "string") {
|
|
47
|
+
if (typeof TextEncoder !== "undefined") {
|
|
48
|
+
return new TextEncoder().encode(data);
|
|
49
|
+
}
|
|
50
|
+
if (typeof Buffer !== "undefined") {
|
|
51
|
+
return Uint8Array.from(Buffer.from(data, "utf8"));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (data instanceof Uint8Array) return data;
|
|
55
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
|
|
56
|
+
return new Uint8Array(data);
|
|
57
|
+
}
|
|
58
|
+
if (ArrayBuffer.isView(data)) {
|
|
59
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
60
|
+
}
|
|
61
|
+
if (data instanceof ArrayBuffer) {
|
|
62
|
+
return new Uint8Array(data);
|
|
63
|
+
}
|
|
64
|
+
throw new Error("Unsupported input type for bytes.");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function fromBytes(data, encoding) {
|
|
68
|
+
if (!encoding) return data;
|
|
69
|
+
const enc = encoding === "utf8" ? "utf-8" : encoding;
|
|
70
|
+
if (typeof TextDecoder !== "undefined") {
|
|
71
|
+
return new TextDecoder(enc).decode(data);
|
|
72
|
+
}
|
|
73
|
+
if (typeof Buffer !== "undefined") {
|
|
74
|
+
return Buffer.from(data).toString(encoding);
|
|
75
|
+
}
|
|
76
|
+
throw new Error("TextDecoder not available.");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeLineBreaks(text) {
|
|
80
|
+
return String(text).replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function createLineBuffer(state, key, onLine) {
|
|
84
|
+
const bufferKey = `${key}Buffer`;
|
|
85
|
+
state[bufferKey] = "";
|
|
86
|
+
|
|
87
|
+
const pushLine = (line) => {
|
|
88
|
+
state[key].push(line);
|
|
89
|
+
if (onLine) onLine(line);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
write(text) {
|
|
94
|
+
const normalized = normalizeLineBreaks(text);
|
|
95
|
+
if (!normalized && !state[bufferKey]) return;
|
|
96
|
+
if (!state[bufferKey] && !normalized.includes("\n")) {
|
|
97
|
+
pushLine(normalized);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const combined = `${state[bufferKey]}${normalized}`;
|
|
101
|
+
const parts = combined.split("\n");
|
|
102
|
+
const endsWithNewline = combined.endsWith("\n");
|
|
103
|
+
const lineCount = endsWithNewline ? parts.length : Math.max(0, parts.length - 1);
|
|
104
|
+
for (let i = 0; i < lineCount; i += 1) {
|
|
105
|
+
pushLine(parts[i]);
|
|
106
|
+
}
|
|
107
|
+
state[bufferKey] = endsWithNewline ? "" : parts[parts.length - 1];
|
|
108
|
+
},
|
|
109
|
+
flush() {
|
|
110
|
+
if (!state[bufferKey]) return;
|
|
111
|
+
pushLine(state[bufferKey]);
|
|
112
|
+
state[bufferKey] = "";
|
|
113
|
+
},
|
|
114
|
+
reset() {
|
|
115
|
+
state[bufferKey] = "";
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function callMain(module, args) {
|
|
121
|
+
let exitCode = 0;
|
|
122
|
+
try {
|
|
123
|
+
module.callMain(args);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
if (err && err.name === "ExitStatus") {
|
|
126
|
+
exitCode = err.status || 0;
|
|
127
|
+
} else {
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return exitCode;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function linesToText(lines) {
|
|
135
|
+
if (!lines.length) return "";
|
|
136
|
+
return lines.join("\n");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function toUrl(value, baseUrl) {
|
|
140
|
+
if (!value) return null;
|
|
141
|
+
if (value instanceof URL) return value;
|
|
142
|
+
try {
|
|
143
|
+
return new URL(value);
|
|
144
|
+
} catch {
|
|
145
|
+
return new URL(value, baseUrl);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function resolveModuleFactory(artifactBase, options) {
|
|
150
|
+
const moduleUrl =
|
|
151
|
+
toUrl(options.moduleUrl, import.meta.url) ||
|
|
152
|
+
new URL(`../dist/${artifactBase}.js`, import.meta.url);
|
|
153
|
+
let moduleFactory = options.moduleFactory;
|
|
154
|
+
|
|
155
|
+
if (!moduleFactory) {
|
|
156
|
+
const mod = await import(moduleUrl.href);
|
|
157
|
+
moduleFactory = mod.default || (options.exportName ? mod[options.exportName] : undefined);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (typeof moduleFactory !== "function") {
|
|
161
|
+
throw new Error(`Module factory not available for ${artifactBase}.`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return { moduleFactory, moduleUrl };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
class WasmRunner {
|
|
168
|
+
constructor(module, state, options = {}) {
|
|
169
|
+
this._module = module;
|
|
170
|
+
this._state = state;
|
|
171
|
+
this._workDir = options.workDir || "/work";
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static async load(artifactBase, options = {}) {
|
|
175
|
+
const { moduleFactory, moduleUrl } = await resolveModuleFactory(
|
|
176
|
+
artifactBase,
|
|
177
|
+
options
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const state = {
|
|
181
|
+
stdout: [],
|
|
182
|
+
stderr: [],
|
|
183
|
+
stdin: null,
|
|
184
|
+
stdinOffset: 0
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const onStdout =
|
|
188
|
+
typeof options.onStdout === "function" ? options.onStdout : null;
|
|
189
|
+
const onStderr =
|
|
190
|
+
typeof options.onStderr === "function" ? options.onStderr : null;
|
|
191
|
+
const stdoutLines = createLineBuffer(state, "stdout", onStdout);
|
|
192
|
+
const stderrLines = createLineBuffer(state, "stderr", onStderr);
|
|
193
|
+
state._stdoutLines = stdoutLines;
|
|
194
|
+
state._stderrLines = stderrLines;
|
|
195
|
+
|
|
196
|
+
const moduleOptions = {
|
|
197
|
+
noInitialRun: true,
|
|
198
|
+
noExitRuntime: true,
|
|
199
|
+
print(text) {
|
|
200
|
+
stdoutLines.write(text);
|
|
201
|
+
},
|
|
202
|
+
printErr(text) {
|
|
203
|
+
stderrLines.write(text);
|
|
204
|
+
},
|
|
205
|
+
stdin() {
|
|
206
|
+
if (!state.stdin) return null;
|
|
207
|
+
if (state.stdinOffset >= state.stdin.length) return null;
|
|
208
|
+
return state.stdin[state.stdinOffset++];
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
if (options.wasmBinary) {
|
|
213
|
+
moduleOptions.wasmBinary = toBytes(options.wasmBinary);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (options.moduleOptions && typeof options.moduleOptions === "object") {
|
|
217
|
+
const { print, printErr, stdin, locateFile, ...rest } = options.moduleOptions;
|
|
218
|
+
Object.assign(moduleOptions, rest);
|
|
219
|
+
if (!options.locateFile && !options.wasmUrl && locateFile) {
|
|
220
|
+
moduleOptions.locateFile = locateFile;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (options.locateFile) {
|
|
225
|
+
moduleOptions.locateFile = options.locateFile;
|
|
226
|
+
} else if (options.wasmUrl) {
|
|
227
|
+
const wasmUrl = toUrl(options.wasmUrl, moduleUrl);
|
|
228
|
+
moduleOptions.locateFile = (file) => {
|
|
229
|
+
if (file.endsWith(".wasm")) {
|
|
230
|
+
return wasmUrl.href;
|
|
231
|
+
}
|
|
232
|
+
return file;
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const module = await moduleFactory(moduleOptions);
|
|
237
|
+
return new WasmRunner(module, state, { workDir: options.workDir });
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
get FS() {
|
|
241
|
+
return this._module.FS;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
exists(pathValue) {
|
|
245
|
+
const path = toPosixPath(pathValue);
|
|
246
|
+
return this._module.FS.analyzePath(path).exists;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
writeFile(pathValue, data) {
|
|
250
|
+
const path = toPosixPath(pathValue);
|
|
251
|
+
ensureDir(this._module.FS, dirname(path));
|
|
252
|
+
this._module.FS.writeFile(path, toBytes(data));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
readFile(pathValue, encoding = "utf8") {
|
|
256
|
+
const path = toPosixPath(pathValue);
|
|
257
|
+
const data = this._module.FS.readFile(path);
|
|
258
|
+
return fromBytes(data, encoding);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
runWithStdin(stdinText, options = {}) {
|
|
262
|
+
this._state.stdout.length = 0;
|
|
263
|
+
this._state.stderr.length = 0;
|
|
264
|
+
if (this._state._stdoutLines) this._state._stdoutLines.reset();
|
|
265
|
+
if (this._state._stderrLines) this._state._stderrLines.reset();
|
|
266
|
+
if (stdinText == null) {
|
|
267
|
+
this._state.stdin = null;
|
|
268
|
+
this._state.stdinOffset = 0;
|
|
269
|
+
} else {
|
|
270
|
+
this._state.stdin = toBytes(stdinText);
|
|
271
|
+
this._state.stdinOffset = 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const workDir = toPosixPath(options.workDir || this._workDir || "");
|
|
275
|
+
if (workDir) {
|
|
276
|
+
ensureDir(this._module.FS, workDir);
|
|
277
|
+
this._module.FS.chdir(workDir);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const files = options.files || [];
|
|
281
|
+
for (const file of files) {
|
|
282
|
+
if (!file || !file.path) continue;
|
|
283
|
+
const dest = toPosixPath(file.path);
|
|
284
|
+
const target = dest.startsWith("/") ? dest : joinPath(workDir, dest);
|
|
285
|
+
ensureDir(this._module.FS, dirname(target));
|
|
286
|
+
this._module.FS.writeFile(target, toBytes(file.data));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
let exitCode = 0;
|
|
290
|
+
try {
|
|
291
|
+
exitCode = callMain(this._module, options.args || []);
|
|
292
|
+
} finally {
|
|
293
|
+
if (this._state._stdoutLines) this._state._stdoutLines.flush();
|
|
294
|
+
if (this._state._stderrLines) this._state._stderrLines.flush();
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
stdout: linesToText(this._state.stdout),
|
|
298
|
+
stderr: linesToText(this._state.stderr),
|
|
299
|
+
exitCode
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
destroy() {
|
|
304
|
+
const module = this._module;
|
|
305
|
+
if (!module) return;
|
|
306
|
+
try {
|
|
307
|
+
const fs = module.FS;
|
|
308
|
+
if (fs && typeof fs.analyzePath === "function") {
|
|
309
|
+
const workDir = this._workDir || "/work";
|
|
310
|
+
if (fs.analyzePath(workDir).exists) {
|
|
311
|
+
const entries = fs.readdir(workDir);
|
|
312
|
+
for (const name of entries) {
|
|
313
|
+
if (name === "." || name === "..") continue;
|
|
314
|
+
const target = `${workDir}/${name}`;
|
|
315
|
+
try {
|
|
316
|
+
fs.unlink(target);
|
|
317
|
+
} catch {
|
|
318
|
+
// ignore cleanup errors
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
} catch {
|
|
324
|
+
// ignore cleanup errors
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
try {
|
|
328
|
+
if (typeof module._exit === "function") {
|
|
329
|
+
module._exit(0);
|
|
330
|
+
}
|
|
331
|
+
} catch {
|
|
332
|
+
// ignore exit errors
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (this._state) {
|
|
336
|
+
this._state.stdout = [];
|
|
337
|
+
this._state.stderr = [];
|
|
338
|
+
this._state.stdin = null;
|
|
339
|
+
this._state.stdoutBuffer = "";
|
|
340
|
+
this._state.stderrBuffer = "";
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
this._module = null;
|
|
344
|
+
this._state = null;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export { WasmRunner, isNode, joinPath, toPosixPath };
|
|
349
|
+
|