mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 13:21:55 +00:00
feat(evaluateInEngine262): Add mock global console, capture results and return
- Updated tool metadata to describe pure ECMAScript restrictions and new JSON output (importantSections, otherSections, consoleOutput). - Added `ConsoleEntry` type and logic to capture console method calls during evaluation. - Exposed a global `console` with `log`, `warn`, `debug`, and `error` methods to the evaluated code. - Adjusted argument description and example usage accordingly.
This commit is contained in:
@@ -12,13 +12,14 @@ import { z } from "zod";
|
|||||||
*/
|
*/
|
||||||
export const toolMetadata = {
|
export const toolMetadata = {
|
||||||
description:
|
description:
|
||||||
"Executes JavaScript code in the engine262 JavaScript engine and captures which ECMAScript specification sections are hit during execution. " +
|
"Executes pure ECMAScript JavaScript code in the engine262 JavaScript engine and captures which ECMAScript specification sections are hit during execution. " +
|
||||||
"Returns the full marks array as JSON. Useful for understanding how specific JavaScript operations map to the ECMAScript spec. " +
|
"Returns JSON with importantSections, otherSections, and consoleOutput arrays. Useful for understanding how specific JavaScript operations map to the ECMAScript spec. " +
|
||||||
"ask262Debug is available globally in the execution context (no import needed). " +
|
"Code must be pure ECMAScript with no DOM, browser, or Node.js APIs (no fs, document, window, etc.). " +
|
||||||
|
"console object with log/warn/debug/error methods and ask262Debug are available globally (no import needed). " +
|
||||||
"Use ask262Debug.startImportant() and ask262Debug.stopImportant() to mark important sections. " +
|
"Use ask262Debug.startImportant() and ask262Debug.stopImportant() to mark important sections. " +
|
||||||
"Example: ask262Debug.startImportant(); let x = 1 + 2; ask262Debug.stopImportant();",
|
"Example: console.log('test'); ask262Debug.startImportant(); let x = 1 + 2; ask262Debug.stopImportant();",
|
||||||
args: {
|
args: {
|
||||||
code: "JavaScript code to execute in engine262 (e.g., '[1,2,3].map(x => x * 2)')",
|
code: "JavaScript code to execute in engine262 (e.g., 'console.log([1,2,3].map(x => x * 2))')",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,6 +35,12 @@ interface MarkData {
|
|||||||
readonly important: boolean;
|
readonly important: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Console log entry type
|
||||||
|
interface ConsoleEntry {
|
||||||
|
method: string;
|
||||||
|
values: unknown[];
|
||||||
|
}
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: engine262 is an external module without TypeScript types
|
// biome-ignore lint/suspicious/noExplicitAny: engine262 is an external module without TypeScript types
|
||||||
let engine262Module: any = null;
|
let engine262Module: any = null;
|
||||||
|
|
||||||
@@ -80,12 +87,15 @@ export function createEvaluateInEngine262Tool() {
|
|||||||
// Reset marks from previous runs
|
// Reset marks from previous runs
|
||||||
ask262Debug.marks = [];
|
ask262Debug.marks = [];
|
||||||
|
|
||||||
|
// Array to capture console output
|
||||||
|
const consoleOutput: ConsoleEntry[] = [];
|
||||||
|
|
||||||
// Set up agent and realm
|
// Set up agent and realm
|
||||||
const agent = new Agent();
|
const agent = new Agent();
|
||||||
setSurroundingAgent(agent);
|
setSurroundingAgent(agent);
|
||||||
const realm = new ManagedRealm();
|
const realm = new ManagedRealm();
|
||||||
|
|
||||||
// Expose ask262Debug controls to the evaluated code
|
// Expose ask262Debug and console to the evaluated code
|
||||||
realm.scope(() => {
|
realm.scope(() => {
|
||||||
const debugObj = OrdinaryObjectCreate(
|
const debugObj = OrdinaryObjectCreate(
|
||||||
agent.intrinsic("%Object.prototype%"),
|
agent.intrinsic("%Object.prototype%"),
|
||||||
@@ -127,6 +137,51 @@ export function createEvaluateInEngine262Tool() {
|
|||||||
skipDebugger(
|
skipDebugger(
|
||||||
CreateDataProperty(debugObj, Value("stopImportant"), stopImportant),
|
CreateDataProperty(debugObj, Value("stopImportant"), stopImportant),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Create console object with methods (excluding 'clear')
|
||||||
|
const consoleObj = OrdinaryObjectCreate(
|
||||||
|
agent.intrinsic("%Object.prototype%"),
|
||||||
|
);
|
||||||
|
skipDebugger(
|
||||||
|
CreateDataProperty(
|
||||||
|
realm.GlobalObject,
|
||||||
|
Value("console"),
|
||||||
|
consoleObj,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add console methods: log, warn, debug, error
|
||||||
|
const consoleMethods = ["log", "warn", "debug", "error"];
|
||||||
|
for (const method of consoleMethods) {
|
||||||
|
const fn = CreateBuiltinFunction(
|
||||||
|
(args: unknown[]) => {
|
||||||
|
// Convert engine262 values to JavaScript values for the output
|
||||||
|
const jsValues = args.map((arg) => {
|
||||||
|
// Handle engine262 Value types - convert to primitive JS values
|
||||||
|
if (arg && typeof arg === "object") {
|
||||||
|
// Try to get string value if it's a JSStringValue
|
||||||
|
const strVal = (arg as { stringValue?: () => string })
|
||||||
|
.stringValue;
|
||||||
|
if (typeof strVal === "function") {
|
||||||
|
return strVal.call(arg);
|
||||||
|
}
|
||||||
|
// Try other common properties
|
||||||
|
const value = (arg as { value?: unknown }).value;
|
||||||
|
if (value !== undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
});
|
||||||
|
consoleOutput.push({ method, values: jsValues });
|
||||||
|
return Value.undefined;
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
Value(method),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
skipDebugger(CreateDataProperty(consoleObj, Value(method), fn));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start tracing
|
// Start tracing
|
||||||
@@ -149,13 +204,17 @@ export function createEvaluateInEngine262Tool() {
|
|||||||
const result = {
|
const result = {
|
||||||
importantSections: importantMarks.map((m) => m.sectionIds),
|
importantSections: importantMarks.map((m) => m.sectionIds),
|
||||||
otherSections: otherMarks.map((m) => m.sectionIds),
|
otherSections: otherMarks.map((m) => m.sectionIds),
|
||||||
|
consoleOutput: consoleOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return compressed JSON
|
// Return compressed JSON
|
||||||
return JSON.stringify(result);
|
return JSON.stringify(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[Tool: ask262_evaluate_in_engine262] Error: ${error}`);
|
console.error(`[Tool: ask262_evaluate_in_engine262] Error: ${error}`);
|
||||||
return `Error executing code in engine262: ${error instanceof Error ? error.message : String(error)}`;
|
const errorResult = {
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
};
|
||||||
|
return JSON.stringify(errorResult);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user