@tracecode/harness 0.5.0 → 0.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/CHANGELOG.md +23 -0
- package/LICENSE +67 -80
- package/README.md +31 -4
- package/dist/browser.cjs +974 -19
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +3 -2
- package/dist/browser.d.ts +3 -2
- package/dist/browser.js +974 -19
- package/dist/browser.js.map +1 -1
- package/dist/cli.cjs +24 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +24 -0
- package/dist/cli.js.map +1 -1
- package/dist/core.cjs +611 -4
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +20 -6
- package/dist/core.d.ts +20 -6
- package/dist/core.js +605 -4
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +1055 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1049 -52
- package/dist/index.js.map +1 -1
- package/dist/internal/browser.cjs +211 -0
- package/dist/internal/browser.cjs.map +1 -1
- package/dist/internal/browser.d.cts +62 -6
- package/dist/internal/browser.d.ts +62 -6
- package/dist/internal/browser.js +210 -0
- package/dist/internal/browser.js.map +1 -1
- package/dist/javascript.cjs +37 -19
- package/dist/javascript.cjs.map +1 -1
- package/dist/javascript.d.cts +2 -2
- package/dist/javascript.d.ts +2 -2
- package/dist/javascript.js +37 -19
- package/dist/javascript.js.map +1 -1
- package/dist/python.cjs +14 -14
- package/dist/python.cjs.map +1 -1
- package/dist/python.d.cts +8 -8
- package/dist/python.d.ts +8 -8
- package/dist/python.js +14 -14
- package/dist/python.js.map +1 -1
- package/dist/{runtime-types-DtaaAhHL.d.ts → runtime-types-89nchXlY.d.cts} +8 -4
- package/dist/{runtime-types--lBQ6rYu.d.cts → runtime-types-CCQ-ZLc9.d.ts} +8 -4
- package/dist/{types-DwIYM3Ku.d.cts → types-zyvpJKCi.d.cts} +1 -0
- package/dist/{types-DwIYM3Ku.d.ts → types-zyvpJKCi.d.ts} +1 -0
- package/package.json +12 -6
- package/workers/java/.build/classes/harness/browser/JavaRewriteLibrary.class +0 -0
- package/workers/java/java-worker.js +712 -0
- package/workers/java/src/harness/browser/JavaRewriteLibrary.java +54 -0
- package/workers/javascript/javascript-worker.js +343 -63
- package/workers/python/generated-python-harness-snippets.js +3 -3
- package/workers/python/pyodide-worker.js +419 -68
- package/workers/python/runtime-core.js +52 -3
- package/workers/vendor/java-browser-spike-helper.jar +0 -0
- package/workers/vendor/java-practice-rewriter.jar +0 -0
- package/workers/vendor/java-rewrite-bridge.jar +0 -0
- package/workers/vendor/javaparser-core-3.25.10.jar +0 -0
- package/workers/vendor/jdk.compiler-17.jar +0 -0
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// packages/harness-core/src/trace-contract.ts
|
|
2
|
-
var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-
|
|
2
|
+
var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-04-21";
|
|
3
3
|
var TRACE_EVENTS = /* @__PURE__ */ new Set([
|
|
4
4
|
"line",
|
|
5
5
|
"call",
|
|
@@ -120,7 +120,39 @@ function normalizeAccesses(accesses) {
|
|
|
120
120
|
}
|
|
121
121
|
return payload;
|
|
122
122
|
}).filter((access) => access !== null);
|
|
123
|
-
|
|
123
|
+
if (normalized.length === 0) {
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
const statsByVariable = /* @__PURE__ */ new Map();
|
|
127
|
+
for (const access of normalized) {
|
|
128
|
+
const stats = statsByVariable.get(access.variable) ?? { hasCellRead: false, hasCellWrite: false };
|
|
129
|
+
if (access.kind === "cell-read") stats.hasCellRead = true;
|
|
130
|
+
if (access.kind === "cell-write") stats.hasCellWrite = true;
|
|
131
|
+
statsByVariable.set(access.variable, stats);
|
|
132
|
+
}
|
|
133
|
+
const deduped = /* @__PURE__ */ new Set();
|
|
134
|
+
const collapsed = normalized.filter((access) => {
|
|
135
|
+
const stats = statsByVariable.get(access.variable);
|
|
136
|
+
if (access.kind === "indexed-read" && (stats?.hasCellRead || stats?.hasCellWrite)) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
if (access.kind === "indexed-write" && stats?.hasCellWrite) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
const key = JSON.stringify([
|
|
143
|
+
access.variable,
|
|
144
|
+
access.kind,
|
|
145
|
+
access.indices ?? null,
|
|
146
|
+
access.pathDepth ?? null,
|
|
147
|
+
access.method ?? null
|
|
148
|
+
]);
|
|
149
|
+
if (deduped.has(key)) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
deduped.add(key);
|
|
153
|
+
return true;
|
|
154
|
+
});
|
|
155
|
+
return collapsed.length > 0 ? collapsed : void 0;
|
|
124
156
|
}
|
|
125
157
|
function normalizeRecord(value) {
|
|
126
158
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
@@ -184,8 +216,64 @@ function normalizeTraceStep(step) {
|
|
|
184
216
|
...normalizedVisualization ? { visualization: normalizedVisualization } : {}
|
|
185
217
|
};
|
|
186
218
|
}
|
|
219
|
+
function collapseTraceAccessNoise(trace) {
|
|
220
|
+
const variablesWithCellAccess = /* @__PURE__ */ new Set();
|
|
221
|
+
const accessStatsByVariable = /* @__PURE__ */ new Map();
|
|
222
|
+
for (const step of trace) {
|
|
223
|
+
for (const access of step.accesses ?? []) {
|
|
224
|
+
const stats = accessStatsByVariable.get(access.variable) ?? {
|
|
225
|
+
hasCellRead: false,
|
|
226
|
+
hasCellWrite: false,
|
|
227
|
+
hasMutatingCall: false,
|
|
228
|
+
hasIndexedWrite: false
|
|
229
|
+
};
|
|
230
|
+
if (access.kind === "cell-read" || access.kind === "cell-write") {
|
|
231
|
+
variablesWithCellAccess.add(access.variable);
|
|
232
|
+
}
|
|
233
|
+
if (access.kind === "cell-read") stats.hasCellRead = true;
|
|
234
|
+
if (access.kind === "cell-write") stats.hasCellWrite = true;
|
|
235
|
+
if (access.kind === "mutating-call") stats.hasMutatingCall = true;
|
|
236
|
+
if (access.kind === "indexed-write") stats.hasIndexedWrite = true;
|
|
237
|
+
accessStatsByVariable.set(access.variable, stats);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (variablesWithCellAccess.size === 0) {
|
|
241
|
+
return trace;
|
|
242
|
+
}
|
|
243
|
+
return trace.map((step) => {
|
|
244
|
+
if (!step.accesses?.length) {
|
|
245
|
+
return step;
|
|
246
|
+
}
|
|
247
|
+
const filtered = step.accesses.filter((access) => {
|
|
248
|
+
const stats = accessStatsByVariable.get(access.variable);
|
|
249
|
+
if (variablesWithCellAccess.has(access.variable)) {
|
|
250
|
+
return access.kind !== "indexed-read" && access.kind !== "indexed-write";
|
|
251
|
+
}
|
|
252
|
+
if (access.kind === "mutating-call" && stats?.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
if (access.kind === "indexed-read" && stats?.hasMutatingCall && !stats.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
return true;
|
|
259
|
+
});
|
|
260
|
+
if (filtered.length === step.accesses.length) {
|
|
261
|
+
return step;
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
...step,
|
|
265
|
+
...filtered.length > 0 ? { accesses: filtered } : {},
|
|
266
|
+
...filtered.length === 0 ? { accesses: void 0 } : {}
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
}
|
|
187
270
|
function normalizeRuntimeTraceContract(language, result) {
|
|
188
|
-
const
|
|
271
|
+
const rawNormalizedTrace = collapseTraceAccessNoise(
|
|
272
|
+
Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : []
|
|
273
|
+
);
|
|
274
|
+
const maxTraceSteps = typeof result.maxTraceSteps === "number" && Number.isFinite(result.maxTraceSteps) ? Math.max(1, Math.floor(result.maxTraceSteps)) : void 0;
|
|
275
|
+
const traceWasClipped = maxTraceSteps !== void 0 && rawNormalizedTrace.length > maxTraceSteps;
|
|
276
|
+
const normalizedTrace = traceWasClipped && maxTraceSteps !== void 0 ? rawNormalizedTrace.slice(0, maxTraceSteps) : rawNormalizedTrace;
|
|
189
277
|
const lineEventCount = typeof result.lineEventCount === "number" && Number.isFinite(result.lineEventCount) ? Math.floor(result.lineEventCount) : normalizedTrace.filter((step) => step.event === "line").length;
|
|
190
278
|
const normalizedConsole = Array.isArray(result.consoleOutput) ? result.consoleOutput.map((line) => String(line)) : [];
|
|
191
279
|
return {
|
|
@@ -197,7 +285,7 @@ function normalizeRuntimeTraceContract(language, result) {
|
|
|
197
285
|
...typeof result.errorLine === "number" && Number.isFinite(result.errorLine) ? { errorLine: Math.floor(result.errorLine) } : {},
|
|
198
286
|
consoleOutput: normalizedConsole,
|
|
199
287
|
trace: normalizedTrace,
|
|
200
|
-
...result.traceLimitExceeded !== void 0 ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) } : {},
|
|
288
|
+
...result.traceLimitExceeded !== void 0 || traceWasClipped ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) || traceWasClipped } : {},
|
|
201
289
|
...typeof result.timeoutReason === "string" && result.timeoutReason.length > 0 ? { timeoutReason: result.timeoutReason } : {},
|
|
202
290
|
lineEventCount: Math.max(0, lineEventCount),
|
|
203
291
|
traceStepCount: normalizedTrace.length
|
|
@@ -256,6 +344,513 @@ function adaptJavaScriptTraceExecutionResult(language, result) {
|
|
|
256
344
|
return adaptTraceExecutionResult(language, result);
|
|
257
345
|
}
|
|
258
346
|
|
|
347
|
+
// packages/harness-core/src/trace-adapters/java.ts
|
|
348
|
+
function parseScalar(raw) {
|
|
349
|
+
if (raw === "null") return null;
|
|
350
|
+
if (raw === "true") return true;
|
|
351
|
+
if (raw === "false") return false;
|
|
352
|
+
if (/^-?\d+$/.test(raw)) return Number.parseInt(raw, 10);
|
|
353
|
+
if (/^-?\d+\.\d+$/.test(raw)) return Number.parseFloat(raw);
|
|
354
|
+
if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("[") && raw.endsWith("]") || raw.startsWith("{") && raw.endsWith("}")) {
|
|
355
|
+
try {
|
|
356
|
+
return JSON.parse(raw);
|
|
357
|
+
} catch {
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return raw;
|
|
361
|
+
}
|
|
362
|
+
function parseKeyValuePairs(fragment) {
|
|
363
|
+
const variables = {};
|
|
364
|
+
const matches = Array.from(fragment.matchAll(/\b([A-Za-z_][A-Za-z0-9_.]*)=/g));
|
|
365
|
+
for (let index = 0; index < matches.length; index += 1) {
|
|
366
|
+
const match = matches[index];
|
|
367
|
+
const rawKey = match[1];
|
|
368
|
+
const valueStart = (match.index ?? 0) + match[0].length;
|
|
369
|
+
const valueEnd = index + 1 < matches.length ? matches[index + 1].index ?? fragment.length : fragment.length;
|
|
370
|
+
const rawValue = fragment.slice(valueStart, valueEnd).trim();
|
|
371
|
+
if (!rawKey || rawValue === void 0) continue;
|
|
372
|
+
if (rawKey === "method") continue;
|
|
373
|
+
variables[rawKey.replaceAll(".", "_")] = parseScalar(rawValue);
|
|
374
|
+
}
|
|
375
|
+
return variables;
|
|
376
|
+
}
|
|
377
|
+
function extractLineMetadata(event) {
|
|
378
|
+
const match = event.match(/^line=(\d+)(?:\s+(.*))?$/);
|
|
379
|
+
if (!match) {
|
|
380
|
+
return { line: 1, payload: event };
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
line: Number.parseInt(match[1], 10),
|
|
384
|
+
payload: match[2] ?? ""
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function stripInlineComments(line, inBlockComment) {
|
|
388
|
+
let result = "";
|
|
389
|
+
let index = 0;
|
|
390
|
+
let inBlock = inBlockComment;
|
|
391
|
+
while (index < line.length) {
|
|
392
|
+
const current = line[index];
|
|
393
|
+
const next = index + 1 < line.length ? line[index + 1] : "";
|
|
394
|
+
if (inBlock) {
|
|
395
|
+
if (current === "*" && next === "/") {
|
|
396
|
+
inBlock = false;
|
|
397
|
+
index += 2;
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
index += 1;
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
if (current === "/" && next === "*") {
|
|
404
|
+
inBlock = true;
|
|
405
|
+
index += 2;
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
if (current === "/" && next === "/") {
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
result += current;
|
|
412
|
+
index += 1;
|
|
413
|
+
}
|
|
414
|
+
return { text: result, inBlockComment: inBlock };
|
|
415
|
+
}
|
|
416
|
+
function isMethodDeclarationLine(line) {
|
|
417
|
+
const trimmed = line.trim();
|
|
418
|
+
if (!trimmed) return false;
|
|
419
|
+
if (trimmed.startsWith("@")) return false;
|
|
420
|
+
if (!trimmed.includes("(") || !trimmed.includes(")")) return false;
|
|
421
|
+
if (trimmed.endsWith(";")) return false;
|
|
422
|
+
if (trimmed.includes("->")) return false;
|
|
423
|
+
if (/^(?:if|for|while|switch|catch|do|try|else|return|throw|new)\b/.test(trimmed)) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
if (!/[A-Za-z_][A-Za-z0-9_]*\s*\([^{};]*\)/.test(trimmed)) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
return /(?:\{\s*)?$/.test(trimmed);
|
|
430
|
+
}
|
|
431
|
+
function buildLineRemap(sourceText) {
|
|
432
|
+
if (typeof sourceText !== "string" || sourceText.length === 0) {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
const lines = sourceText.split(/\r?\n/);
|
|
436
|
+
const executable = /* @__PURE__ */ new Set();
|
|
437
|
+
let inBlockComment = false;
|
|
438
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
439
|
+
const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
|
|
440
|
+
inBlockComment = nextInBlockComment;
|
|
441
|
+
if (text.trim().length > 0) {
|
|
442
|
+
executable.add(index + 1);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (executable.size === 0) {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
const nextExecutableAtOrAfter = new Array(lines.length + 2).fill(null);
|
|
449
|
+
let nextExecutable = null;
|
|
450
|
+
for (let line = lines.length; line >= 1; line -= 1) {
|
|
451
|
+
if (executable.has(line)) {
|
|
452
|
+
nextExecutable = line;
|
|
453
|
+
}
|
|
454
|
+
nextExecutableAtOrAfter[line] = nextExecutable;
|
|
455
|
+
}
|
|
456
|
+
const previousExecutableAtOrBefore = new Array(lines.length + 2).fill(null);
|
|
457
|
+
let previousExecutable = null;
|
|
458
|
+
for (let line = 1; line <= lines.length; line += 1) {
|
|
459
|
+
if (executable.has(line)) {
|
|
460
|
+
previousExecutable = line;
|
|
461
|
+
}
|
|
462
|
+
previousExecutableAtOrBefore[line] = previousExecutable;
|
|
463
|
+
}
|
|
464
|
+
const remap = /* @__PURE__ */ new Map();
|
|
465
|
+
for (let line = 1; line <= lines.length; line += 1) {
|
|
466
|
+
if (executable.has(line)) continue;
|
|
467
|
+
const forward = nextExecutableAtOrAfter[line];
|
|
468
|
+
const backward = previousExecutableAtOrBefore[line];
|
|
469
|
+
const target = forward ?? backward;
|
|
470
|
+
if (target !== null && target !== line) {
|
|
471
|
+
remap.set(line, target);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return remap;
|
|
475
|
+
}
|
|
476
|
+
function buildMethodDeclarationLineSet(sourceText) {
|
|
477
|
+
if (typeof sourceText !== "string" || sourceText.length === 0) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
const declarationLines = /* @__PURE__ */ new Set();
|
|
481
|
+
const lines = sourceText.split(/\r?\n/);
|
|
482
|
+
let inBlockComment = false;
|
|
483
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
484
|
+
const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
|
|
485
|
+
inBlockComment = nextInBlockComment;
|
|
486
|
+
if (isMethodDeclarationLine(text)) {
|
|
487
|
+
declarationLines.add(index + 1);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return declarationLines;
|
|
491
|
+
}
|
|
492
|
+
function parseAccessEvent(payload) {
|
|
493
|
+
const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
|
|
494
|
+
const cellRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
|
|
495
|
+
if (cellRead) {
|
|
496
|
+
return [{
|
|
497
|
+
variable: cellRead[1],
|
|
498
|
+
kind: "cell-read",
|
|
499
|
+
indices: [Number.parseInt(cellRead[2], 10), Number.parseInt(cellRead[3], 10)],
|
|
500
|
+
pathDepth: 2
|
|
501
|
+
}];
|
|
502
|
+
}
|
|
503
|
+
const indexedRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
|
|
504
|
+
if (indexedRead) {
|
|
505
|
+
return [{
|
|
506
|
+
variable: indexedRead[1],
|
|
507
|
+
kind: "indexed-read",
|
|
508
|
+
indices: [Number.parseInt(indexedRead[2], 10)],
|
|
509
|
+
pathDepth: 1
|
|
510
|
+
}];
|
|
511
|
+
}
|
|
512
|
+
const cellWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
|
|
513
|
+
if (cellWrite) {
|
|
514
|
+
return [{
|
|
515
|
+
variable: cellWrite[1],
|
|
516
|
+
kind: "cell-write",
|
|
517
|
+
indices: [Number.parseInt(cellWrite[2], 10), Number.parseInt(cellWrite[3], 10)],
|
|
518
|
+
pathDepth: 2
|
|
519
|
+
}];
|
|
520
|
+
}
|
|
521
|
+
const indexedWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
|
|
522
|
+
if (indexedWrite) {
|
|
523
|
+
if (isEphemeralOutputArrayName(indexedWrite[1])) {
|
|
524
|
+
return void 0;
|
|
525
|
+
}
|
|
526
|
+
return [{
|
|
527
|
+
variable: indexedWrite[1],
|
|
528
|
+
kind: "indexed-write",
|
|
529
|
+
indices: [Number.parseInt(indexedWrite[2], 10)],
|
|
530
|
+
pathDepth: 1
|
|
531
|
+
}];
|
|
532
|
+
}
|
|
533
|
+
const mutatingCall = payload.match(/^mutate ([A-Za-z_][A-Za-z0-9_]*) method=([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
534
|
+
if (mutatingCall) {
|
|
535
|
+
return [{
|
|
536
|
+
variable: mutatingCall[1],
|
|
537
|
+
kind: "mutating-call",
|
|
538
|
+
method: mutatingCall[2],
|
|
539
|
+
pathDepth: 1
|
|
540
|
+
}];
|
|
541
|
+
}
|
|
542
|
+
return void 0;
|
|
543
|
+
}
|
|
544
|
+
function parseStructureState(payload) {
|
|
545
|
+
const match = payload.match(/^state (linked-list|tree) ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
|
|
546
|
+
if (!match) return null;
|
|
547
|
+
return {
|
|
548
|
+
structure: match[1],
|
|
549
|
+
variable: match[2],
|
|
550
|
+
value: JSON.parse(match[3])
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
function parseObjectState(payload) {
|
|
554
|
+
const match = payload.match(/^object-state ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
|
|
555
|
+
if (!match) return null;
|
|
556
|
+
return {
|
|
557
|
+
variable: match[1],
|
|
558
|
+
visualization: JSON.parse(match[2])
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function parseObjectFieldEvent(payload) {
|
|
562
|
+
const match = payload.match(/^(access|write) ([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
|
|
563
|
+
if (!match) return null;
|
|
564
|
+
return {
|
|
565
|
+
variable: match[2],
|
|
566
|
+
field: match[3],
|
|
567
|
+
value: parseScalar(match[4])
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function buildFieldVisualization(event) {
|
|
571
|
+
return {
|
|
572
|
+
objectKinds: {
|
|
573
|
+
[event.variable]: "object"
|
|
574
|
+
},
|
|
575
|
+
hashMaps: [
|
|
576
|
+
{
|
|
577
|
+
name: event.variable,
|
|
578
|
+
kind: "object",
|
|
579
|
+
objectClassName: event.field === "next" || event.field === "prev" ? "ListNode" : event.field === "left" || event.field === "right" ? "TreeNode" : void 0,
|
|
580
|
+
objectId: `${event.variable}-object`,
|
|
581
|
+
highlightedKey: event.field,
|
|
582
|
+
entries: [{ key: event.field, value: event.value, highlight: true }]
|
|
583
|
+
}
|
|
584
|
+
]
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
function callStacksEqual(left, right) {
|
|
588
|
+
return JSON.stringify(left ?? []) === JSON.stringify(right ?? []);
|
|
589
|
+
}
|
|
590
|
+
function mergeVisualizationPayloads(left, right) {
|
|
591
|
+
if (!left) return right;
|
|
592
|
+
if (!right) return left;
|
|
593
|
+
return {
|
|
594
|
+
...left,
|
|
595
|
+
...right,
|
|
596
|
+
objectKinds: {
|
|
597
|
+
...left.objectKinds ?? {},
|
|
598
|
+
...right.objectKinds ?? {}
|
|
599
|
+
},
|
|
600
|
+
hashMaps: [
|
|
601
|
+
...left.hashMaps ?? [],
|
|
602
|
+
...right.hashMaps ?? []
|
|
603
|
+
]
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function maybeMergeConsecutiveLineStep(trace, nextStep) {
|
|
607
|
+
if (nextStep.event !== "line") {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
const previous = trace.at(-1);
|
|
611
|
+
if (!previous || previous.event !== "line") {
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
if (previous.line !== nextStep.line || previous.function !== nextStep.function) {
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
if (!callStacksEqual(previous.callStack, nextStep.callStack)) {
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
previous.variables = { ...previous.variables ?? {}, ...nextStep.variables ?? {} };
|
|
621
|
+
if (nextStep.accesses?.length) {
|
|
622
|
+
previous.accesses = [...previous.accesses ?? [], ...nextStep.accesses];
|
|
623
|
+
}
|
|
624
|
+
previous.visualization = mergeVisualizationPayloads(previous.visualization, nextStep.visualization);
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
function filterStructuredVariables(variables) {
|
|
628
|
+
if (!variables) {
|
|
629
|
+
return void 0;
|
|
630
|
+
}
|
|
631
|
+
const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
|
|
632
|
+
const entries = Object.entries(variables).filter(([name, value]) => {
|
|
633
|
+
if (value === null || typeof value !== "object") {
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
if (!Array.isArray(value)) {
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
if (Array.isArray(value[0])) {
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
return !isEphemeralOutputArrayName(name);
|
|
643
|
+
});
|
|
644
|
+
if (entries.length === 0) {
|
|
645
|
+
return void 0;
|
|
646
|
+
}
|
|
647
|
+
return Object.fromEntries(entries);
|
|
648
|
+
}
|
|
649
|
+
function appendJavaTraceStep(trace, step, pendingAccesses) {
|
|
650
|
+
const nextStep = pendingAccesses.length > 0 ? { ...step, accesses: [...pendingAccesses] } : step;
|
|
651
|
+
pendingAccesses.length = 0;
|
|
652
|
+
if (!maybeMergeConsecutiveLineStep(trace, nextStep)) {
|
|
653
|
+
trace.push(nextStep);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
function mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, patch) {
|
|
657
|
+
const candidate = trace.at(-1);
|
|
658
|
+
if (!candidate || candidate.event !== "line") {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
if (candidate.line !== line || candidate.function !== currentFunction) {
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
if (!callStacksEqual(candidate.callStack, currentCallStack)) {
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
candidate.variables = { ...candidate.variables ?? {}, ...patch.variables ?? {} };
|
|
668
|
+
if (patch.accesses?.length) {
|
|
669
|
+
candidate.accesses = [...candidate.accesses ?? [], ...patch.accesses];
|
|
670
|
+
}
|
|
671
|
+
candidate.visualization = mergeVisualizationPayloads(candidate.visualization, patch.visualization);
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
function mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses) {
|
|
675
|
+
return mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
|
|
676
|
+
variables: void 0,
|
|
677
|
+
accesses,
|
|
678
|
+
visualization: void 0
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
function eventsToRawTrace(events, sourceText) {
|
|
682
|
+
const trace = [];
|
|
683
|
+
const variables = {};
|
|
684
|
+
const objectKinds = {};
|
|
685
|
+
const stack = [];
|
|
686
|
+
const pendingAccesses = [];
|
|
687
|
+
let currentFunction = "<module>";
|
|
688
|
+
const lineRemap = buildLineRemap(sourceText);
|
|
689
|
+
const declarationLines = buildMethodDeclarationLineSet(sourceText);
|
|
690
|
+
for (const rawEvent of events) {
|
|
691
|
+
if (rawEvent === "clear" || rawEvent === "reset") continue;
|
|
692
|
+
const metadata = extractLineMetadata(rawEvent);
|
|
693
|
+
const line = lineRemap?.get(metadata.line) ?? metadata.line;
|
|
694
|
+
const payload = metadata.payload;
|
|
695
|
+
const isDeclarationLine = declarationLines?.has(line) === true;
|
|
696
|
+
if (payload.startsWith("call ")) {
|
|
697
|
+
const match = payload.match(/^call\s+(\S+)(?:\s+(.*))?$/);
|
|
698
|
+
const functionName = match?.[1] ?? currentFunction;
|
|
699
|
+
const argsFragment = match?.[2] ?? "";
|
|
700
|
+
Object.assign(variables, parseKeyValuePairs(argsFragment));
|
|
701
|
+
currentFunction = functionName || currentFunction;
|
|
702
|
+
stack.push({ function: currentFunction, line });
|
|
703
|
+
appendJavaTraceStep(trace, {
|
|
704
|
+
line,
|
|
705
|
+
event: "call",
|
|
706
|
+
function: currentFunction,
|
|
707
|
+
variables: { ...variables },
|
|
708
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
|
|
709
|
+
}, pendingAccesses);
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
if (payload.startsWith("return ")) {
|
|
713
|
+
const match = payload.match(/^return\s+(\S+)$/);
|
|
714
|
+
const functionName = match?.[1] ?? currentFunction;
|
|
715
|
+
const returnVariables = functionName === "<module>" ? { ...variables } : filterStructuredVariables(variables) ?? {};
|
|
716
|
+
appendJavaTraceStep(trace, {
|
|
717
|
+
line,
|
|
718
|
+
event: "return",
|
|
719
|
+
function: functionName || currentFunction,
|
|
720
|
+
variables: returnVariables,
|
|
721
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
|
|
722
|
+
}, pendingAccesses);
|
|
723
|
+
stack.pop();
|
|
724
|
+
currentFunction = stack[stack.length - 1]?.function ?? "<module>";
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
if (isDeclarationLine) {
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
if (payload.length === 0) {
|
|
731
|
+
appendJavaTraceStep(trace, {
|
|
732
|
+
line,
|
|
733
|
+
event: "line",
|
|
734
|
+
function: currentFunction,
|
|
735
|
+
variables: { ...variables },
|
|
736
|
+
...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
|
|
737
|
+
}, pendingAccesses);
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
const structureState = parseStructureState(payload);
|
|
741
|
+
if (structureState) {
|
|
742
|
+
variables[structureState.variable] = structureState.value;
|
|
743
|
+
objectKinds[structureState.variable] = structureState.structure;
|
|
744
|
+
appendJavaTraceStep(trace, {
|
|
745
|
+
line,
|
|
746
|
+
event: "line",
|
|
747
|
+
function: currentFunction,
|
|
748
|
+
variables: { ...variables },
|
|
749
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
|
|
750
|
+
visualization: {
|
|
751
|
+
objectKinds: { ...objectKinds }
|
|
752
|
+
}
|
|
753
|
+
}, pendingAccesses);
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
const objectState = parseObjectState(payload);
|
|
757
|
+
if (objectState) {
|
|
758
|
+
variables[objectState.variable] = { __ref__: objectState.visualization.objectId ?? `${objectState.variable}-object` };
|
|
759
|
+
appendJavaTraceStep(trace, {
|
|
760
|
+
line,
|
|
761
|
+
event: "line",
|
|
762
|
+
function: currentFunction,
|
|
763
|
+
variables: { ...variables },
|
|
764
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
|
|
765
|
+
visualization: {
|
|
766
|
+
objectKinds: { [objectState.variable]: "object" },
|
|
767
|
+
hashMaps: [objectState.visualization]
|
|
768
|
+
}
|
|
769
|
+
}, pendingAccesses);
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
const objectField = parseObjectFieldEvent(payload);
|
|
773
|
+
if (objectField) {
|
|
774
|
+
variables[objectField.variable] = { __ref__: `${objectField.variable}-object` };
|
|
775
|
+
const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
|
|
776
|
+
if (mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
|
|
777
|
+
variables: { ...variables },
|
|
778
|
+
accesses: void 0,
|
|
779
|
+
visualization: buildFieldVisualization(objectField)
|
|
780
|
+
})) {
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
appendJavaTraceStep(trace, {
|
|
784
|
+
line,
|
|
785
|
+
event: "line",
|
|
786
|
+
function: currentFunction,
|
|
787
|
+
variables: { ...variables },
|
|
788
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
|
|
789
|
+
visualization: buildFieldVisualization(objectField)
|
|
790
|
+
}, pendingAccesses);
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
Object.assign(variables, parseKeyValuePairs(payload));
|
|
794
|
+
const accesses = parseAccessEvent(payload);
|
|
795
|
+
if (accesses) {
|
|
796
|
+
const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
|
|
797
|
+
if (mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses)) {
|
|
798
|
+
continue;
|
|
799
|
+
}
|
|
800
|
+
pendingAccesses.push(...accesses);
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
appendJavaTraceStep(trace, {
|
|
804
|
+
line,
|
|
805
|
+
event: "line",
|
|
806
|
+
function: currentFunction,
|
|
807
|
+
variables: { ...variables },
|
|
808
|
+
...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
|
|
809
|
+
}, pendingAccesses);
|
|
810
|
+
}
|
|
811
|
+
if (pendingAccesses.length > 0 && trace.length > 0) {
|
|
812
|
+
const last = trace[trace.length - 1];
|
|
813
|
+
last.accesses = [...last.accesses ?? [], ...pendingAccesses];
|
|
814
|
+
}
|
|
815
|
+
return trace;
|
|
816
|
+
}
|
|
817
|
+
function buildJavaExecutionResult(output, events, executionTimeMs = 0, traceLimitExceeded, timeoutReason, maxTraceSteps, sourceText) {
|
|
818
|
+
const trace = eventsToRawTrace(events, sourceText);
|
|
819
|
+
return {
|
|
820
|
+
success: true,
|
|
821
|
+
output,
|
|
822
|
+
trace,
|
|
823
|
+
executionTimeMs,
|
|
824
|
+
consoleOutput: [],
|
|
825
|
+
...traceLimitExceeded !== void 0 ? { traceLimitExceeded } : {},
|
|
826
|
+
...maxTraceSteps !== void 0 ? { maxTraceSteps } : {},
|
|
827
|
+
...timeoutReason ? { timeoutReason } : {},
|
|
828
|
+
lineEventCount: trace.filter((step) => step.event === "line").length,
|
|
829
|
+
traceStepCount: trace.length
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
function normalizeJavaTraceContract(result) {
|
|
833
|
+
const normalized = normalizeRuntimeTraceContract(
|
|
834
|
+
"java",
|
|
835
|
+
buildJavaExecutionResult(
|
|
836
|
+
result.output,
|
|
837
|
+
result.events,
|
|
838
|
+
0,
|
|
839
|
+
result.traceLimitExceeded,
|
|
840
|
+
result.timeoutReason,
|
|
841
|
+
void 0,
|
|
842
|
+
result.sourceText
|
|
843
|
+
)
|
|
844
|
+
);
|
|
845
|
+
return {
|
|
846
|
+
...normalized,
|
|
847
|
+
language: "java"
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
function adaptJavaTraceExecutionResult(result) {
|
|
851
|
+
return adaptTraceExecutionResult("java", result);
|
|
852
|
+
}
|
|
853
|
+
|
|
259
854
|
// packages/harness-browser/src/javascript-worker-client.ts
|
|
260
855
|
var EXECUTION_TIMEOUT_MS = 7e3;
|
|
261
856
|
var INTERVIEW_MODE_TIMEOUT_MS = 5e3;
|
|
@@ -582,6 +1177,7 @@ var PYTHON_RUNTIME_PROFILE = {
|
|
|
582
1177
|
maxTraceSteps: true,
|
|
583
1178
|
maxLineEvents: true,
|
|
584
1179
|
maxSingleLineHits: true,
|
|
1180
|
+
maxStoredEvents: true,
|
|
585
1181
|
minimalTrace: true
|
|
586
1182
|
},
|
|
587
1183
|
fidelity: {
|
|
@@ -643,6 +1239,7 @@ var JAVASCRIPT_RUNTIME_PROFILE = {
|
|
|
643
1239
|
maxTraceSteps: true,
|
|
644
1240
|
maxLineEvents: true,
|
|
645
1241
|
maxSingleLineHits: true,
|
|
1242
|
+
maxStoredEvents: true,
|
|
646
1243
|
minimalTrace: true
|
|
647
1244
|
},
|
|
648
1245
|
fidelity: {
|
|
@@ -704,6 +1301,7 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
|
|
|
704
1301
|
maxTraceSteps: true,
|
|
705
1302
|
maxLineEvents: true,
|
|
706
1303
|
maxSingleLineHits: true,
|
|
1304
|
+
maxStoredEvents: true,
|
|
707
1305
|
minimalTrace: true
|
|
708
1306
|
},
|
|
709
1307
|
fidelity: {
|
|
@@ -734,10 +1332,78 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
|
|
|
734
1332
|
}
|
|
735
1333
|
}
|
|
736
1334
|
};
|
|
1335
|
+
var JAVA_RUNTIME_PROFILE = {
|
|
1336
|
+
language: "java",
|
|
1337
|
+
maturity: "experimental",
|
|
1338
|
+
capabilities: {
|
|
1339
|
+
execution: {
|
|
1340
|
+
styles: {
|
|
1341
|
+
function: true,
|
|
1342
|
+
solutionMethod: true,
|
|
1343
|
+
opsClass: true,
|
|
1344
|
+
script: false,
|
|
1345
|
+
interviewMode: true
|
|
1346
|
+
},
|
|
1347
|
+
timeouts: {
|
|
1348
|
+
clientTimeouts: true,
|
|
1349
|
+
runtimeTimeouts: true
|
|
1350
|
+
}
|
|
1351
|
+
},
|
|
1352
|
+
tracing: {
|
|
1353
|
+
supported: true,
|
|
1354
|
+
events: {
|
|
1355
|
+
line: true,
|
|
1356
|
+
call: true,
|
|
1357
|
+
return: true,
|
|
1358
|
+
exception: true,
|
|
1359
|
+
stdout: false,
|
|
1360
|
+
timeout: true
|
|
1361
|
+
},
|
|
1362
|
+
controls: {
|
|
1363
|
+
maxTraceSteps: true,
|
|
1364
|
+
maxLineEvents: false,
|
|
1365
|
+
maxSingleLineHits: false,
|
|
1366
|
+
maxStoredEvents: true,
|
|
1367
|
+
minimalTrace: false
|
|
1368
|
+
},
|
|
1369
|
+
fidelity: {
|
|
1370
|
+
preciseLineMapping: true,
|
|
1371
|
+
stableFunctionNames: true,
|
|
1372
|
+
callStack: true
|
|
1373
|
+
}
|
|
1374
|
+
},
|
|
1375
|
+
diagnostics: {
|
|
1376
|
+
compileErrors: true,
|
|
1377
|
+
runtimeErrors: true,
|
|
1378
|
+
mappedErrorLines: false,
|
|
1379
|
+
stackTraces: true
|
|
1380
|
+
},
|
|
1381
|
+
structures: {
|
|
1382
|
+
treeNodeRefs: true,
|
|
1383
|
+
listNodeRefs: true,
|
|
1384
|
+
mapSerialization: true,
|
|
1385
|
+
setSerialization: true,
|
|
1386
|
+
graphSerialization: false,
|
|
1387
|
+
cycleReferences: true
|
|
1388
|
+
},
|
|
1389
|
+
visualization: {
|
|
1390
|
+
runtimePayloads: true,
|
|
1391
|
+
objectKinds: true,
|
|
1392
|
+
hashMaps: true,
|
|
1393
|
+
stepVisualization: true
|
|
1394
|
+
}
|
|
1395
|
+
},
|
|
1396
|
+
notes: [
|
|
1397
|
+
"Java currently supports the browser-local Java 17 lane for function, solution-method, and ops-class execution.",
|
|
1398
|
+
"Interview-mode Java reuses the same browser-local execution path and remains experimental in the first harness slice.",
|
|
1399
|
+
"Script-style Java is not enabled yet."
|
|
1400
|
+
]
|
|
1401
|
+
};
|
|
737
1402
|
var LANGUAGE_RUNTIME_PROFILES = {
|
|
738
1403
|
python: PYTHON_RUNTIME_PROFILE,
|
|
739
1404
|
javascript: JAVASCRIPT_RUNTIME_PROFILE,
|
|
740
|
-
typescript: TYPESCRIPT_RUNTIME_PROFILE
|
|
1405
|
+
typescript: TYPESCRIPT_RUNTIME_PROFILE,
|
|
1406
|
+
java: JAVA_RUNTIME_PROFILE
|
|
741
1407
|
};
|
|
742
1408
|
var SUPPORTED_LANGUAGES = Object.freeze(
|
|
743
1409
|
Object.keys(LANGUAGE_RUNTIME_PROFILES)
|
|
@@ -814,13 +1480,307 @@ function createJavaScriptRuntimeClient(runtimeLanguage, workerClient) {
|
|
|
814
1480
|
return new JavaScriptRuntimeClient(runtimeLanguage, workerClient);
|
|
815
1481
|
}
|
|
816
1482
|
|
|
1483
|
+
// packages/harness-browser/src/java-worker-client.ts
|
|
1484
|
+
var TRACING_TIMEOUT_MS2 = 25e3;
|
|
1485
|
+
var INIT_TIMEOUT_MS2 = 25e3;
|
|
1486
|
+
var MESSAGE_TIMEOUT_MS2 = 3e4;
|
|
1487
|
+
var WORKER_READY_TIMEOUT_MS2 = 1e4;
|
|
1488
|
+
var JavaWorkerClient = class {
|
|
1489
|
+
constructor(options) {
|
|
1490
|
+
this.options = options;
|
|
1491
|
+
this.debug = options.debug ?? process.env.NODE_ENV === "development";
|
|
1492
|
+
}
|
|
1493
|
+
worker = null;
|
|
1494
|
+
pendingMessages = /* @__PURE__ */ new Map();
|
|
1495
|
+
messageId = 0;
|
|
1496
|
+
isInitializing = false;
|
|
1497
|
+
initPromise = null;
|
|
1498
|
+
workerReadyPromise = null;
|
|
1499
|
+
workerReadyResolve = null;
|
|
1500
|
+
workerReadyReject = null;
|
|
1501
|
+
debug;
|
|
1502
|
+
isSupported() {
|
|
1503
|
+
return typeof Worker !== "undefined";
|
|
1504
|
+
}
|
|
1505
|
+
getWorker() {
|
|
1506
|
+
if (this.worker) return this.worker;
|
|
1507
|
+
if (!this.isSupported()) {
|
|
1508
|
+
throw new Error("Web Workers are not supported in this environment");
|
|
1509
|
+
}
|
|
1510
|
+
this.workerReadyPromise = new Promise((resolve, reject) => {
|
|
1511
|
+
this.workerReadyResolve = resolve;
|
|
1512
|
+
this.workerReadyReject = (error) => reject(error);
|
|
1513
|
+
});
|
|
1514
|
+
const workerUrl = this.debug && !this.options.workerUrl.includes("?") ? `${this.options.workerUrl}?dev=${Date.now()}` : this.options.workerUrl;
|
|
1515
|
+
this.worker = new Worker(workerUrl);
|
|
1516
|
+
this.worker.onmessage = (event) => {
|
|
1517
|
+
const { id, type, payload } = event.data;
|
|
1518
|
+
if (type === "worker-ready") {
|
|
1519
|
+
this.workerReadyResolve?.();
|
|
1520
|
+
this.workerReadyResolve = null;
|
|
1521
|
+
this.workerReadyReject = null;
|
|
1522
|
+
return;
|
|
1523
|
+
}
|
|
1524
|
+
if (!id) return;
|
|
1525
|
+
const pending = this.pendingMessages.get(id);
|
|
1526
|
+
if (!pending) return;
|
|
1527
|
+
this.pendingMessages.delete(id);
|
|
1528
|
+
if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
|
|
1529
|
+
if (type === "error") {
|
|
1530
|
+
pending.reject(new Error(payload.error));
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
pending.resolve(payload);
|
|
1534
|
+
};
|
|
1535
|
+
this.worker.onerror = (error) => {
|
|
1536
|
+
const workerError = new Error(error.message || "Java worker error");
|
|
1537
|
+
this.workerReadyReject?.(workerError);
|
|
1538
|
+
this.workerReadyResolve = null;
|
|
1539
|
+
this.workerReadyReject = null;
|
|
1540
|
+
for (const [, pending] of this.pendingMessages) {
|
|
1541
|
+
if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
|
|
1542
|
+
pending.reject(workerError);
|
|
1543
|
+
}
|
|
1544
|
+
this.pendingMessages.clear();
|
|
1545
|
+
this.terminateAndReset(workerError);
|
|
1546
|
+
};
|
|
1547
|
+
return this.worker;
|
|
1548
|
+
}
|
|
1549
|
+
async waitForWorkerReady() {
|
|
1550
|
+
const readyPromise = this.workerReadyPromise;
|
|
1551
|
+
if (!readyPromise) return;
|
|
1552
|
+
await new Promise((resolve, reject) => {
|
|
1553
|
+
let settled = false;
|
|
1554
|
+
const timeoutId = globalThis.setTimeout(() => {
|
|
1555
|
+
if (settled) return;
|
|
1556
|
+
settled = true;
|
|
1557
|
+
const timeoutError = new Error(
|
|
1558
|
+
`Java worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS2 / 1e3)}s)`
|
|
1559
|
+
);
|
|
1560
|
+
this.terminateAndReset(timeoutError);
|
|
1561
|
+
reject(timeoutError);
|
|
1562
|
+
}, WORKER_READY_TIMEOUT_MS2);
|
|
1563
|
+
readyPromise.then(() => {
|
|
1564
|
+
if (settled) return;
|
|
1565
|
+
settled = true;
|
|
1566
|
+
globalThis.clearTimeout(timeoutId);
|
|
1567
|
+
resolve();
|
|
1568
|
+
}).catch((error) => {
|
|
1569
|
+
if (settled) return;
|
|
1570
|
+
settled = true;
|
|
1571
|
+
globalThis.clearTimeout(timeoutId);
|
|
1572
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
1573
|
+
});
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS2) {
|
|
1577
|
+
const worker = this.getWorker();
|
|
1578
|
+
await this.waitForWorkerReady();
|
|
1579
|
+
const id = String(++this.messageId);
|
|
1580
|
+
return new Promise((resolve, reject) => {
|
|
1581
|
+
this.pendingMessages.set(id, {
|
|
1582
|
+
resolve,
|
|
1583
|
+
reject
|
|
1584
|
+
});
|
|
1585
|
+
const timeoutId = globalThis.setTimeout(() => {
|
|
1586
|
+
const pending2 = this.pendingMessages.get(id);
|
|
1587
|
+
if (!pending2) return;
|
|
1588
|
+
this.pendingMessages.delete(id);
|
|
1589
|
+
pending2.reject(new Error(`Worker request timed out: ${type}`));
|
|
1590
|
+
}, timeoutMs);
|
|
1591
|
+
const pending = this.pendingMessages.get(id);
|
|
1592
|
+
if (pending) pending.timeoutId = timeoutId;
|
|
1593
|
+
worker.postMessage({ id, type, payload });
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
async executeWithTimeout(executor, timeoutMs) {
|
|
1597
|
+
return new Promise((resolve, reject) => {
|
|
1598
|
+
let settled = false;
|
|
1599
|
+
const timeoutId = globalThis.setTimeout(() => {
|
|
1600
|
+
if (settled) return;
|
|
1601
|
+
settled = true;
|
|
1602
|
+
this.terminateAndReset();
|
|
1603
|
+
reject(
|
|
1604
|
+
new Error(
|
|
1605
|
+
`Java execution timed out after ${Math.round(timeoutMs / 1e3)} seconds.`
|
|
1606
|
+
)
|
|
1607
|
+
);
|
|
1608
|
+
}, timeoutMs);
|
|
1609
|
+
executor().then((result) => {
|
|
1610
|
+
if (settled) return;
|
|
1611
|
+
settled = true;
|
|
1612
|
+
globalThis.clearTimeout(timeoutId);
|
|
1613
|
+
resolve(result);
|
|
1614
|
+
}).catch((error) => {
|
|
1615
|
+
if (settled) return;
|
|
1616
|
+
settled = true;
|
|
1617
|
+
globalThis.clearTimeout(timeoutId);
|
|
1618
|
+
reject(error);
|
|
1619
|
+
});
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
terminateAndReset(reason = new Error("Worker was terminated")) {
|
|
1623
|
+
this.workerReadyReject?.(reason);
|
|
1624
|
+
if (this.worker) {
|
|
1625
|
+
this.worker.terminate();
|
|
1626
|
+
this.worker = null;
|
|
1627
|
+
}
|
|
1628
|
+
this.initPromise = null;
|
|
1629
|
+
this.isInitializing = false;
|
|
1630
|
+
this.workerReadyPromise = null;
|
|
1631
|
+
this.workerReadyResolve = null;
|
|
1632
|
+
this.workerReadyReject = null;
|
|
1633
|
+
for (const [, pending] of this.pendingMessages) {
|
|
1634
|
+
if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
|
|
1635
|
+
pending.reject(reason);
|
|
1636
|
+
}
|
|
1637
|
+
this.pendingMessages.clear();
|
|
1638
|
+
}
|
|
1639
|
+
async init() {
|
|
1640
|
+
if (this.initPromise) return this.initPromise;
|
|
1641
|
+
if (this.isInitializing) {
|
|
1642
|
+
await new Promise((resolve) => globalThis.setTimeout(resolve, 100));
|
|
1643
|
+
return this.init();
|
|
1644
|
+
}
|
|
1645
|
+
this.isInitializing = true;
|
|
1646
|
+
this.initPromise = this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
|
|
1647
|
+
try {
|
|
1648
|
+
return await this.initPromise;
|
|
1649
|
+
} catch (error) {
|
|
1650
|
+
this.initPromise = null;
|
|
1651
|
+
throw error;
|
|
1652
|
+
} finally {
|
|
1653
|
+
this.isInitializing = false;
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
async executeWithTracing(code, functionName, inputs, options, executionStyle) {
|
|
1657
|
+
await this.init();
|
|
1658
|
+
return this.executeWithTimeout(
|
|
1659
|
+
() => this.sendMessage(
|
|
1660
|
+
"execute-with-tracing",
|
|
1661
|
+
{ code, functionName, inputs, options, executionStyle },
|
|
1662
|
+
TRACING_TIMEOUT_MS2 + 5e3
|
|
1663
|
+
),
|
|
1664
|
+
TRACING_TIMEOUT_MS2
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1667
|
+
async executeCode(code, functionName, inputs, options, executionStyle) {
|
|
1668
|
+
const result = await this.executeWithTracing(code, functionName, inputs, options, executionStyle);
|
|
1669
|
+
if (!result.success) {
|
|
1670
|
+
return {
|
|
1671
|
+
success: false,
|
|
1672
|
+
output: null,
|
|
1673
|
+
error: result.error ?? "Java execution failed",
|
|
1674
|
+
...result.errorLine !== void 0 ? { errorLine: result.errorLine } : {},
|
|
1675
|
+
consoleOutput: result.consoleOutput
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
return {
|
|
1679
|
+
success: true,
|
|
1680
|
+
output: result.output,
|
|
1681
|
+
consoleOutput: result.consoleOutput
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
async executeCodeInterviewMode(code, functionName, inputs, options, executionStyle) {
|
|
1685
|
+
return this.executeCode(code, functionName, inputs, options, executionStyle);
|
|
1686
|
+
}
|
|
1687
|
+
terminate() {
|
|
1688
|
+
this.terminateAndReset();
|
|
1689
|
+
}
|
|
1690
|
+
};
|
|
1691
|
+
|
|
1692
|
+
// packages/harness-browser/src/java-runtime-client.ts
|
|
1693
|
+
var JavaRuntimeClient = class {
|
|
1694
|
+
constructor(workerClient) {
|
|
1695
|
+
this.workerClient = workerClient;
|
|
1696
|
+
}
|
|
1697
|
+
async init() {
|
|
1698
|
+
return this.workerClient.init();
|
|
1699
|
+
}
|
|
1700
|
+
async executeWithTracing(code, functionName, inputs, options, executionStyle = "function") {
|
|
1701
|
+
assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
|
|
1702
|
+
request: "trace",
|
|
1703
|
+
executionStyle,
|
|
1704
|
+
functionName
|
|
1705
|
+
});
|
|
1706
|
+
const rawResult = await this.workerClient.executeWithTracing(
|
|
1707
|
+
code,
|
|
1708
|
+
functionName ?? "",
|
|
1709
|
+
inputs,
|
|
1710
|
+
options,
|
|
1711
|
+
executionStyle
|
|
1712
|
+
);
|
|
1713
|
+
if (!rawResult.success) {
|
|
1714
|
+
return {
|
|
1715
|
+
success: false,
|
|
1716
|
+
error: rawResult.error ?? "Java tracing failed",
|
|
1717
|
+
...rawResult.errorLine !== void 0 ? { errorLine: rawResult.errorLine } : {},
|
|
1718
|
+
trace: [],
|
|
1719
|
+
executionTimeMs: rawResult.executionTimeMs,
|
|
1720
|
+
consoleOutput: rawResult.consoleOutput,
|
|
1721
|
+
...rawResult.traceLimitExceeded !== void 0 ? { traceLimitExceeded: rawResult.traceLimitExceeded } : {},
|
|
1722
|
+
...rawResult.timeoutReason ? { timeoutReason: rawResult.timeoutReason } : {},
|
|
1723
|
+
lineEventCount: 0,
|
|
1724
|
+
traceStepCount: 0
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
const adapted = adaptJavaTraceExecutionResult(
|
|
1728
|
+
buildJavaExecutionResult(
|
|
1729
|
+
rawResult.output,
|
|
1730
|
+
rawResult.events,
|
|
1731
|
+
rawResult.executionTimeMs,
|
|
1732
|
+
rawResult.traceLimitExceeded,
|
|
1733
|
+
rawResult.timeoutReason,
|
|
1734
|
+
void 0,
|
|
1735
|
+
rawResult.sourceText
|
|
1736
|
+
)
|
|
1737
|
+
);
|
|
1738
|
+
return {
|
|
1739
|
+
...adapted,
|
|
1740
|
+
consoleOutput: rawResult.consoleOutput,
|
|
1741
|
+
executionTimeMs: rawResult.executionTimeMs
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
async executeCode(code, functionName, inputs, executionStyle = "function") {
|
|
1745
|
+
assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
|
|
1746
|
+
request: "execute",
|
|
1747
|
+
executionStyle,
|
|
1748
|
+
functionName
|
|
1749
|
+
});
|
|
1750
|
+
return this.workerClient.executeCode(
|
|
1751
|
+
code,
|
|
1752
|
+
functionName,
|
|
1753
|
+
inputs,
|
|
1754
|
+
void 0,
|
|
1755
|
+
executionStyle
|
|
1756
|
+
);
|
|
1757
|
+
}
|
|
1758
|
+
async executeCodeInterviewMode(code, functionName, inputs, executionStyle = "function") {
|
|
1759
|
+
assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
|
|
1760
|
+
request: "interview",
|
|
1761
|
+
executionStyle,
|
|
1762
|
+
functionName
|
|
1763
|
+
});
|
|
1764
|
+
return this.workerClient.executeCodeInterviewMode(
|
|
1765
|
+
code,
|
|
1766
|
+
functionName,
|
|
1767
|
+
inputs,
|
|
1768
|
+
void 0,
|
|
1769
|
+
executionStyle
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
function createJavaRuntimeClient(workerClient) {
|
|
1774
|
+
return new JavaRuntimeClient(workerClient);
|
|
1775
|
+
}
|
|
1776
|
+
|
|
817
1777
|
// packages/harness-browser/src/pyodide-worker-client.ts
|
|
818
1778
|
var EXECUTION_TIMEOUT_MS2 = 1e4;
|
|
819
1779
|
var INTERVIEW_MODE_TIMEOUT_MS2 = 5e3;
|
|
820
|
-
var
|
|
821
|
-
var
|
|
822
|
-
var
|
|
823
|
-
var
|
|
1780
|
+
var TRACING_TIMEOUT_MS3 = 3e4;
|
|
1781
|
+
var INIT_TIMEOUT_MS3 = 12e4;
|
|
1782
|
+
var MESSAGE_TIMEOUT_MS3 = 2e4;
|
|
1783
|
+
var WORKER_READY_TIMEOUT_MS3 = 1e4;
|
|
824
1784
|
var PyodideWorkerClient = class {
|
|
825
1785
|
constructor(options) {
|
|
826
1786
|
this.options = options;
|
|
@@ -910,14 +1870,14 @@ var PyodideWorkerClient = class {
|
|
|
910
1870
|
if (settled) return;
|
|
911
1871
|
settled = true;
|
|
912
1872
|
const timeoutError = new Error(
|
|
913
|
-
`Python worker failed to initialize in time (${Math.round(
|
|
1873
|
+
`Python worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS3 / 1e3)}s)`
|
|
914
1874
|
);
|
|
915
1875
|
if (this.debug) {
|
|
916
|
-
console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs:
|
|
1876
|
+
console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs: WORKER_READY_TIMEOUT_MS3 });
|
|
917
1877
|
}
|
|
918
1878
|
this.terminateAndReset(timeoutError);
|
|
919
1879
|
reject(timeoutError);
|
|
920
|
-
},
|
|
1880
|
+
}, WORKER_READY_TIMEOUT_MS3);
|
|
921
1881
|
readyPromise.then(() => {
|
|
922
1882
|
if (settled) return;
|
|
923
1883
|
settled = true;
|
|
@@ -934,7 +1894,7 @@ var PyodideWorkerClient = class {
|
|
|
934
1894
|
/**
|
|
935
1895
|
* Send a message to the worker and wait for a response
|
|
936
1896
|
*/
|
|
937
|
-
async sendMessage(type, payload, timeoutMs =
|
|
1897
|
+
async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS3) {
|
|
938
1898
|
const worker = this.getWorker();
|
|
939
1899
|
await this.waitForWorkerReady();
|
|
940
1900
|
const id = String(++this.messageId);
|
|
@@ -1018,7 +1978,7 @@ var PyodideWorkerClient = class {
|
|
|
1018
1978
|
this.isInitializing = true;
|
|
1019
1979
|
this.initPromise = (async () => {
|
|
1020
1980
|
try {
|
|
1021
|
-
return await this.sendMessage("init", void 0,
|
|
1981
|
+
return await this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
|
|
1022
1982
|
} catch (error) {
|
|
1023
1983
|
const message = error instanceof Error ? error.message : String(error);
|
|
1024
1984
|
const shouldRetry = message.includes("Worker request timed out: init") || message.includes("Worker was terminated") || message.includes("Worker error") || message.includes("failed to initialize in time");
|
|
@@ -1029,7 +1989,7 @@ var PyodideWorkerClient = class {
|
|
|
1029
1989
|
console.warn("[PyodideWorkerClient] init failed, resetting worker and retrying once", { message });
|
|
1030
1990
|
}
|
|
1031
1991
|
this.terminateAndReset();
|
|
1032
|
-
return this.sendMessage("init", void 0,
|
|
1992
|
+
return this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
|
|
1033
1993
|
}
|
|
1034
1994
|
})();
|
|
1035
1995
|
try {
|
|
@@ -1056,9 +2016,9 @@ var PyodideWorkerClient = class {
|
|
|
1056
2016
|
inputs,
|
|
1057
2017
|
executionStyle,
|
|
1058
2018
|
options
|
|
1059
|
-
},
|
|
2019
|
+
}, TRACING_TIMEOUT_MS3 + 5e3),
|
|
1060
2020
|
// Message timeout slightly longer than execution timeout
|
|
1061
|
-
|
|
2021
|
+
TRACING_TIMEOUT_MS3
|
|
1062
2022
|
);
|
|
1063
2023
|
} catch (error) {
|
|
1064
2024
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -1068,7 +2028,7 @@ var PyodideWorkerClient = class {
|
|
|
1068
2028
|
success: false,
|
|
1069
2029
|
error: errorMessage,
|
|
1070
2030
|
trace: [],
|
|
1071
|
-
executionTimeMs:
|
|
2031
|
+
executionTimeMs: TRACING_TIMEOUT_MS3,
|
|
1072
2032
|
consoleOutput: [],
|
|
1073
2033
|
traceLimitExceeded: true,
|
|
1074
2034
|
timeoutReason: "client-timeout",
|
|
@@ -1224,6 +2184,7 @@ var DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS = Object.freeze({
|
|
|
1224
2184
|
pythonRuntimeCore: "pyodide/runtime-core.js",
|
|
1225
2185
|
pythonSnippets: "generated-python-harness-snippets.js",
|
|
1226
2186
|
javascriptWorker: "javascript-worker.js",
|
|
2187
|
+
javaWorker: "java-worker.js",
|
|
1227
2188
|
typescriptCompiler: "vendor/typescript.js"
|
|
1228
2189
|
});
|
|
1229
2190
|
function isExplicitAssetPath(pathname) {
|
|
@@ -1257,6 +2218,7 @@ function resolveBrowserHarnessAssets(options = {}) {
|
|
|
1257
2218
|
assetBaseUrl,
|
|
1258
2219
|
assets.javascriptWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javascriptWorker
|
|
1259
2220
|
),
|
|
2221
|
+
javaWorker: resolveAssetPath(assetBaseUrl, assets.javaWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javaWorker),
|
|
1260
2222
|
typescriptCompiler: resolveAssetPath(
|
|
1261
2223
|
assetBaseUrl,
|
|
1262
2224
|
assets.typescriptCompiler ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.typescriptCompiler
|
|
@@ -1270,6 +2232,7 @@ var BrowserHarnessRuntime = class {
|
|
|
1270
2232
|
supportedLanguages = SUPPORTED_LANGUAGES;
|
|
1271
2233
|
pythonWorkerClient;
|
|
1272
2234
|
javaScriptWorkerClient;
|
|
2235
|
+
javaWorkerClient;
|
|
1273
2236
|
clients;
|
|
1274
2237
|
constructor(options = {}) {
|
|
1275
2238
|
this.assets = resolveBrowserHarnessAssets(options);
|
|
@@ -1281,10 +2244,15 @@ var BrowserHarnessRuntime = class {
|
|
|
1281
2244
|
workerUrl: this.assets.javascriptWorker,
|
|
1282
2245
|
debug: options.debug
|
|
1283
2246
|
});
|
|
2247
|
+
this.javaWorkerClient = new JavaWorkerClient({
|
|
2248
|
+
workerUrl: this.assets.javaWorker,
|
|
2249
|
+
debug: options.debug
|
|
2250
|
+
});
|
|
1284
2251
|
this.clients = {
|
|
1285
2252
|
python: createPythonRuntimeClient(this.pythonWorkerClient),
|
|
1286
2253
|
javascript: createJavaScriptRuntimeClient("javascript", this.javaScriptWorkerClient),
|
|
1287
|
-
typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient)
|
|
2254
|
+
typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient),
|
|
2255
|
+
java: createJavaRuntimeClient(this.javaWorkerClient)
|
|
1288
2256
|
};
|
|
1289
2257
|
}
|
|
1290
2258
|
getClient(language) {
|
|
@@ -1308,11 +2276,16 @@ var BrowserHarnessRuntime = class {
|
|
|
1308
2276
|
this.pythonWorkerClient.terminate();
|
|
1309
2277
|
return;
|
|
1310
2278
|
}
|
|
2279
|
+
if (language === "java") {
|
|
2280
|
+
this.javaWorkerClient.terminate();
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
1311
2283
|
this.javaScriptWorkerClient.terminate();
|
|
1312
2284
|
}
|
|
1313
2285
|
dispose() {
|
|
1314
2286
|
this.pythonWorkerClient.terminate();
|
|
1315
2287
|
this.javaScriptWorkerClient.terminate();
|
|
2288
|
+
this.javaWorkerClient.terminate();
|
|
1316
2289
|
}
|
|
1317
2290
|
};
|
|
1318
2291
|
function createBrowserHarness(options = {}) {
|
|
@@ -1415,7 +2388,7 @@ def _serialize(obj, depth=0, node_refs=None):
|
|
|
1415
2388
|
except TypeError:
|
|
1416
2389
|
sorted_vals = [_serialize(x, depth + 1, node_refs) for x in obj]
|
|
1417
2390
|
return {"__type__": "set", "values": sorted_vals}
|
|
1418
|
-
elif (
|
|
2391
|
+
elif isinstance(obj, TreeNode):
|
|
1419
2392
|
obj_ref = id(obj)
|
|
1420
2393
|
if obj_ref in node_refs:
|
|
1421
2394
|
return {"__ref__": node_refs[obj_ref]}
|
|
@@ -1431,7 +2404,7 @@ def _serialize(obj, depth=0, node_refs=None):
|
|
|
1431
2404
|
if hasattr(obj, 'right'):
|
|
1432
2405
|
result["right"] = _serialize(obj.right, depth + 1, node_refs)
|
|
1433
2406
|
return result
|
|
1434
|
-
elif (
|
|
2407
|
+
elif isinstance(obj, ListNode):
|
|
1435
2408
|
obj_ref = id(obj)
|
|
1436
2409
|
if obj_ref in node_refs:
|
|
1437
2410
|
return {"__ref__": node_refs[obj_ref]}
|
|
@@ -1509,14 +2482,14 @@ def _serialize(obj, depth=0):
|
|
|
1509
2482
|
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
1510
2483
|
except TypeError:
|
|
1511
2484
|
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
1512
|
-
elif (
|
|
2485
|
+
elif isinstance(obj, TreeNode):
|
|
1513
2486
|
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
1514
2487
|
if hasattr(obj, 'left'):
|
|
1515
2488
|
result["left"] = _serialize(obj.left, depth + 1)
|
|
1516
2489
|
if hasattr(obj, 'right'):
|
|
1517
2490
|
result["right"] = _serialize(obj.right, depth + 1)
|
|
1518
2491
|
return result
|
|
1519
|
-
elif (
|
|
2492
|
+
elif isinstance(obj, ListNode):
|
|
1520
2493
|
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
1521
2494
|
result["next"] = _serialize(obj.next, depth + 1)
|
|
1522
2495
|
return result
|
|
@@ -1591,14 +2564,14 @@ def _serialize(obj, depth=0):
|
|
|
1591
2564
|
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
1592
2565
|
except TypeError:
|
|
1593
2566
|
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
1594
|
-
elif
|
|
2567
|
+
elif isinstance(obj, TreeNode):
|
|
1595
2568
|
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
|
|
1596
2569
|
if hasattr(obj, 'left'):
|
|
1597
2570
|
result["left"] = _serialize(obj.left, depth + 1)
|
|
1598
2571
|
if hasattr(obj, 'right'):
|
|
1599
2572
|
result["right"] = _serialize(obj.right, depth + 1)
|
|
1600
2573
|
return result
|
|
1601
|
-
elif
|
|
2574
|
+
elif isinstance(obj, ListNode):
|
|
1602
2575
|
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
|
|
1603
2576
|
result["next"] = _serialize(obj.next, depth + 1)
|
|
1604
2577
|
return result
|
|
@@ -1630,14 +2603,14 @@ def _serialize(obj, depth=0):
|
|
|
1630
2603
|
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
1631
2604
|
except TypeError:
|
|
1632
2605
|
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
1633
|
-
elif (
|
|
2606
|
+
elif isinstance(obj, TreeNode):
|
|
1634
2607
|
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
1635
2608
|
if hasattr(obj, 'left'):
|
|
1636
2609
|
result["left"] = _serialize(obj.left, depth + 1)
|
|
1637
2610
|
if hasattr(obj, 'right'):
|
|
1638
2611
|
result["right"] = _serialize(obj.right, depth + 1)
|
|
1639
2612
|
return result
|
|
1640
|
-
elif (
|
|
2613
|
+
elif isinstance(obj, ListNode):
|
|
1641
2614
|
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
1642
2615
|
result["next"] = _serialize(obj.next, depth + 1)
|
|
1643
2616
|
return result
|
|
@@ -1865,7 +2838,7 @@ def _serialize(obj, depth=0, node_refs=None):
|
|
|
1865
2838
|
except TypeError:
|
|
1866
2839
|
sorted_vals = [_serialize(x, depth + 1, node_refs) for x in obj]
|
|
1867
2840
|
return {"__type__": "set", "values": sorted_vals}
|
|
1868
|
-
elif (
|
|
2841
|
+
elif isinstance(obj, TreeNode):
|
|
1869
2842
|
obj_ref = id(obj)
|
|
1870
2843
|
if obj_ref in node_refs:
|
|
1871
2844
|
return {"__ref__": node_refs[obj_ref]}
|
|
@@ -1881,7 +2854,7 @@ def _serialize(obj, depth=0, node_refs=None):
|
|
|
1881
2854
|
if hasattr(obj, 'right'):
|
|
1882
2855
|
result["right"] = _serialize(obj.right, depth + 1, node_refs)
|
|
1883
2856
|
return result
|
|
1884
|
-
elif (
|
|
2857
|
+
elif isinstance(obj, ListNode):
|
|
1885
2858
|
obj_ref = id(obj)
|
|
1886
2859
|
if obj_ref in node_refs:
|
|
1887
2860
|
return {"__ref__": node_refs[obj_ref]}
|
|
@@ -1959,14 +2932,14 @@ def _serialize(obj, depth=0):
|
|
|
1959
2932
|
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
1960
2933
|
except TypeError:
|
|
1961
2934
|
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
1962
|
-
elif (
|
|
2935
|
+
elif isinstance(obj, TreeNode):
|
|
1963
2936
|
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
1964
2937
|
if hasattr(obj, 'left'):
|
|
1965
2938
|
result["left"] = _serialize(obj.left, depth + 1)
|
|
1966
2939
|
if hasattr(obj, 'right'):
|
|
1967
2940
|
result["right"] = _serialize(obj.right, depth + 1)
|
|
1968
2941
|
return result
|
|
1969
|
-
elif (
|
|
2942
|
+
elif isinstance(obj, ListNode):
|
|
1970
2943
|
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
1971
2944
|
result["next"] = _serialize(obj.next, depth + 1)
|
|
1972
2945
|
return result
|
|
@@ -2041,14 +3014,14 @@ def _serialize(obj, depth=0):
|
|
|
2041
3014
|
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
2042
3015
|
except TypeError:
|
|
2043
3016
|
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
2044
|
-
elif
|
|
3017
|
+
elif isinstance(obj, TreeNode):
|
|
2045
3018
|
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
|
|
2046
3019
|
if hasattr(obj, 'left'):
|
|
2047
3020
|
result["left"] = _serialize(obj.left, depth + 1)
|
|
2048
3021
|
if hasattr(obj, 'right'):
|
|
2049
3022
|
result["right"] = _serialize(obj.right, depth + 1)
|
|
2050
3023
|
return result
|
|
2051
|
-
elif
|
|
3024
|
+
elif isinstance(obj, ListNode):
|
|
2052
3025
|
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
|
|
2053
3026
|
result["next"] = _serialize(obj.next, depth + 1)
|
|
2054
3027
|
return result
|
|
@@ -2142,16 +3115,17 @@ function createConsoleProxy(output) {
|
|
|
2142
3115
|
}
|
|
2143
3116
|
function isLikelyTreeNodeValue(value) {
|
|
2144
3117
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
2145
|
-
const
|
|
2146
|
-
|
|
2147
|
-
|
|
3118
|
+
const record = value;
|
|
3119
|
+
if (record.__type__ === "TreeNode") return true;
|
|
3120
|
+
const ctor = value.constructor;
|
|
3121
|
+
return ctor?.name === "TreeNode";
|
|
2148
3122
|
}
|
|
2149
3123
|
function isLikelyListNodeValue(value) {
|
|
2150
3124
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
2151
|
-
const
|
|
2152
|
-
|
|
2153
|
-
const
|
|
2154
|
-
return
|
|
3125
|
+
const record = value;
|
|
3126
|
+
if (record.__type__ === "ListNode") return true;
|
|
3127
|
+
const ctor = value.constructor;
|
|
3128
|
+
return ctor?.name === "ListNode";
|
|
2155
3129
|
}
|
|
2156
3130
|
function getCustomClassName(value) {
|
|
2157
3131
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
@@ -2206,22 +3180,25 @@ function serializeValue(value, depth = 0, seen = /* @__PURE__ */ new WeakSet(),
|
|
|
2206
3180
|
const nodePrefix = isTree ? "tree" : "list";
|
|
2207
3181
|
const nodeId = `${nodePrefix}-${nodeRefState.nextId++}`;
|
|
2208
3182
|
nodeRefState.ids.set(objectValue, nodeId);
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
};
|
|
2217
|
-
}
|
|
2218
|
-
return {
|
|
3183
|
+
const out2 = isTree ? {
|
|
3184
|
+
__type__: "TreeNode",
|
|
3185
|
+
__id__: nodeId,
|
|
3186
|
+
val: serializeValue(nodeValue.val ?? nodeValue.value ?? null, depth + 1, seen, nodeRefState),
|
|
3187
|
+
left: serializeValue(nodeValue.left ?? null, depth + 1, seen, nodeRefState),
|
|
3188
|
+
right: serializeValue(nodeValue.right ?? null, depth + 1, seen, nodeRefState)
|
|
3189
|
+
} : {
|
|
2219
3190
|
__type__: "ListNode",
|
|
2220
3191
|
__id__: nodeId,
|
|
2221
3192
|
val: serializeValue(nodeValue.val ?? nodeValue.value ?? null, depth + 1, seen, nodeRefState),
|
|
2222
3193
|
next: serializeValue(nodeValue.next ?? null, depth + 1, seen, nodeRefState),
|
|
2223
3194
|
..."prev" in nodeValue ? { prev: serializeValue(nodeValue.prev ?? null, depth + 1, seen, nodeRefState) } : {}
|
|
2224
3195
|
};
|
|
3196
|
+
const skipped = isTree ? /* @__PURE__ */ new Set(["__id__", "__type__", "__class__", "val", "value", "left", "right"]) : /* @__PURE__ */ new Set(["__id__", "__type__", "__class__", "val", "value", "next", "prev"]);
|
|
3197
|
+
for (const [k, v] of Object.entries(nodeValue)) {
|
|
3198
|
+
if (skipped.has(k)) continue;
|
|
3199
|
+
out2[k] = serializeValue(v, depth + 1, seen, nodeRefState);
|
|
3200
|
+
}
|
|
3201
|
+
return out2;
|
|
2225
3202
|
}
|
|
2226
3203
|
const customClassName = getCustomClassName(value);
|
|
2227
3204
|
if (customClassName) {
|
|
@@ -2385,21 +3362,31 @@ function materializeTreeInput(value) {
|
|
|
2385
3362
|
}
|
|
2386
3363
|
const record = value;
|
|
2387
3364
|
if (isLikelyTreeNodeValue(record)) {
|
|
2388
|
-
|
|
3365
|
+
const node = {
|
|
2389
3366
|
val: record.val ?? record.value ?? null,
|
|
2390
3367
|
value: record.val ?? record.value ?? null,
|
|
2391
3368
|
left: materializeTreeInput(record.left ?? null),
|
|
2392
3369
|
right: materializeTreeInput(record.right ?? null)
|
|
2393
3370
|
};
|
|
3371
|
+
for (const [key, nested] of Object.entries(record)) {
|
|
3372
|
+
if (key === "__id__" || key === "__type__" || key === "val" || key === "value" || key === "left" || key === "right") continue;
|
|
3373
|
+
node[key] = materializeTreeInput(nested);
|
|
3374
|
+
}
|
|
3375
|
+
return node;
|
|
2394
3376
|
}
|
|
2395
3377
|
const taggedRecord = value;
|
|
2396
3378
|
if (taggedRecord.__type__ === "TreeNode") {
|
|
2397
|
-
|
|
3379
|
+
const node = {
|
|
2398
3380
|
val: taggedRecord.val ?? taggedRecord.value ?? null,
|
|
2399
3381
|
value: taggedRecord.val ?? taggedRecord.value ?? null,
|
|
2400
3382
|
left: materializeTreeInput(taggedRecord.left ?? null),
|
|
2401
3383
|
right: materializeTreeInput(taggedRecord.right ?? null)
|
|
2402
3384
|
};
|
|
3385
|
+
for (const [key, nested] of Object.entries(taggedRecord)) {
|
|
3386
|
+
if (key === "__id__" || key === "__type__" || key === "val" || key === "value" || key === "left" || key === "right") continue;
|
|
3387
|
+
node[key] = materializeTreeInput(nested);
|
|
3388
|
+
}
|
|
3389
|
+
return node;
|
|
2403
3390
|
}
|
|
2404
3391
|
return value;
|
|
2405
3392
|
}
|
|
@@ -2443,6 +3430,10 @@ function materializeListInput(value, refs = /* @__PURE__ */ new Map(), materiali
|
|
|
2443
3430
|
refs.set(taggedRecord.__id__, node);
|
|
2444
3431
|
}
|
|
2445
3432
|
node.next = materializeListInput(taggedRecord.next ?? null, refs, materialized);
|
|
3433
|
+
for (const [key, nested] of Object.entries(taggedRecord)) {
|
|
3434
|
+
if (key === "__id__" || key === "__type__" || key === "__class__" || key === "val" || key === "value" || key === "next") continue;
|
|
3435
|
+
node[key] = materializeListInput(nested, refs, materialized);
|
|
3436
|
+
}
|
|
2446
3437
|
return node;
|
|
2447
3438
|
}
|
|
2448
3439
|
return value;
|
|
@@ -2806,9 +3797,13 @@ export {
|
|
|
2806
3797
|
TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION,
|
|
2807
3798
|
TYPESCRIPT_RUNTIME_DECLARATIONS,
|
|
2808
3799
|
adaptJavaScriptTraceExecutionResult,
|
|
3800
|
+
adaptJavaTraceExecutionResult as adaptJavaSpikeTraceExecutionResult,
|
|
3801
|
+
adaptJavaTraceExecutionResult,
|
|
2809
3802
|
adaptPythonTraceExecutionResult,
|
|
2810
3803
|
adaptTraceExecutionResult,
|
|
2811
3804
|
assertRuntimeRequestSupported,
|
|
3805
|
+
buildJavaExecutionResult,
|
|
3806
|
+
buildJavaExecutionResult as buildJavaSpikeExecutionResult,
|
|
2812
3807
|
createBrowserHarness,
|
|
2813
3808
|
executeJavaScriptCode,
|
|
2814
3809
|
executeJavaScriptWithTracing,
|
|
@@ -2820,6 +3815,8 @@ export {
|
|
|
2820
3815
|
getSupportedLanguageProfiles,
|
|
2821
3816
|
identifyConversions,
|
|
2822
3817
|
isLanguageSupported,
|
|
3818
|
+
normalizeJavaTraceContract as normalizeJavaSpikeTraceContract,
|
|
3819
|
+
normalizeJavaTraceContract,
|
|
2823
3820
|
normalizeRuntimeTraceContract,
|
|
2824
3821
|
resolveBrowserHarnessAssets,
|
|
2825
3822
|
stableStringifyRuntimeTraceContract,
|