Title: [210338] branches/safari-603-branch

Diff

Modified: branches/safari-603-branch/LayoutTests/ChangeLog (210337 => 210338)


--- branches/safari-603-branch/LayoutTests/ChangeLog	2017-01-05 17:08:47 UTC (rev 210337)
+++ branches/safari-603-branch/LayoutTests/ChangeLog	2017-01-05 17:08:50 UTC (rev 210338)
@@ -1,3 +1,19 @@
+2017-01-05  Matthew Hanson  <matthew_han...@apple.com>
+
+        Merge r210033. rdar://problem/29755339
+
+    2016-12-20  Joseph Pecoraro  <pecor...@apple.com>
+
+            Web Inspector: Console could be made useful for very simple await expressions
+            https://bugs.webkit.org/show_bug.cgi?id=165681
+            <rdar://problem/29755339>
+
+            Reviewed by Brian Burg.
+
+            * inspector/controller/runtime-controller-expected.txt:
+            * inspector/controller/runtime-controller.html:
+            Test the "await _expression_" convenience of RuntimeManager.
+
 2017-01-04  Matthew Hanson  <matthew_han...@apple.com>
 
         Merge r209990. rdar://problem/29705967

Modified: branches/safari-603-branch/LayoutTests/inspector/controller/runtime-controller-expected.txt (210337 => 210338)


--- branches/safari-603-branch/LayoutTests/inspector/controller/runtime-controller-expected.txt	2017-01-05 17:08:47 UTC (rev 210337)
+++ branches/safari-603-branch/LayoutTests/inspector/controller/runtime-controller-expected.txt	2017-01-05 17:08:50 UTC (rev 210338)
@@ -1,4 +1,13 @@
-Tests for the Runtime.parse command.
+CONSOLE MESSAGE: line 7: %o
+CONSOLE MESSAGE: line 7: %o
+CONSOLE MESSAGE: line 7: %o
+CONSOLE MESSAGE: line 9: Thrown exception
+CONSOLE MESSAGE: line 7: %o
+CONSOLE MESSAGE: line 9: Promise.reject
+CONSOLE MESSAGE: line 9: Rejection
+CONSOLE MESSAGE: line 7: %o
+CONSOLE MESSAGE: line 7: %o
+Tests for RuntimeManager operations.
 
 
 == Running test suite: RuntimeManager
@@ -20,3 +29,32 @@
 Source: ;{ let a = 1; a += 1; a }
 PASS: Evaluation should produce the labeled statement's value.
 
+-- Running test case: RuntimeManager.prototype.evaluateInInspectedWindow.AwaitConvenience
+
+Source: await 1
+PASS: Transformed. Should log the value or an exception.
+Source:    await 2   
+PASS: Transformed. Should log the value or an exception.
+Source: var x = await 3
+PASS: Transformed. Should log the value or an exception.
+Source: await causeExceptionImmediately()
+PASS: Transformed. Should log the value or an exception.
+Source: await Promise.resolve(4)
+PASS: Transformed. Should log the value or an exception.
+Source: await Promise.reject('Promise.reject')
+PASS: Transformed. Should log the value or an exception.
+Source: await rejectedEventually()
+PASS: Transformed. Should log the value or an exception.
+Source: await asyncOperation()
+PASS: Transformed. Should log the value or an exception.
+Source: x = await asyncOperation()
+PASS: Transformed. Should log the value or an exception.
+Source: return 10
+PASS: Exception. Should not get transformed and produce a SyntaxError.
+Source: await 10; 1
+PASS: Exception. Should not get transformed and produce a SyntaxError.
+Source: 1; await 10;
+PASS: Exception. Should not get transformed and produce a SyntaxError.
+Source: x = y = await 10
+PASS: Exception. Should not get transformed and produce a SyntaxError.
+

Modified: branches/safari-603-branch/LayoutTests/inspector/controller/runtime-controller.html (210337 => 210338)


--- branches/safari-603-branch/LayoutTests/inspector/controller/runtime-controller.html	2017-01-05 17:08:47 UTC (rev 210337)
+++ branches/safari-603-branch/LayoutTests/inspector/controller/runtime-controller.html	2017-01-05 17:08:50 UTC (rev 210338)
@@ -3,6 +3,27 @@
 <head>
 <script src=""
 <script>
+let resultNumber = 100;
+function asyncOperation() {
+    return new Promise((resolve, reject) => {
+        setTimeout(() => {
+            resolve(resultNumber++);
+        }, 50);
+    });
+}
+
+function rejectedEventually() {
+    return new Promise((resolve, reject) => {
+        setTimeout(() => {
+            reject("Rejection");
+        }, 50);
+    });
+}
+
+function causeExceptionImmediately() {
+    throw "Thrown exception";
+}
+
 function test()
 {
     let suite = InspectorTest.createAsyncSuite("RuntimeManager");
@@ -10,7 +31,7 @@
     suite.addTestCase({
         name: "RuntimeManager.prototype.evaluateInInspectedWindow.ObjectLiteralConvenience",
         description: "Test evaluating an object literal string conveniently converts wraps it in parenthesis to avoid misinterpretation as a program with a block and labeled statement.",
-        test: (resolve, reject) => {
+        test(resolve, reject) {
             function testSource(_expression_, callback) {
                 WebInspector.runtimeManager.evaluateInInspectedWindow(_expression_, {objectGroup: "test"}, (result, wasThrown) => {
                     InspectorTest.log("Source: " + _expression_);
@@ -50,11 +71,64 @@
         }
     });
 
+    suite.addTestCase({
+        name: "RuntimeManager.prototype.evaluateInInspectedWindow.AwaitConvenience",
+        description: "Test evaluating a simple await _expression_ wraps it into an async function and eventually resolves the value.",
+        test(resolve, reject) {
+            function testSource(_expression_, callback) {
+                WebInspector.runtimeManager.evaluateInInspectedWindow(_expression_, {objectGroup: "test"}, (result, wasThrown) => {
+                    InspectorTest.log("Source: " + _expression_);
+                    callback(result, wasThrown);
+                });
+            }
+
+            function expectUndefined(result, wasThrown) {
+                InspectorTest.expectThat(result.isUndefined(), "Transformed. Should log the value or an exception.");
+            }
+
+            function expectException(result, wasThrown) {
+                InspectorTest.expectThat(wasThrown, "Exception. Should not get transformed and produce a SyntaxError.");
+            }
+
+            // The convenience will detect these and make an async task.
+            const expected = 6;
+            testSource("await 1", expectUndefined);
+            testSource("   await 2   ", expectUndefined);
+            testSource("var x = await 3", expectUndefined);
+            testSource("await causeExceptionImmediately()", expectUndefined);
+            testSource("await Promise.resolve(4)", expectUndefined);
+            testSource("await Promise.reject('Promise.reject')", expectUndefined);
+            testSource("await rejectedEventually()", expectUndefined);
+            testSource("await asyncOperation()", expectUndefined);
+            testSource("x = await asyncOperation()", expectUndefined);
+
+            InspectorTest.log("");
+
+            // The convenience will not apply to these noexpressions.
+            testSource("return 10", expectException);
+            testSource("await 10; 1", expectException);
+            testSource("1; await 10;", expectException);
+            testSource("x = y = await 10", expectException);
+
+            // We can resolve after receiving the expected number of console.info messages.
+            let seen = 0;
+            let listener = WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, (event) => {
+                let consoleMessage = event.data.message;
+                if (consoleMessage.level !== WebInspector.ConsoleMessage.MessageLevel.Info)
+                    return;
+                if (++seen !== expected)
+                    return;
+                WebInspector.logManager.removeEventListener(WebInspector.LogManager.Event.MessageAdded, listener);
+                resolve();
+            });
+        }
+    });
+
     suite.runTestCasesAndFinish();
 }
 </script>
 </head>
 <body _onload_="runTest()">
-<p>Tests for the Runtime.parse command.</p>
+<p>Tests for RuntimeManager operations.</p>
 </body>
 </html>

Modified: branches/safari-603-branch/Source/WebInspectorUI/ChangeLog (210337 => 210338)


--- branches/safari-603-branch/Source/WebInspectorUI/ChangeLog	2017-01-05 17:08:47 UTC (rev 210337)
+++ branches/safari-603-branch/Source/WebInspectorUI/ChangeLog	2017-01-05 17:08:50 UTC (rev 210338)
@@ -1,5 +1,52 @@
 2017-01-05  Matthew Hanson  <matthew_han...@apple.com>
 
+        Merge r210033. rdar://problem/29755339
+
+    2016-12-20  Joseph Pecoraro  <pecor...@apple.com>
+
+            Web Inspector: Console could be made useful for very simple await expressions
+            https://bugs.webkit.org/show_bug.cgi?id=165681
+            <rdar://problem/29755339>
+
+            Reviewed by Brian Burg.
+
+            Normally await expressions are only allowed inside of async functions.
+            They make dealing with async operations easy, but can't be used directly
+            in Web Inspector's console without making your own async function wrapper.
+
+            This change allows simple await expressions to be run in the console.
+            The supported syntaxes are (simple _expression_ with optional assignment):
+
+                await <expr>
+                x = await <expr>
+                let x = await <expr>
+
+            Web Inspector's console will automatically wrap this in an async
+            function and report the resulting value or exception. For instance
+            in the last example above:
+
+                let x;
+                (async function() {
+                    try {
+                        x = await <expr>;
+                        console.info("%o", x);
+                    } catch (e) {
+                        console.error(e);
+                    }
+                })();
+                undefined
+
+            This way users can get the convenience of await in the Console.
+            This also gives users a nice way of extracting a value out of
+            a Promise without writing their own handlers.
+
+            * UserInterface/Controllers/RuntimeManager.js:
+            (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow):
+            (WebInspector.RuntimeManager.prototype._tryApplyAwaitConvenience):
+            Wrap simple await expressions into a function that will log the result.
+
+2017-01-05  Matthew Hanson  <matthew_han...@apple.com>
+
         Merge r210032. rdar://problem/29744608
 
     2016-12-20  Joseph Pecoraro  <pecor...@apple.com>

Modified: branches/safari-603-branch/Source/WebInspectorUI/UserInterface/Controllers/BreakpointLogMessageLexer.js (210337 => 210338)


--- branches/safari-603-branch/Source/WebInspectorUI/UserInterface/Controllers/BreakpointLogMessageLexer.js	2017-01-05 17:08:47 UTC (rev 210337)
+++ branches/safari-603-branch/Source/WebInspectorUI/UserInterface/Controllers/BreakpointLogMessageLexer.js	2017-01-05 17:08:50 UTC (rev 210338)
@@ -152,7 +152,7 @@
     _possiblePlaceholder()
     {
         let character = this._consume();
-        console.assert(character === "$")
+        console.assert(character === "$");
         let nextCharacter = this._peek();
 
         console.assert(this._states.lastValue === WebInspector.BreakpointLogMessageLexer.State.PossiblePlaceholder);

Modified: branches/safari-603-branch/Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js (210337 => 210338)


--- branches/safari-603-branch/Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js	2017-01-05 17:08:47 UTC (rev 210337)
+++ branches/safari-603-branch/Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js	2017-01-05 17:08:50 UTC (rev 210338)
@@ -74,6 +74,9 @@
         } 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_);
@@ -162,6 +165,91 @@
         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";
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to