Commit b3173ca4 authored by Nicolas Chevobbe's avatar Nicolas Chevobbe Committed by Jason Laster
Browse files

Bug 1520957 - [release 119] Fix unhelpful error in top-level await malformed...

Bug 1520957 - [release 119] Fix unhelpful error in top-level await malformed expression. (#7695). r=dwalsh
parent 1eab7508
Loading
Loading
Loading
Loading
+48 −33
Original line number Diff line number Diff line
@@ -880,11 +880,15 @@ function parseVueScript(code) {
}
function parseConsoleScript(text, opts) {
  try {
    return _parse(text, {
      plugins: ["objectRestSpread"],
      ...opts,
      allowAwaitOutsideFunction: true
    });
  } catch (e) {
    return null;
  }
}
function parseScript(text, opts) {
@@ -23033,8 +23037,7 @@ function locationKey(start) {
  return `${start.line}:${start.column}`;
}
function mapOriginalExpression(expression, mappings) {
  const ast = (0, _ast.parseConsoleScript)(expression);
function mapOriginalExpression(expression, ast, mappings) {
  const scopes = (0, _getScopes.buildScopeList)(ast, "");
  let shouldUpdate = false;
@@ -23498,6 +23501,8 @@ Object.defineProperty(exports, "__esModule", {
});
exports.default = mapExpression;
var _ast = __webpack_require__(1375);
var _mapOriginalExpression = __webpack_require__(3613);
var _mapOriginalExpression2 = _interopRequireDefault(_mapOriginalExpression);
@@ -23512,6 +23517,10 @@ var _mapAwaitExpression2 = _interopRequireDefault(_mapAwaitExpression);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: 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/>. */
function mapExpression(expression, mappings, bindings, shouldMapBindings = true, shouldMapAwait = true) {
  const mapped = {
    await: false,
@@ -23519,22 +23528,23 @@ function mapExpression(expression, mappings, bindings, shouldMapBindings = true,
    originalExpression: false
  };
  const ast = (0, _ast.parseConsoleScript)(expression);
  try {
    if (mappings) {
    if (mappings && ast) {
      const beforeOriginalExpression = expression;
      expression = (0, _mapOriginalExpression2.default)(expression, mappings);
      expression = (0, _mapOriginalExpression2.default)(expression, ast, mappings);
      mapped.originalExpression = beforeOriginalExpression !== expression;
    }
    if (shouldMapBindings) {
    if (shouldMapBindings && ast) {
      const beforeBindings = expression;
      expression = (0, _mapBindings2.default)(expression, bindings);
      expression = (0, _mapBindings2.default)(expression, ast, bindings);
      mapped.bindings = beforeBindings !== expression;
    }
    if (shouldMapAwait) {
      const beforeAwait = expression;
      expression = (0, _mapAwaitExpression2.default)(expression);
      expression = (0, _mapAwaitExpression2.default)(expression, ast);
      mapped.await = beforeAwait !== expression;
    }
  } catch (e) {
@@ -23545,9 +23555,7 @@ function mapExpression(expression, mappings, bindings, shouldMapBindings = true,
    expression,
    mapped
  };
} /* 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/>. */
}
/***/ }),
@@ -23562,8 +23570,6 @@ Object.defineProperty(exports, "__esModule", {
});
exports.default = mapExpressionBindings;
var _ast = __webpack_require__(1375);
var _helpers = __webpack_require__(1411);
var _generator = __webpack_require__(2365);
@@ -23578,10 +23584,6 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: 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/>. */
function getAssignmentTarget(node, bindings) {
  if (t.isObjectPattern(node)) {
    for (const property of node.properties) {
@@ -23624,6 +23626,10 @@ function getAssignmentTarget(node, bindings) {
// translates new bindings `var a = 3` into `self.a = 3`
// and existing bindings `var a = 3` into `a = 3` for re-assignments
/* 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/>. */
function globalizeDeclaration(node, bindings) {
  return node.declarations.map(declaration => t.expressionStatement(t.assignmentExpression("=", getAssignmentTarget(declaration.id, bindings), declaration.init)));
}
@@ -23648,9 +23654,7 @@ function replaceNode(ancestors, node) {
  }
}
function mapExpressionBindings(expression, bindings = []) {
  const ast = (0, _ast.parseConsoleScript)(expression);
function mapExpressionBindings(expression, ast, bindings = []) {
  let isMapped = false;
  let shouldUpdate = true;
@@ -44371,14 +44375,13 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
 * 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/>. */
function hasTopLevelAwait(expression) {
  const ast = (0, _ast.parseConsoleScript)(expression);
function hasTopLevelAwait(ast) {
  const hasAwait = (0, _ast.hasNode)(ast, (node, ancestors, b) => t.isAwaitExpression(node) && (0, _helpers.isTopLevel)(ancestors));
  return hasAwait && ast;
  return hasAwait;
}
function wrapExpression(ast) {
function wrapExpressionFromAst(ast) {
  const statements = ast.program.body;
  const lastStatement = statements[statements.length - 1];
  const body = statements.slice(0, -1).concat(t.returnStatement(lastStatement.expression));
@@ -44388,15 +44391,27 @@ function wrapExpression(ast) {
  return (0, _generator2.default)(newAst).code;
}
function mapTopLevelAwait(expression) {
  const ast = hasTopLevelAwait(expression);
  if (ast) {
    return wrapExpression(ast);
function mapTopLevelAwait(expression, ast) {
  if (!ast) {
    // If there's no ast this means the expression is malformed. And if the
    // expression contains the await keyword, we still want to wrap it in an
    // async iife in order to get a meaningful message (without this, the
    // engine will throw an Error stating that await keywords are only valid
    // in async functions and generators).
    if (expression.includes("await ")) {
      return `(async () => { ${expression} })();`;
    }
    return expression;
  }
  if (!hasTopLevelAwait(ast)) {
    return expression;
  }
  return wrapExpressionFromAst(ast);
}
/***/ }),
/***/ 398:
+24 −10
Original line number Diff line number Diff line
@@ -7,20 +7,19 @@
import generate from "@babel/generator";
import * as t from "@babel/types";

import { parseConsoleScript, hasNode } from "./utils/ast";
import { hasNode } from "./utils/ast";
import { isTopLevel } from "./utils/helpers";

function hasTopLevelAwait(expression: string) {
  const ast = parseConsoleScript(expression);
function hasTopLevelAwait(ast: Object): boolean {
  const hasAwait = hasNode(
    ast,
    (node, ancestors, b) => t.isAwaitExpression(node) && isTopLevel(ancestors)
  );

  return hasAwait && ast;
  return hasAwait;
}

function wrapExpression(ast) {
function wrapExpressionFromAst(ast): string {
  const statements = ast.program.body;
  const lastStatement = statements[statements.length - 1];
  const body = statements
@@ -37,11 +36,26 @@ function wrapExpression(ast) {
  return generate(newAst).code;
}

export default function mapTopLevelAwait(expression: string) {
  const ast = hasTopLevelAwait(expression);
  if (ast) {
    return wrapExpression(ast);
export default function mapTopLevelAwait(
  expression: string,
  ast?: Object
): string {
  if (!ast) {
    // If there's no ast this means the expression is malformed. And if the
    // expression contains the await keyword, we still want to wrap it in an
    // async iife in order to get a meaningful message (without this, the
    // engine will throw an Error stating that await keywords are only valid
    // in async functions and generators).
    if (expression.includes("await ")) {
      return `(async () => { ${expression} })();`;
    }

    return expression;
  }

  if (!hasTopLevelAwait(ast)) {
    return expression;
  }

  return wrapExpressionFromAst(ast);
}
+1 −3
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@

// @flow

import { parseConsoleScript } from "./utils/ast";
import { isTopLevel } from "./utils/helpers";

import generate from "@babel/generator";
@@ -92,10 +91,9 @@ function replaceNode(ancestors, node) {

export default function mapExpressionBindings(
  expression: string,
  ast?: Object,
  bindings: string[] = []
): string {
  const ast = parseConsoleScript(expression);

  let isMapped = false;
  let shouldUpdate = true;

+7 −5
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@

// @flow

import { parseConsoleScript } from "./utils/ast";
import mapOriginalExpression from "./mapOriginalExpression";
import mapExpressionBindings from "./mapBindings";
import mapTopLevelAwait from "./mapAwaitExpression";
@@ -30,22 +31,23 @@ export default function mapExpression(
    originalExpression: false
  };

  const ast = parseConsoleScript(expression);
  try {
    if (mappings) {
    if (mappings && ast) {
      const beforeOriginalExpression = expression;
      expression = mapOriginalExpression(expression, mappings);
      expression = mapOriginalExpression(expression, ast, mappings);
      mapped.originalExpression = beforeOriginalExpression !== expression;
    }

    if (shouldMapBindings) {
    if (shouldMapBindings && ast) {
      const beforeBindings = expression;
      expression = mapExpressionBindings(expression, bindings);
      expression = mapExpressionBindings(expression, ast, bindings);
      mapped.bindings = beforeBindings !== expression;
    }

    if (shouldMapAwait) {
      const beforeAwait = expression;
      expression = mapTopLevelAwait(expression);
      expression = mapTopLevelAwait(expression, ast);
      mapped.await = beforeAwait !== expression;
    }
  } catch (e) {
+2 −2
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
// @flow

import type { Position } from "../../types";
import { parseScript, parseConsoleScript } from "./utils/ast";
import { parseScript } from "./utils/ast";
import { buildScopeList } from "./getScopes";
import generate from "@babel/generator";
import * as t from "@babel/types";
@@ -36,11 +36,11 @@ function locationKey(start: Position): string {

export default function mapOriginalExpression(
  expression: string,
  ast: ?Object,
  mappings: {
    [string]: string | null
  }
): string {
  const ast = parseConsoleScript(expression);
  const scopes = buildScopeList(ast, "");
  let shouldUpdate = false;

Loading