Bug 1624966 - It should be possible to Preview optional member expressions in an inline script r=nchevobbe
authorJason Laster <jlaster@mozilla.com>
Thu, 26 Mar 2020 09:57:43 +0000
changeset 520592 7c9e6706d6b58c5534766917e9baf7bf466e23fc
parent 520591 fa8a9f99515a64b259e53c70b873512328281856
child 520593 37445084f5f86f46d281d007ed5d26ae76ad6c37
push id37253
push usernerli@mozilla.com
push dateThu, 26 Mar 2020 21:36:52 +0000
treeherdermozilla-central@c644dd16e2cc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnchevobbe
bugs1624966
milestone76.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1624966 - It should be possible to Preview optional member expressions in an inline script r=nchevobbe Differential Revision: https://phabricator.services.mozilla.com/D68270
devtools/client/debugger/bin/module-manifest.json
devtools/client/debugger/dist/parser-worker.js
devtools/client/debugger/src/workers/parser/utils/ast.js
devtools/client/debugger/test/mochitest/browser_dbg-preview.js
devtools/client/debugger/test/mochitest/examples/doc-preview.html
--- a/devtools/client/debugger/bin/module-manifest.json
+++ b/devtools/client/debugger/bin/module-manifest.json
@@ -10,17 +10,17 @@
           "0": 0,
           "1": 1
         }
       },
       "chunks": {
         "byName": {},
         "byBlocks": {},
         "usedIds": {
-          "0": 0
+          "1": 1
         }
       }
     }
   ],
   "extract-text-webpack-plugin ../../extract-text-webpack-plugin/dist ../../css-loader/index.js??ref--3-1!../../postcss-loader/lib/index.js!../../react-aria-components/src/tabs/tab.css": [
     {
       "modules": {
         "byIdentifier": {
@@ -31,17 +31,17 @@
           "0": 0,
           "1": 1
         }
       },
       "chunks": {
         "byName": {},
         "byBlocks": {},
         "usedIds": {
-          "0": 0
+          "1": 1
         }
       }
     }
   ],
   "extract-text-webpack-plugin ../../extract-text-webpack-plugin/dist ../../css-loader/index.js??ref--3-1!../../postcss-loader/lib/index.js!../../react-aria-components/src/tabs/tab-list.css": [
     {
       "modules": {
         "byIdentifier": {
@@ -52,17 +52,17 @@
           "0": 0,
           "1": 1
         }
       },
       "chunks": {
         "byName": {},
         "byBlocks": {},
         "usedIds": {
-          "0": 0
+          "1": 1
         }
       }
     }
   ],
   "extract-text-webpack-plugin ../../extract-text-webpack-plugin/dist ../../css-loader/index.js??ref--3-1!../../postcss-loader/lib/index.js!../../devtools-contextmenu/menu.css": [
     {
       "modules": {
         "byIdentifier": {
@@ -73,17 +73,17 @@
           "0": 0,
           "1": 1
         }
       },
       "chunks": {
         "byName": {},
         "byBlocks": {},
         "usedIds": {
-          "0": 0
+          "1": 1
         }
       }
     }
   ],
   "extract-text-webpack-plugin ../../extract-text-webpack-plugin/dist ../../css-loader/index.js??ref--3-1!../../postcss-loader/lib/index.js!../../../packages/devtools-components/src/tree.css": [
     {
       "modules": {
         "byIdentifier": {
@@ -94,17 +94,17 @@
           "0": 0,
           "1": 1
         }
       },
       "chunks": {
         "byName": {},
         "byBlocks": {},
         "usedIds": {
-          "0": 0
+          "1": 1
         }
       }
     }
   ],
   "extract-text-webpack-plugin ../../extract-text-webpack-plugin/dist ../../css-loader/index.js??ref--3-1!../../postcss-loader/lib/index.js!../../../packages/devtools-reps/src/object-inspector/components/ObjectInspector.css": [
     {
       "modules": {
         "byIdentifier": {
@@ -115,17 +115,17 @@
           "0": 0,
           "1": 1
         }
       },
       "chunks": {
         "byName": {},
         "byBlocks": {},
         "usedIds": {
-          "0": 0
+          "1": 1
         }
       }
     }
   ],
   "extract-text-webpack-plugin ../../extract-text-webpack-plugin/dist ../../css-loader/index.js??ref--3-1!../../postcss-loader/lib/index.js!../../../packages/devtools-reps/src/reps/reps.css": [
     {
       "modules": {
         "byIdentifier": {
@@ -136,17 +136,17 @@
           "0": 0,
           "1": 1
         }
       },
       "chunks": {
         "byName": {},
         "byBlocks": {},
         "usedIds": {
-          "0": 0
+          "1": 1
         }
       }
     }
   ],
   "modules": {
     "byIdentifier": {
       "external \"devtools/client/shared/vendor/react-prop-types\"": 0,
       "external \"devtools/client/shared/vendor/react-dom-factories\"": 1,
--- a/devtools/client/debugger/dist/parser-worker.js
+++ b/devtools/client/debugger/dist/parser-worker.js
@@ -7108,17 +7108,18 @@ function parse(text, opts) {
 // our parser's signature
 
 
 function htmlParser({
   source,
   line
 }) {
   return parse(source, {
-    startLine: line
+    startLine: line,
+    ...sourceOptions.generated
   });
 }
 
 const VUE_COMPONENT_START = /^\s*</;
 
 function vueParser({
   source,
   line
@@ -15679,17 +15680,19 @@ function extractSymbol(path, symbols, st
         start,
         end
       },
       expression: getSnippet(path.parentPath)
     });
   }
 
   if (t.isCallExpression(path)) {
-    const callee = path.node.callee;
+    const {
+      callee
+    } = path.node;
     const args = path.node.arguments;
 
     if (t.isMemberExpression(callee)) {
       const {
         property: {
           name,
           loc
         }
@@ -15748,17 +15751,19 @@ function extractSymbol(path, symbols, st
         location: {
           start,
           end
         }
       });
     }
 
     if (path.node.typeAnnotation) {
-      const column = path.node.typeAnnotation.loc.start.column;
+      const {
+        column
+      } = path.node.typeAnnotation.loc.start;
       end = { ...end,
         column
       };
     }
 
     symbols.identifiers.push({
       name: path.node.name,
       expression: path.node.name,
@@ -15903,17 +15908,19 @@ function getMemberSnippet(node, expressi
   return expression;
 }
 
 function getObjectSnippet(path, prevPath, expression = "") {
   if (!path) {
     return expression;
   }
 
-  const name = path.node.key.name;
+  const {
+    name
+  } = path.node.key;
   const extendedExpression = extendSnippet(name, expression, path, prevPath);
   const nextPrevPath = path;
   const nextPath = path.parentPath && path.parentPath.parentPath;
   return getSnippet(nextPath, nextPrevPath, extendedExpression);
 }
 
 function getArraySnippet(path, prevPath, expression) {
   if (!prevPath.parentPath) {
@@ -15929,17 +15936,19 @@ function getArraySnippet(path, prevPath,
 
 function getSnippet(path, prevPath, expression = "") {
   if (!path) {
     return expression;
   }
 
   if (t.isVariableDeclaration(path)) {
     const node = path.node.declarations[0];
-    const name = node.id.name;
+    const {
+      name
+    } = node.id;
     return extendSnippet(name, expression, path, prevPath);
   }
 
   if (t.isVariableDeclarator(path)) {
     const node = path.node.id;
 
     if (t.isObjectPattern(node)) {
       return expression;
@@ -17823,17 +17832,19 @@ function getFunctionName(node, parent) {
     return node.id.name;
   }
 
   if (t.isObjectMethod(node, {
     computed: false
   }) || t.isClassMethod(node, {
     computed: false
   })) {
-    const key = node.key;
+    const {
+      key
+    } = node;
 
     if (t.isIdentifier(key)) {
       return key.name;
     }
 
     if (t.isStringLiteral(key)) {
       return key.value;
     }
@@ -17847,17 +17858,19 @@ function getFunctionName(node, parent) {
     computed: false,
     value: node
   }) || // TODO: Babylon 6 doesn't support computed class props. It is included
   // here so that it is most flexible. Once Babylon 7 is used, this
   // can change to use computed: false like ObjectProperty.
   t.isClassProperty(parent, {
     value: node
   }) && !parent.computed) {
-    const key = parent.key;
+    const {
+      key
+    } = parent;
 
     if (t.isIdentifier(key)) {
       return key.name;
     }
 
     if (t.isStringLiteral(key)) {
       return key.value;
     }
@@ -41658,17 +41671,19 @@ function _interopRequireWildcard(obj) { 
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 // the function class is inferred from a call like
 // createClass or extend
 function fromCallExpression(callExpression) {
   const whitelist = ["extend", "createClass"];
-  const callee = callExpression.node.callee;
+  const {
+    callee
+  } = callExpression.node;
 
   if (!callee) {
     return null;
   }
 
   const name = t.isMemberExpression(callee) ? callee.property.name : callee.name;
 
   if (!whitelist.includes(name)) {
@@ -41682,33 +41697,37 @@ function fromCallExpression(callExpressi
   }
 
   const assignment = callExpression.findParent(p => t.isAssignmentExpression(p.node));
 
   if (!assignment) {
     return null;
   }
 
-  const left = assignment.node.left;
+  const {
+    left
+  } = assignment.node;
 
   if (left.name) {
     return name;
   }
 
   if (t.isMemberExpression(left)) {
     return left.property.name;
   }
 
   return null;
 } // the function class is inferred from a prototype assignment
 // e.g. TodoClass.prototype.render = function() {}
 
 
 function fromPrototype(assignment) {
-  const left = assignment.node.left;
+  const {
+    left
+  } = assignment.node;
 
   if (!left) {
     return null;
   }
 
   if (t.isMemberExpression(left) && left.object && t.isMemberExpression(left.object) && left.object.property.identifier === "prototype") {
     return left.object.object.name;
   }
@@ -41987,17 +42006,19 @@ const scopeCollectionVisitor = {
         start: fromBabelLocation(node.loc.start, state.sourceId),
         end: fromBabelLocation(node.loc.end, state.sourceId)
       });
       scope.bindings.this = {
         type: "implicit",
         refs: []
       };
     } else if (t.isFunction(node)) {
-      let scope = state.scope;
+      let {
+        scope
+      } = state;
 
       if (t.isFunctionExpression(node) && isNode(node.id, "Identifier")) {
         scope = pushTempScope(state, "block", "Function Expression", {
           start: fromBabelLocation(node.loc.start, state.sourceId),
           end: fromBabelLocation(node.loc.end, state.sourceId)
         });
         state.declarationBindingIds.add(node.id);
         scope.bindings[node.id.name] = {
@@ -42385,18 +42406,20 @@ function buildMetaBindings(sourceId, nod
   if (parentIndex <= 1) {
     return null;
   }
 
   const parent = ancestors[parentIndex].node;
   const grandparent = ancestors[parentIndex - 1].node; // Consider "0, foo" to be equivalent to "foo".
 
   if (t.isSequenceExpression(parent) && parent.expressions.length === 2 && t.isNumericLiteral(parent.expressions[0]) && parent.expressions[1] === node) {
-    let start = parent.loc.start;
-    let end = parent.loc.end;
+    let {
+      start,
+      end
+    } = parent.loc;
 
     if (t.isCallExpression(grandparent, {
       callee: parent
     })) {
       // Attempt to expand the range around parentheses, e.g.
       // (0, foo.bar)()
       start = grandparent.loc.start;
       end = Object.assign({}, end);
--- a/devtools/client/debugger/src/workers/parser/utils/ast.js
+++ b/devtools/client/debugger/src/workers/parser/utils/ast.js
@@ -66,17 +66,17 @@ export function parse(text: ?string, opt
   }
 
   return ast;
 }
 
 // Custom parser for parse-script-tags that adapts its input structure to
 // our parser's signature
 function htmlParser({ source, line }) {
-  return parse(source, { startLine: line });
+  return parse(source, { startLine: line, ...sourceOptions.generated });
 }
 
 const VUE_COMPONENT_START = /^\s*</;
 function vueParser({ source, line }) {
   return parse(source, {
     startLine: line,
     ...sourceOptions.original,
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg-preview.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg-preview.js
@@ -27,18 +27,22 @@ async function testBucketedArray(dbg) {
   is(preview.properties[2].contents.value, 101, "length is 101");
   await resume(dbg);
 }
 
 // Test hovering on an object, which will show a popup and on a
 // simple value, which will show a tooltip.
 add_task(async function() {
   const dbg = await initDebugger("doc-preview.html", "preview.js");
+
+  await previews(dbg, "testInline", [
+    { line: 17, column: 16, expression: "obj?.prop", result: 2 },
+  ]);
+
   await selectSource(dbg, "preview.js");
-
   await testBucketedArray(dbg);
 
   await previews(dbg, "empties", [
     { line: 6, column: 9, expression: "a", result: '""' },
     { line: 7, column: 9, expression: "b", result: "false" },
     { line: 8, column: 9, expression: "c", result: "undefined" },
     { line: 9, column: 9, expression: "d", result: "null" },
   ]);
--- a/devtools/client/debugger/test/mochitest/examples/doc-preview.html
+++ b/devtools/client/debugger/test/mochitest/examples/doc-preview.html
@@ -6,15 +6,22 @@
   <head>
     <meta charset="utf-8"/>
     <title>Debugger Preview</title>
   </head>
 
   <body>
     <script src="preview.js"></script>
     <script>
+
+      function testInline() {
+        const obj = {prop: 2}
+        obj?.prop
+        debugger;
+      }
+
       // This inline script allows this HTML page to show up as a
       // source. It also needs to introduce a new global variable so
       // it's not immediately garbage collected.
       inline_script = function () { var x = 5; };
     </script>
   </body>
 </html>