@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/core.cjs
CHANGED
|
@@ -22,15 +22,21 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION: () => RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION,
|
|
24
24
|
adaptJavaScriptTraceExecutionResult: () => adaptJavaScriptTraceExecutionResult,
|
|
25
|
+
adaptJavaSpikeTraceExecutionResult: () => adaptJavaTraceExecutionResult,
|
|
26
|
+
adaptJavaTraceExecutionResult: () => adaptJavaTraceExecutionResult,
|
|
25
27
|
adaptPythonTraceExecutionResult: () => adaptPythonTraceExecutionResult,
|
|
26
28
|
adaptTraceExecutionResult: () => adaptTraceExecutionResult,
|
|
29
|
+
buildJavaExecutionResult: () => buildJavaExecutionResult,
|
|
30
|
+
buildJavaSpikeExecutionResult: () => buildJavaExecutionResult,
|
|
31
|
+
normalizeJavaSpikeTraceContract: () => normalizeJavaTraceContract,
|
|
32
|
+
normalizeJavaTraceContract: () => normalizeJavaTraceContract,
|
|
27
33
|
normalizeRuntimeTraceContract: () => normalizeRuntimeTraceContract,
|
|
28
34
|
stableStringifyRuntimeTraceContract: () => stableStringifyRuntimeTraceContract
|
|
29
35
|
});
|
|
30
36
|
module.exports = __toCommonJS(src_exports);
|
|
31
37
|
|
|
32
38
|
// packages/harness-core/src/trace-contract.ts
|
|
33
|
-
var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-
|
|
39
|
+
var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-04-21";
|
|
34
40
|
var TRACE_EVENTS = /* @__PURE__ */ new Set([
|
|
35
41
|
"line",
|
|
36
42
|
"call",
|
|
@@ -151,7 +157,39 @@ function normalizeAccesses(accesses) {
|
|
|
151
157
|
}
|
|
152
158
|
return payload;
|
|
153
159
|
}).filter((access) => access !== null);
|
|
154
|
-
|
|
160
|
+
if (normalized.length === 0) {
|
|
161
|
+
return void 0;
|
|
162
|
+
}
|
|
163
|
+
const statsByVariable = /* @__PURE__ */ new Map();
|
|
164
|
+
for (const access of normalized) {
|
|
165
|
+
const stats = statsByVariable.get(access.variable) ?? { hasCellRead: false, hasCellWrite: false };
|
|
166
|
+
if (access.kind === "cell-read") stats.hasCellRead = true;
|
|
167
|
+
if (access.kind === "cell-write") stats.hasCellWrite = true;
|
|
168
|
+
statsByVariable.set(access.variable, stats);
|
|
169
|
+
}
|
|
170
|
+
const deduped = /* @__PURE__ */ new Set();
|
|
171
|
+
const collapsed = normalized.filter((access) => {
|
|
172
|
+
const stats = statsByVariable.get(access.variable);
|
|
173
|
+
if (access.kind === "indexed-read" && (stats?.hasCellRead || stats?.hasCellWrite)) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
if (access.kind === "indexed-write" && stats?.hasCellWrite) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
const key = JSON.stringify([
|
|
180
|
+
access.variable,
|
|
181
|
+
access.kind,
|
|
182
|
+
access.indices ?? null,
|
|
183
|
+
access.pathDepth ?? null,
|
|
184
|
+
access.method ?? null
|
|
185
|
+
]);
|
|
186
|
+
if (deduped.has(key)) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
deduped.add(key);
|
|
190
|
+
return true;
|
|
191
|
+
});
|
|
192
|
+
return collapsed.length > 0 ? collapsed : void 0;
|
|
155
193
|
}
|
|
156
194
|
function normalizeRecord(value) {
|
|
157
195
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
@@ -215,8 +253,64 @@ function normalizeTraceStep(step) {
|
|
|
215
253
|
...normalizedVisualization ? { visualization: normalizedVisualization } : {}
|
|
216
254
|
};
|
|
217
255
|
}
|
|
256
|
+
function collapseTraceAccessNoise(trace) {
|
|
257
|
+
const variablesWithCellAccess = /* @__PURE__ */ new Set();
|
|
258
|
+
const accessStatsByVariable = /* @__PURE__ */ new Map();
|
|
259
|
+
for (const step of trace) {
|
|
260
|
+
for (const access of step.accesses ?? []) {
|
|
261
|
+
const stats = accessStatsByVariable.get(access.variable) ?? {
|
|
262
|
+
hasCellRead: false,
|
|
263
|
+
hasCellWrite: false,
|
|
264
|
+
hasMutatingCall: false,
|
|
265
|
+
hasIndexedWrite: false
|
|
266
|
+
};
|
|
267
|
+
if (access.kind === "cell-read" || access.kind === "cell-write") {
|
|
268
|
+
variablesWithCellAccess.add(access.variable);
|
|
269
|
+
}
|
|
270
|
+
if (access.kind === "cell-read") stats.hasCellRead = true;
|
|
271
|
+
if (access.kind === "cell-write") stats.hasCellWrite = true;
|
|
272
|
+
if (access.kind === "mutating-call") stats.hasMutatingCall = true;
|
|
273
|
+
if (access.kind === "indexed-write") stats.hasIndexedWrite = true;
|
|
274
|
+
accessStatsByVariable.set(access.variable, stats);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (variablesWithCellAccess.size === 0) {
|
|
278
|
+
return trace;
|
|
279
|
+
}
|
|
280
|
+
return trace.map((step) => {
|
|
281
|
+
if (!step.accesses?.length) {
|
|
282
|
+
return step;
|
|
283
|
+
}
|
|
284
|
+
const filtered = step.accesses.filter((access) => {
|
|
285
|
+
const stats = accessStatsByVariable.get(access.variable);
|
|
286
|
+
if (variablesWithCellAccess.has(access.variable)) {
|
|
287
|
+
return access.kind !== "indexed-read" && access.kind !== "indexed-write";
|
|
288
|
+
}
|
|
289
|
+
if (access.kind === "mutating-call" && stats?.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
if (access.kind === "indexed-read" && stats?.hasMutatingCall && !stats.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
return true;
|
|
296
|
+
});
|
|
297
|
+
if (filtered.length === step.accesses.length) {
|
|
298
|
+
return step;
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
...step,
|
|
302
|
+
...filtered.length > 0 ? { accesses: filtered } : {},
|
|
303
|
+
...filtered.length === 0 ? { accesses: void 0 } : {}
|
|
304
|
+
};
|
|
305
|
+
});
|
|
306
|
+
}
|
|
218
307
|
function normalizeRuntimeTraceContract(language, result) {
|
|
219
|
-
const
|
|
308
|
+
const rawNormalizedTrace = collapseTraceAccessNoise(
|
|
309
|
+
Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : []
|
|
310
|
+
);
|
|
311
|
+
const maxTraceSteps = typeof result.maxTraceSteps === "number" && Number.isFinite(result.maxTraceSteps) ? Math.max(1, Math.floor(result.maxTraceSteps)) : void 0;
|
|
312
|
+
const traceWasClipped = maxTraceSteps !== void 0 && rawNormalizedTrace.length > maxTraceSteps;
|
|
313
|
+
const normalizedTrace = traceWasClipped && maxTraceSteps !== void 0 ? rawNormalizedTrace.slice(0, maxTraceSteps) : rawNormalizedTrace;
|
|
220
314
|
const lineEventCount = typeof result.lineEventCount === "number" && Number.isFinite(result.lineEventCount) ? Math.floor(result.lineEventCount) : normalizedTrace.filter((step) => step.event === "line").length;
|
|
221
315
|
const normalizedConsole = Array.isArray(result.consoleOutput) ? result.consoleOutput.map((line) => String(line)) : [];
|
|
222
316
|
return {
|
|
@@ -228,7 +322,7 @@ function normalizeRuntimeTraceContract(language, result) {
|
|
|
228
322
|
...typeof result.errorLine === "number" && Number.isFinite(result.errorLine) ? { errorLine: Math.floor(result.errorLine) } : {},
|
|
229
323
|
consoleOutput: normalizedConsole,
|
|
230
324
|
trace: normalizedTrace,
|
|
231
|
-
...result.traceLimitExceeded !== void 0 ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) } : {},
|
|
325
|
+
...result.traceLimitExceeded !== void 0 || traceWasClipped ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) || traceWasClipped } : {},
|
|
232
326
|
...typeof result.timeoutReason === "string" && result.timeoutReason.length > 0 ? { timeoutReason: result.timeoutReason } : {},
|
|
233
327
|
lineEventCount: Math.max(0, lineEventCount),
|
|
234
328
|
traceStepCount: normalizedTrace.length
|
|
@@ -286,12 +380,525 @@ function adaptPythonTraceExecutionResult(result) {
|
|
|
286
380
|
function adaptJavaScriptTraceExecutionResult(language, result) {
|
|
287
381
|
return adaptTraceExecutionResult(language, result);
|
|
288
382
|
}
|
|
383
|
+
|
|
384
|
+
// packages/harness-core/src/trace-adapters/java.ts
|
|
385
|
+
function parseScalar(raw) {
|
|
386
|
+
if (raw === "null") return null;
|
|
387
|
+
if (raw === "true") return true;
|
|
388
|
+
if (raw === "false") return false;
|
|
389
|
+
if (/^-?\d+$/.test(raw)) return Number.parseInt(raw, 10);
|
|
390
|
+
if (/^-?\d+\.\d+$/.test(raw)) return Number.parseFloat(raw);
|
|
391
|
+
if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("[") && raw.endsWith("]") || raw.startsWith("{") && raw.endsWith("}")) {
|
|
392
|
+
try {
|
|
393
|
+
return JSON.parse(raw);
|
|
394
|
+
} catch {
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return raw;
|
|
398
|
+
}
|
|
399
|
+
function parseKeyValuePairs(fragment) {
|
|
400
|
+
const variables = {};
|
|
401
|
+
const matches = Array.from(fragment.matchAll(/\b([A-Za-z_][A-Za-z0-9_.]*)=/g));
|
|
402
|
+
for (let index = 0; index < matches.length; index += 1) {
|
|
403
|
+
const match = matches[index];
|
|
404
|
+
const rawKey = match[1];
|
|
405
|
+
const valueStart = (match.index ?? 0) + match[0].length;
|
|
406
|
+
const valueEnd = index + 1 < matches.length ? matches[index + 1].index ?? fragment.length : fragment.length;
|
|
407
|
+
const rawValue = fragment.slice(valueStart, valueEnd).trim();
|
|
408
|
+
if (!rawKey || rawValue === void 0) continue;
|
|
409
|
+
if (rawKey === "method") continue;
|
|
410
|
+
variables[rawKey.replaceAll(".", "_")] = parseScalar(rawValue);
|
|
411
|
+
}
|
|
412
|
+
return variables;
|
|
413
|
+
}
|
|
414
|
+
function extractLineMetadata(event) {
|
|
415
|
+
const match = event.match(/^line=(\d+)(?:\s+(.*))?$/);
|
|
416
|
+
if (!match) {
|
|
417
|
+
return { line: 1, payload: event };
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
line: Number.parseInt(match[1], 10),
|
|
421
|
+
payload: match[2] ?? ""
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function stripInlineComments(line, inBlockComment) {
|
|
425
|
+
let result = "";
|
|
426
|
+
let index = 0;
|
|
427
|
+
let inBlock = inBlockComment;
|
|
428
|
+
while (index < line.length) {
|
|
429
|
+
const current = line[index];
|
|
430
|
+
const next = index + 1 < line.length ? line[index + 1] : "";
|
|
431
|
+
if (inBlock) {
|
|
432
|
+
if (current === "*" && next === "/") {
|
|
433
|
+
inBlock = false;
|
|
434
|
+
index += 2;
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
index += 1;
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
if (current === "/" && next === "*") {
|
|
441
|
+
inBlock = true;
|
|
442
|
+
index += 2;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (current === "/" && next === "/") {
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
result += current;
|
|
449
|
+
index += 1;
|
|
450
|
+
}
|
|
451
|
+
return { text: result, inBlockComment: inBlock };
|
|
452
|
+
}
|
|
453
|
+
function isMethodDeclarationLine(line) {
|
|
454
|
+
const trimmed = line.trim();
|
|
455
|
+
if (!trimmed) return false;
|
|
456
|
+
if (trimmed.startsWith("@")) return false;
|
|
457
|
+
if (!trimmed.includes("(") || !trimmed.includes(")")) return false;
|
|
458
|
+
if (trimmed.endsWith(";")) return false;
|
|
459
|
+
if (trimmed.includes("->")) return false;
|
|
460
|
+
if (/^(?:if|for|while|switch|catch|do|try|else|return|throw|new)\b/.test(trimmed)) {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
if (!/[A-Za-z_][A-Za-z0-9_]*\s*\([^{};]*\)/.test(trimmed)) {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
return /(?:\{\s*)?$/.test(trimmed);
|
|
467
|
+
}
|
|
468
|
+
function buildLineRemap(sourceText) {
|
|
469
|
+
if (typeof sourceText !== "string" || sourceText.length === 0) {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
const lines = sourceText.split(/\r?\n/);
|
|
473
|
+
const executable = /* @__PURE__ */ new Set();
|
|
474
|
+
let inBlockComment = false;
|
|
475
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
476
|
+
const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
|
|
477
|
+
inBlockComment = nextInBlockComment;
|
|
478
|
+
if (text.trim().length > 0) {
|
|
479
|
+
executable.add(index + 1);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
if (executable.size === 0) {
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
const nextExecutableAtOrAfter = new Array(lines.length + 2).fill(null);
|
|
486
|
+
let nextExecutable = null;
|
|
487
|
+
for (let line = lines.length; line >= 1; line -= 1) {
|
|
488
|
+
if (executable.has(line)) {
|
|
489
|
+
nextExecutable = line;
|
|
490
|
+
}
|
|
491
|
+
nextExecutableAtOrAfter[line] = nextExecutable;
|
|
492
|
+
}
|
|
493
|
+
const previousExecutableAtOrBefore = new Array(lines.length + 2).fill(null);
|
|
494
|
+
let previousExecutable = null;
|
|
495
|
+
for (let line = 1; line <= lines.length; line += 1) {
|
|
496
|
+
if (executable.has(line)) {
|
|
497
|
+
previousExecutable = line;
|
|
498
|
+
}
|
|
499
|
+
previousExecutableAtOrBefore[line] = previousExecutable;
|
|
500
|
+
}
|
|
501
|
+
const remap = /* @__PURE__ */ new Map();
|
|
502
|
+
for (let line = 1; line <= lines.length; line += 1) {
|
|
503
|
+
if (executable.has(line)) continue;
|
|
504
|
+
const forward = nextExecutableAtOrAfter[line];
|
|
505
|
+
const backward = previousExecutableAtOrBefore[line];
|
|
506
|
+
const target = forward ?? backward;
|
|
507
|
+
if (target !== null && target !== line) {
|
|
508
|
+
remap.set(line, target);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return remap;
|
|
512
|
+
}
|
|
513
|
+
function buildMethodDeclarationLineSet(sourceText) {
|
|
514
|
+
if (typeof sourceText !== "string" || sourceText.length === 0) {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
const declarationLines = /* @__PURE__ */ new Set();
|
|
518
|
+
const lines = sourceText.split(/\r?\n/);
|
|
519
|
+
let inBlockComment = false;
|
|
520
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
521
|
+
const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
|
|
522
|
+
inBlockComment = nextInBlockComment;
|
|
523
|
+
if (isMethodDeclarationLine(text)) {
|
|
524
|
+
declarationLines.add(index + 1);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return declarationLines;
|
|
528
|
+
}
|
|
529
|
+
function parseAccessEvent(payload) {
|
|
530
|
+
const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
|
|
531
|
+
const cellRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
|
|
532
|
+
if (cellRead) {
|
|
533
|
+
return [{
|
|
534
|
+
variable: cellRead[1],
|
|
535
|
+
kind: "cell-read",
|
|
536
|
+
indices: [Number.parseInt(cellRead[2], 10), Number.parseInt(cellRead[3], 10)],
|
|
537
|
+
pathDepth: 2
|
|
538
|
+
}];
|
|
539
|
+
}
|
|
540
|
+
const indexedRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
|
|
541
|
+
if (indexedRead) {
|
|
542
|
+
return [{
|
|
543
|
+
variable: indexedRead[1],
|
|
544
|
+
kind: "indexed-read",
|
|
545
|
+
indices: [Number.parseInt(indexedRead[2], 10)],
|
|
546
|
+
pathDepth: 1
|
|
547
|
+
}];
|
|
548
|
+
}
|
|
549
|
+
const cellWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
|
|
550
|
+
if (cellWrite) {
|
|
551
|
+
return [{
|
|
552
|
+
variable: cellWrite[1],
|
|
553
|
+
kind: "cell-write",
|
|
554
|
+
indices: [Number.parseInt(cellWrite[2], 10), Number.parseInt(cellWrite[3], 10)],
|
|
555
|
+
pathDepth: 2
|
|
556
|
+
}];
|
|
557
|
+
}
|
|
558
|
+
const indexedWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
|
|
559
|
+
if (indexedWrite) {
|
|
560
|
+
if (isEphemeralOutputArrayName(indexedWrite[1])) {
|
|
561
|
+
return void 0;
|
|
562
|
+
}
|
|
563
|
+
return [{
|
|
564
|
+
variable: indexedWrite[1],
|
|
565
|
+
kind: "indexed-write",
|
|
566
|
+
indices: [Number.parseInt(indexedWrite[2], 10)],
|
|
567
|
+
pathDepth: 1
|
|
568
|
+
}];
|
|
569
|
+
}
|
|
570
|
+
const mutatingCall = payload.match(/^mutate ([A-Za-z_][A-Za-z0-9_]*) method=([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
571
|
+
if (mutatingCall) {
|
|
572
|
+
return [{
|
|
573
|
+
variable: mutatingCall[1],
|
|
574
|
+
kind: "mutating-call",
|
|
575
|
+
method: mutatingCall[2],
|
|
576
|
+
pathDepth: 1
|
|
577
|
+
}];
|
|
578
|
+
}
|
|
579
|
+
return void 0;
|
|
580
|
+
}
|
|
581
|
+
function parseStructureState(payload) {
|
|
582
|
+
const match = payload.match(/^state (linked-list|tree) ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
|
|
583
|
+
if (!match) return null;
|
|
584
|
+
return {
|
|
585
|
+
structure: match[1],
|
|
586
|
+
variable: match[2],
|
|
587
|
+
value: JSON.parse(match[3])
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function parseObjectState(payload) {
|
|
591
|
+
const match = payload.match(/^object-state ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
|
|
592
|
+
if (!match) return null;
|
|
593
|
+
return {
|
|
594
|
+
variable: match[1],
|
|
595
|
+
visualization: JSON.parse(match[2])
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function parseObjectFieldEvent(payload) {
|
|
599
|
+
const match = payload.match(/^(access|write) ([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
|
|
600
|
+
if (!match) return null;
|
|
601
|
+
return {
|
|
602
|
+
variable: match[2],
|
|
603
|
+
field: match[3],
|
|
604
|
+
value: parseScalar(match[4])
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
function buildFieldVisualization(event) {
|
|
608
|
+
return {
|
|
609
|
+
objectKinds: {
|
|
610
|
+
[event.variable]: "object"
|
|
611
|
+
},
|
|
612
|
+
hashMaps: [
|
|
613
|
+
{
|
|
614
|
+
name: event.variable,
|
|
615
|
+
kind: "object",
|
|
616
|
+
objectClassName: event.field === "next" || event.field === "prev" ? "ListNode" : event.field === "left" || event.field === "right" ? "TreeNode" : void 0,
|
|
617
|
+
objectId: `${event.variable}-object`,
|
|
618
|
+
highlightedKey: event.field,
|
|
619
|
+
entries: [{ key: event.field, value: event.value, highlight: true }]
|
|
620
|
+
}
|
|
621
|
+
]
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
function callStacksEqual(left, right) {
|
|
625
|
+
return JSON.stringify(left ?? []) === JSON.stringify(right ?? []);
|
|
626
|
+
}
|
|
627
|
+
function mergeVisualizationPayloads(left, right) {
|
|
628
|
+
if (!left) return right;
|
|
629
|
+
if (!right) return left;
|
|
630
|
+
return {
|
|
631
|
+
...left,
|
|
632
|
+
...right,
|
|
633
|
+
objectKinds: {
|
|
634
|
+
...left.objectKinds ?? {},
|
|
635
|
+
...right.objectKinds ?? {}
|
|
636
|
+
},
|
|
637
|
+
hashMaps: [
|
|
638
|
+
...left.hashMaps ?? [],
|
|
639
|
+
...right.hashMaps ?? []
|
|
640
|
+
]
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
function maybeMergeConsecutiveLineStep(trace, nextStep) {
|
|
644
|
+
if (nextStep.event !== "line") {
|
|
645
|
+
return false;
|
|
646
|
+
}
|
|
647
|
+
const previous = trace.at(-1);
|
|
648
|
+
if (!previous || previous.event !== "line") {
|
|
649
|
+
return false;
|
|
650
|
+
}
|
|
651
|
+
if (previous.line !== nextStep.line || previous.function !== nextStep.function) {
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
if (!callStacksEqual(previous.callStack, nextStep.callStack)) {
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
previous.variables = { ...previous.variables ?? {}, ...nextStep.variables ?? {} };
|
|
658
|
+
if (nextStep.accesses?.length) {
|
|
659
|
+
previous.accesses = [...previous.accesses ?? [], ...nextStep.accesses];
|
|
660
|
+
}
|
|
661
|
+
previous.visualization = mergeVisualizationPayloads(previous.visualization, nextStep.visualization);
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
function filterStructuredVariables(variables) {
|
|
665
|
+
if (!variables) {
|
|
666
|
+
return void 0;
|
|
667
|
+
}
|
|
668
|
+
const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
|
|
669
|
+
const entries = Object.entries(variables).filter(([name, value]) => {
|
|
670
|
+
if (value === null || typeof value !== "object") {
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
if (!Array.isArray(value)) {
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
676
|
+
if (Array.isArray(value[0])) {
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
679
|
+
return !isEphemeralOutputArrayName(name);
|
|
680
|
+
});
|
|
681
|
+
if (entries.length === 0) {
|
|
682
|
+
return void 0;
|
|
683
|
+
}
|
|
684
|
+
return Object.fromEntries(entries);
|
|
685
|
+
}
|
|
686
|
+
function appendJavaTraceStep(trace, step, pendingAccesses) {
|
|
687
|
+
const nextStep = pendingAccesses.length > 0 ? { ...step, accesses: [...pendingAccesses] } : step;
|
|
688
|
+
pendingAccesses.length = 0;
|
|
689
|
+
if (!maybeMergeConsecutiveLineStep(trace, nextStep)) {
|
|
690
|
+
trace.push(nextStep);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, patch) {
|
|
694
|
+
const candidate = trace.at(-1);
|
|
695
|
+
if (!candidate || candidate.event !== "line") {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
if (candidate.line !== line || candidate.function !== currentFunction) {
|
|
699
|
+
return false;
|
|
700
|
+
}
|
|
701
|
+
if (!callStacksEqual(candidate.callStack, currentCallStack)) {
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
candidate.variables = { ...candidate.variables ?? {}, ...patch.variables ?? {} };
|
|
705
|
+
if (patch.accesses?.length) {
|
|
706
|
+
candidate.accesses = [...candidate.accesses ?? [], ...patch.accesses];
|
|
707
|
+
}
|
|
708
|
+
candidate.visualization = mergeVisualizationPayloads(candidate.visualization, patch.visualization);
|
|
709
|
+
return true;
|
|
710
|
+
}
|
|
711
|
+
function mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses) {
|
|
712
|
+
return mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
|
|
713
|
+
variables: void 0,
|
|
714
|
+
accesses,
|
|
715
|
+
visualization: void 0
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
function eventsToRawTrace(events, sourceText) {
|
|
719
|
+
const trace = [];
|
|
720
|
+
const variables = {};
|
|
721
|
+
const objectKinds = {};
|
|
722
|
+
const stack = [];
|
|
723
|
+
const pendingAccesses = [];
|
|
724
|
+
let currentFunction = "<module>";
|
|
725
|
+
const lineRemap = buildLineRemap(sourceText);
|
|
726
|
+
const declarationLines = buildMethodDeclarationLineSet(sourceText);
|
|
727
|
+
for (const rawEvent of events) {
|
|
728
|
+
if (rawEvent === "clear" || rawEvent === "reset") continue;
|
|
729
|
+
const metadata = extractLineMetadata(rawEvent);
|
|
730
|
+
const line = lineRemap?.get(metadata.line) ?? metadata.line;
|
|
731
|
+
const payload = metadata.payload;
|
|
732
|
+
const isDeclarationLine = declarationLines?.has(line) === true;
|
|
733
|
+
if (payload.startsWith("call ")) {
|
|
734
|
+
const match = payload.match(/^call\s+(\S+)(?:\s+(.*))?$/);
|
|
735
|
+
const functionName = match?.[1] ?? currentFunction;
|
|
736
|
+
const argsFragment = match?.[2] ?? "";
|
|
737
|
+
Object.assign(variables, parseKeyValuePairs(argsFragment));
|
|
738
|
+
currentFunction = functionName || currentFunction;
|
|
739
|
+
stack.push({ function: currentFunction, line });
|
|
740
|
+
appendJavaTraceStep(trace, {
|
|
741
|
+
line,
|
|
742
|
+
event: "call",
|
|
743
|
+
function: currentFunction,
|
|
744
|
+
variables: { ...variables },
|
|
745
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
|
|
746
|
+
}, pendingAccesses);
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
if (payload.startsWith("return ")) {
|
|
750
|
+
const match = payload.match(/^return\s+(\S+)$/);
|
|
751
|
+
const functionName = match?.[1] ?? currentFunction;
|
|
752
|
+
const returnVariables = functionName === "<module>" ? { ...variables } : filterStructuredVariables(variables) ?? {};
|
|
753
|
+
appendJavaTraceStep(trace, {
|
|
754
|
+
line,
|
|
755
|
+
event: "return",
|
|
756
|
+
function: functionName || currentFunction,
|
|
757
|
+
variables: returnVariables,
|
|
758
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
|
|
759
|
+
}, pendingAccesses);
|
|
760
|
+
stack.pop();
|
|
761
|
+
currentFunction = stack[stack.length - 1]?.function ?? "<module>";
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
if (isDeclarationLine) {
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (payload.length === 0) {
|
|
768
|
+
appendJavaTraceStep(trace, {
|
|
769
|
+
line,
|
|
770
|
+
event: "line",
|
|
771
|
+
function: currentFunction,
|
|
772
|
+
variables: { ...variables },
|
|
773
|
+
...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
|
|
774
|
+
}, pendingAccesses);
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
const structureState = parseStructureState(payload);
|
|
778
|
+
if (structureState) {
|
|
779
|
+
variables[structureState.variable] = structureState.value;
|
|
780
|
+
objectKinds[structureState.variable] = structureState.structure;
|
|
781
|
+
appendJavaTraceStep(trace, {
|
|
782
|
+
line,
|
|
783
|
+
event: "line",
|
|
784
|
+
function: currentFunction,
|
|
785
|
+
variables: { ...variables },
|
|
786
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
|
|
787
|
+
visualization: {
|
|
788
|
+
objectKinds: { ...objectKinds }
|
|
789
|
+
}
|
|
790
|
+
}, pendingAccesses);
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
const objectState = parseObjectState(payload);
|
|
794
|
+
if (objectState) {
|
|
795
|
+
variables[objectState.variable] = { __ref__: objectState.visualization.objectId ?? `${objectState.variable}-object` };
|
|
796
|
+
appendJavaTraceStep(trace, {
|
|
797
|
+
line,
|
|
798
|
+
event: "line",
|
|
799
|
+
function: currentFunction,
|
|
800
|
+
variables: { ...variables },
|
|
801
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
|
|
802
|
+
visualization: {
|
|
803
|
+
objectKinds: { [objectState.variable]: "object" },
|
|
804
|
+
hashMaps: [objectState.visualization]
|
|
805
|
+
}
|
|
806
|
+
}, pendingAccesses);
|
|
807
|
+
continue;
|
|
808
|
+
}
|
|
809
|
+
const objectField = parseObjectFieldEvent(payload);
|
|
810
|
+
if (objectField) {
|
|
811
|
+
variables[objectField.variable] = { __ref__: `${objectField.variable}-object` };
|
|
812
|
+
const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
|
|
813
|
+
if (mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
|
|
814
|
+
variables: { ...variables },
|
|
815
|
+
accesses: void 0,
|
|
816
|
+
visualization: buildFieldVisualization(objectField)
|
|
817
|
+
})) {
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
appendJavaTraceStep(trace, {
|
|
821
|
+
line,
|
|
822
|
+
event: "line",
|
|
823
|
+
function: currentFunction,
|
|
824
|
+
variables: { ...variables },
|
|
825
|
+
callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
|
|
826
|
+
visualization: buildFieldVisualization(objectField)
|
|
827
|
+
}, pendingAccesses);
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
Object.assign(variables, parseKeyValuePairs(payload));
|
|
831
|
+
const accesses = parseAccessEvent(payload);
|
|
832
|
+
if (accesses) {
|
|
833
|
+
const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
|
|
834
|
+
if (mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses)) {
|
|
835
|
+
continue;
|
|
836
|
+
}
|
|
837
|
+
pendingAccesses.push(...accesses);
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
appendJavaTraceStep(trace, {
|
|
841
|
+
line,
|
|
842
|
+
event: "line",
|
|
843
|
+
function: currentFunction,
|
|
844
|
+
variables: { ...variables },
|
|
845
|
+
...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
|
|
846
|
+
}, pendingAccesses);
|
|
847
|
+
}
|
|
848
|
+
if (pendingAccesses.length > 0 && trace.length > 0) {
|
|
849
|
+
const last = trace[trace.length - 1];
|
|
850
|
+
last.accesses = [...last.accesses ?? [], ...pendingAccesses];
|
|
851
|
+
}
|
|
852
|
+
return trace;
|
|
853
|
+
}
|
|
854
|
+
function buildJavaExecutionResult(output, events, executionTimeMs = 0, traceLimitExceeded, timeoutReason, maxTraceSteps, sourceText) {
|
|
855
|
+
const trace = eventsToRawTrace(events, sourceText);
|
|
856
|
+
return {
|
|
857
|
+
success: true,
|
|
858
|
+
output,
|
|
859
|
+
trace,
|
|
860
|
+
executionTimeMs,
|
|
861
|
+
consoleOutput: [],
|
|
862
|
+
...traceLimitExceeded !== void 0 ? { traceLimitExceeded } : {},
|
|
863
|
+
...maxTraceSteps !== void 0 ? { maxTraceSteps } : {},
|
|
864
|
+
...timeoutReason ? { timeoutReason } : {},
|
|
865
|
+
lineEventCount: trace.filter((step) => step.event === "line").length,
|
|
866
|
+
traceStepCount: trace.length
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
function normalizeJavaTraceContract(result) {
|
|
870
|
+
const normalized = normalizeRuntimeTraceContract(
|
|
871
|
+
"java",
|
|
872
|
+
buildJavaExecutionResult(
|
|
873
|
+
result.output,
|
|
874
|
+
result.events,
|
|
875
|
+
0,
|
|
876
|
+
result.traceLimitExceeded,
|
|
877
|
+
result.timeoutReason,
|
|
878
|
+
void 0,
|
|
879
|
+
result.sourceText
|
|
880
|
+
)
|
|
881
|
+
);
|
|
882
|
+
return {
|
|
883
|
+
...normalized,
|
|
884
|
+
language: "java"
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
function adaptJavaTraceExecutionResult(result) {
|
|
888
|
+
return adaptTraceExecutionResult("java", result);
|
|
889
|
+
}
|
|
289
890
|
// Annotate the CommonJS export names for ESM import in node:
|
|
290
891
|
0 && (module.exports = {
|
|
291
892
|
RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION,
|
|
292
893
|
adaptJavaScriptTraceExecutionResult,
|
|
894
|
+
adaptJavaSpikeTraceExecutionResult,
|
|
895
|
+
adaptJavaTraceExecutionResult,
|
|
293
896
|
adaptPythonTraceExecutionResult,
|
|
294
897
|
adaptTraceExecutionResult,
|
|
898
|
+
buildJavaExecutionResult,
|
|
899
|
+
buildJavaSpikeExecutionResult,
|
|
900
|
+
normalizeJavaSpikeTraceContract,
|
|
901
|
+
normalizeJavaTraceContract,
|
|
295
902
|
normalizeRuntimeTraceContract,
|
|
296
903
|
stableStringifyRuntimeTraceContract
|
|
297
904
|
});
|