diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js b/Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js new file mode 100644 index 000000000..a10541422 --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.RuntimeManager = class RuntimeManager extends WebInspector.Object +{ + constructor() + { + super(); + + // Enable the RuntimeAgent to receive notification of execution contexts. + RuntimeAgent.enable(); + + this._activeExecutionContext = WebInspector.mainTarget.executionContext; + + WebInspector.Frame.addEventListener(WebInspector.Frame.Event.ExecutionContextsCleared, this._frameExecutionContextsCleared, this); + } + + // Public + + get activeExecutionContext() + { + return this._activeExecutionContext; + } + + set activeExecutionContext(executionContext) + { + if (this._activeExecutionContext === executionContext) + return; + + this._activeExecutionContext = executionContext; + + this.dispatchEventToListeners(WebInspector.RuntimeManager.Event.ActiveExecutionContextChanged); + } + + evaluateInInspectedWindow(expression, options, callback) + { + let {objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, saveResult, sourceURLAppender} = options; + + includeCommandLineAPI = includeCommandLineAPI || false; + doNotPauseOnExceptionsAndMuteConsole = doNotPauseOnExceptionsAndMuteConsole || false; + returnByValue = returnByValue || false; + generatePreview = generatePreview || false; + saveResult = saveResult || false; + sourceURLAppender = sourceURLAppender || appendWebInspectorSourceURL; + + console.assert(objectGroup, "RuntimeManager.evaluateInInspectedWindow should always be called with an objectGroup"); + console.assert(typeof sourceURLAppender === "function"); + + if (!expression) { + // There is no expression, so the completion should happen against global properties. + expression = "this"; + } else if (/^\s*\{/.test(expression) && /\}\s*$/.test(expression)) { + // Transform {a:1} to ({a:1}) so it is treated like an object literal instead of a block with a label. + expression = "(" + expression + ")"; + } else if (/\bawait\b/.test(expression)) { + // Transform `await <expr>` into an async function assignment. + expression = this._tryApplyAwaitConvenience(expression); + } + + expression = sourceURLAppender(expression); + + let target = this._activeExecutionContext.target; + let executionContextId = this._activeExecutionContext.id; + + if (WebInspector.debuggerManager.activeCallFrame) { + target = WebInspector.debuggerManager.activeCallFrame.target; + executionContextId = target.executionContext.id; + } + + function evalCallback(error, result, wasThrown, savedResultIndex) + { + this.dispatchEventToListeners(WebInspector.RuntimeManager.Event.DidEvaluate, {objectGroup}); + + if (error) { + console.error(error); + callback(null, false); + return; + } + + if (returnByValue) + callback(null, wasThrown, wasThrown ? null : result, savedResultIndex); + else + callback(WebInspector.RemoteObject.fromPayload(result, target), wasThrown, savedResultIndex); + } + + if (WebInspector.debuggerManager.activeCallFrame) { + // COMPATIBILITY (iOS 8): "saveResult" did not exist. + target.DebuggerAgent.evaluateOnCallFrame.invoke({callFrameId: WebInspector.debuggerManager.activeCallFrame.id, expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, saveResult}, evalCallback.bind(this), target.DebuggerAgent); + return; + } + + // COMPATIBILITY (iOS 8): "saveResult" did not exist. + target.RuntimeAgent.evaluate.invoke({expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, contextId: executionContextId, returnByValue, generatePreview, saveResult}, evalCallback.bind(this), target.RuntimeAgent); + } + + saveResult(remoteObject, callback) + { + console.assert(remoteObject instanceof WebInspector.RemoteObject); + + // COMPATIBILITY (iOS 8): Runtime.saveResult did not exist. + if (!RuntimeAgent.saveResult) { + callback(undefined); + return; + } + + function mycallback(error, savedResultIndex) + { + callback(savedResultIndex); + } + + let target = this._activeExecutionContext.target; + let executionContextId = this._activeExecutionContext.id; + + if (remoteObject.objectId) + target.RuntimeAgent.saveResult(remoteObject.asCallArgument(), mycallback); + else + target.RuntimeAgent.saveResult(remoteObject.asCallArgument(), executionContextId, mycallback); + } + + getPropertiesForRemoteObject(objectId, callback) + { + this._activeExecutionContext.target.RuntimeAgent.getProperties(objectId, function(error, result) { + if (error) { + callback(error); + return; + } + + let properties = new Map; + for (let property of result) + properties.set(property.name, property); + + callback(null, properties); + }); + } + + // Private + + _frameExecutionContextsCleared(event) + { + let contexts = event.data.contexts || []; + + let currentContextWasDestroyed = contexts.some((context) => context.id === this._activeExecutionContext.id); + if (currentContextWasDestroyed) + this.activeExecutionContext = WebInspector.mainTarget.executionContext; + } + + _tryApplyAwaitConvenience(originalExpression) + { + let esprimaSyntaxTree; + + // Do not transform if the original code parses just fine. + try { + esprima.parse(originalExpression); + return originalExpression; + } catch (error) { } + + // Do not transform if the async function version does not parse. + try { + esprimaSyntaxTree = esprima.parse("(async function(){" + originalExpression + "})"); + } catch (error) { + return originalExpression; + } + + // Assert expected AST produced by our wrapping code. + console.assert(esprimaSyntaxTree.type === "Program"); + console.assert(esprimaSyntaxTree.body.length === 1); + console.assert(esprimaSyntaxTree.body[0].type === "ExpressionStatement"); + console.assert(esprimaSyntaxTree.body[0].expression.type === "FunctionExpression"); + console.assert(esprimaSyntaxTree.body[0].expression.async); + console.assert(esprimaSyntaxTree.body[0].expression.body.type === "BlockStatement"); + + // Do not transform if there is more than one statement. + let asyncFunctionBlock = esprimaSyntaxTree.body[0].expression.body; + if (asyncFunctionBlock.body.length !== 1) + return originalExpression; + + // Extract the variable name for transformation. + let variableName; + let anonymous = false; + let declarationKind = "var"; + let awaitPortion; + let statement = asyncFunctionBlock.body[0]; + if (statement.type === "ExpressionStatement" + && statement.expression.type === "AwaitExpression") { + // await <expr> + anonymous = true; + } else if (statement.type === "ExpressionStatement" + && statement.expression.type === "AssignmentExpression" + && statement.expression.right.type === "AwaitExpression" + && statement.expression.left.type === "Identifier") { + // x = await <expr> + variableName = statement.expression.left.name; + awaitPortion = originalExpression.substring(originalExpression.indexOf("await")); + } else if (statement.type === "VariableDeclaration" + && statement.declarations.length === 1 + && statement.declarations[0].init.type === "AwaitExpression" + && statement.declarations[0].id.type === "Identifier") { + // var x = await <expr> + variableName = statement.declarations[0].id.name; + declarationKind = statement.kind; + awaitPortion = originalExpression.substring(originalExpression.indexOf("await")); + } else { + // Do not transform if this was not one of the simple supported syntaxes. + return originalExpression; + } + + if (anonymous) { + return ` +(async function() { + try { + let result = ${originalExpression}; + console.info("%o", result); + } catch (e) { + console.error(e); + } +})(); +undefined`; + } + + return `${declarationKind} ${variableName}; +(async function() { + try { + ${variableName} = ${awaitPortion}; + console.info("%o", ${variableName}); + } catch (e) { + console.error(e); + } +})(); +undefined;`; + } +}; + +WebInspector.RuntimeManager.ConsoleObjectGroup = "console"; +WebInspector.RuntimeManager.TopLevelExecutionContextIdentifier = undefined; + +WebInspector.RuntimeManager.Event = { + DidEvaluate: Symbol("runtime-manager-did-evaluate"), + DefaultExecutionContextChanged: Symbol("runtime-manager-default-execution-context-changed"), + ActiveExecutionContextChanged: Symbol("runtime-manager-active-execution-context-changed"), +}; |