diff --git a/src/domains/Runtime.ts b/src/domains/Runtime.ts index b980929..3a94490 100644 --- a/src/domains/Runtime.ts +++ b/src/domains/Runtime.ts @@ -64,9 +64,9 @@ export function getProperties( return objManager.getProperties(params) } -export function evaluate( +export async function evaluate( params: Runtime.EvaluateRequest -): Runtime.EvaluateResponse { +): Promise { const ret: any = {} let result: any @@ -74,7 +74,7 @@ export function evaluate( if (params.throwOnSideEffect && hasSideEffect(params.expression)) { throw EvalError('Possible side-effect in debug-evaluate') } - result = evaluateJs(params.expression) + result = await evaluateJs(params.expression) setGlobal('$_', result) ret.result = objManager.wrap(result, { generatePreview: true, @@ -104,6 +104,7 @@ export function globalLexicalScopeNames() { declare const console: any +let counter = 0 function monitorConsole() { const methods: any = { log: 'log', @@ -133,6 +134,8 @@ function monitorConsole() { }) ) + counter += 0.001 + if (counter > 10) { counter = 0 } trigger('Runtime.consoleAPICalled', { type, args, @@ -141,7 +144,7 @@ function monitorConsole() { type === 'error' || type === 'warning' ? getCallFrames() : [], }, executionContextId: executionContext.id, - timestamp: now(), + timestamp: now() + counter, }) } }) diff --git a/src/index.ts b/src/index.ts index 1dd6e97..0ea8300 100644 --- a/src/index.ts +++ b/src/index.ts @@ -38,7 +38,6 @@ chobitsu.register('Runtime', { discardConsoleEntries: noop, getHeapUsage: noop, getIsolateId: noop, - releaseObject: noop, releaseObjectGroup: noop, runIfWaitingForDebugger: noop, }) diff --git a/src/lib/evaluate.ts b/src/lib/evaluate.ts index 0732a13..b8f41ae 100644 --- a/src/lib/evaluate.ts +++ b/src/lib/evaluate.ts @@ -44,15 +44,34 @@ export function setGlobal(name: string, val: any) { global[name] = val } -export default function evaluate(expression: string) { +const createdInEvalIdents: Set = new Set() +export default async function evaluate(expression: string) { let ret + // try to find variables that are declared in the expression + const vars = expression.match(/(?:;|^|\s)(?:const|let|var)\s+([a-zA-Z0-9_$]+)\s*=/g) ?? [] + let varsInjectScript = '' + for (const var_ of vars) { + const name = var_.split(' ')[1].split('=')[0] + if (name in window && !createdInEvalIdents.has(name)) { + // avoid overriding existing globals + continue + } + + createdInEvalIdents.add(name) + // todo: we should probably also handle multiple declarations but who even uses that? + varsInjectScript += `try{window[${JSON.stringify(name)}]=${name}}catch{};` + } + if (varsInjectScript) { + expression += ';' + varsInjectScript + } injectGlobal() try { - ret = eval.call(window, `(${expression})`) + ret = await eval.call(window, `(async() => (${expression}))()`) } catch (e) { - ret = eval.call(window, expression) + ret = await eval.call(window, `(async () => {${expression}})()`) } + clearGlobal() return ret diff --git a/src/lib/objManager.ts b/src/lib/objManager.ts index ff6a9e3..d79cdd6 100644 --- a/src/lib/objManager.ts +++ b/src/lib/objManager.ts @@ -46,6 +46,10 @@ export function wrap( value: any, { generatePreview = false, self = value } = {} ): any { + if (typeof value === 'object' && value !== null && typeof value.toJSON === 'function') { + value = value.toJSON() + } + const ret = basic(value) const { type, subtype } = ret