summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/workers
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /devtools/client/debugger/src/workers
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/debugger/src/workers')
-rw-r--r--devtools/client/debugger/src/workers/moz.build12
-rw-r--r--devtools/client/debugger/src/workers/parser/findBestMatchExpression.js37
-rw-r--r--devtools/client/debugger/src/workers/parser/findOutOfScopeLocations.js132
-rw-r--r--devtools/client/debugger/src/workers/parser/frameworks.js60
-rw-r--r--devtools/client/debugger/src/workers/parser/getScopes/index.js65
-rw-r--r--devtools/client/debugger/src/workers/parser/getScopes/visitor.js909
-rw-r--r--devtools/client/debugger/src/workers/parser/getSymbols.js567
-rw-r--r--devtools/client/debugger/src/workers/parser/index.js55
-rw-r--r--devtools/client/debugger/src/workers/parser/mapAwaitExpression.js208
-rw-r--r--devtools/client/debugger/src/workers/parser/mapBindings.js120
-rw-r--r--devtools/client/debugger/src/workers/parser/mapExpression.js50
-rw-r--r--devtools/client/debugger/src/workers/parser/mapOriginalExpression.js106
-rw-r--r--devtools/client/debugger/src/workers/parser/moz.build10
-rw-r--r--devtools/client/debugger/src/workers/parser/sources.js24
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/__snapshots__/findOutOfScopeLocations.spec.js.snap47
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/__snapshots__/getScopes.spec.js.snap18895
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/__snapshots__/getSymbols.spec.js.snap169
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/__snapshots__/validate.spec.js.snap3
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/contains.spec.js250
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/findOutOfScopeLocations.spec.js80
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/allSymbols.js33
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/async.js10
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/call-sites.js4
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/callExpressions.js7
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/calls.js21
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/class.js28
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/component.js84
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/computed-props.js8
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/control-flow.js39
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/decorators.js2
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/destructuring.js16
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/es6.js1
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/expression.js25
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/flow.js5
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/angular1FalsePositive.js11
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/angular1Module.js4
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/plainJavascript.js8
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactComponent.js3
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactComponentEs5.js3
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactLibrary.js19
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reduxLibrary.js39
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/vueFileComponent.js3
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/vueFileDeclarative.js6
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/func.js50
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/functionNames.js50
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/generators.js4
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/jsx.js5
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/math.js15
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/modules.js10
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/object-expressions.js6
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/optional-chaining.js3
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/outOfScope.js62
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/outOfScopeComment.js4
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/parseScriptTags.html42
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/private-fields.js24
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/proto.js14
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/regexp.js1
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/resolveToken.js40
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/arrow-function.js11
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/binding-types.js24
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/block-statement.js13
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-declaration.js14
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-expression.js11
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-property.js10
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/complex-nesting.js29
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/expressions.js6
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/flowtype-bindings.js11
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/fn-body-lex-and-nonlex.js23
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/for-loops.js13
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/function-declaration.js11
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/function-expression.js7
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/jsx-component.js6
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/out-of-order-declarations.js21
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/pattern-declarations.js2
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/simple-module.js11
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/switch-statement.js22
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/try-catch.js9
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/ts-sample.ts41
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/tsx-sample.tsx41
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/vue-sample.vue26
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/statements.js40
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/thisExpression.js11
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/fixtures/var.js21
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/framework.spec.js63
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/getScopes.spec.js227
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/getSymbols.spec.js51
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/helpers/index.js86
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/mapBindings.spec.js161
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/mapExpression.spec.js796
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/mapOriginalExpression.spec.js93
-rw-r--r--devtools/client/debugger/src/workers/parser/tests/sources.spec.js14
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/ast.js230
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/contains.js29
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/formatSymbols.js65
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/getFunctionName.js96
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/helpers.js232
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/inferClassName.js93
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/parse-script-tags/customParse.js132
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/parse-script-tags/index.js60
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/parse-script-tags/parseScriptFragment.js155
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/simple-path.js104
-rw-r--r--devtools/client/debugger/src/workers/parser/utils/tests/ast.spec.js41
-rw-r--r--devtools/client/debugger/src/workers/parser/worker.js39
-rw-r--r--devtools/client/debugger/src/workers/pretty-print/LICENSE.md23
-rw-r--r--devtools/client/debugger/src/workers/pretty-print/index.js30
-rw-r--r--devtools/client/debugger/src/workers/pretty-print/moz.build10
-rw-r--r--devtools/client/debugger/src/workers/pretty-print/pretty-fast.js1178
-rw-r--r--devtools/client/debugger/src/workers/pretty-print/tests/__snapshots__/prettyFast.spec.js.snap1974
-rw-r--r--devtools/client/debugger/src/workers/pretty-print/tests/prettyFast.spec.js435
-rw-r--r--devtools/client/debugger/src/workers/pretty-print/worker.js98
-rw-r--r--devtools/client/debugger/src/workers/search/get-matches.js45
-rw-r--r--devtools/client/debugger/src/workers/search/index.js17
-rw-r--r--devtools/client/debugger/src/workers/search/moz.build10
-rw-r--r--devtools/client/debugger/src/workers/search/project-search.js70
-rw-r--r--devtools/client/debugger/src/workers/search/tests/get-matches.spec.js99
-rw-r--r--devtools/client/debugger/src/workers/search/worker.js9
116 files changed, 29707 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/workers/moz.build b/devtools/client/debugger/src/workers/moz.build
new file mode 100644
index 0000000000..12327bf177
--- /dev/null
+++ b/devtools/client/debugger/src/workers/moz.build
@@ -0,0 +1,12 @@
+# vim: set filetype=python:
+# 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/.
+
+DIRS += [
+ "parser",
+ "pretty-print",
+ "search",
+]
+
+CompiledModules()
diff --git a/devtools/client/debugger/src/workers/parser/findBestMatchExpression.js b/devtools/client/debugger/src/workers/parser/findBestMatchExpression.js
new file mode 100644
index 0000000000..6fd5d5e70e
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/findBestMatchExpression.js
@@ -0,0 +1,37 @@
+/* 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/>. */
+
+import { getInternalSymbols } from "./getSymbols";
+
+function findBestMatchExpression(sourceId, tokenPos) {
+ const symbols = getInternalSymbols(sourceId);
+ if (!symbols) {
+ return null;
+ }
+
+ const { line, column } = tokenPos;
+ const { memberExpressions, identifiers, literals } = symbols;
+
+ function matchExpression(expression) {
+ const { location } = expression;
+ const { start, end } = location;
+ return start.line == line && start.column <= column && end.column >= column;
+ }
+ function matchMemberExpression(expression) {
+ // For member expressions we ignore "computed" member expressions `foo[bar]`,
+ // to only match the one that looks like: `foo.bar`.
+ return !expression.computed && matchExpression(expression);
+ }
+ // Avoid duplicating these arrays and be careful about performance as they can be large
+ //
+ // Process member expressions first as they can be including identifiers which
+ // are subset of the member expression.
+ // Ex: `foo.bar` is a member expression made of `foo` and `bar` identifiers.
+ return (
+ memberExpressions.find(matchMemberExpression) ||
+ literals.find(matchExpression) ||
+ identifiers.find(matchExpression)
+ );
+}
+export default findBestMatchExpression;
diff --git a/devtools/client/debugger/src/workers/parser/findOutOfScopeLocations.js b/devtools/client/debugger/src/workers/parser/findOutOfScopeLocations.js
new file mode 100644
index 0000000000..6c466965c2
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/findOutOfScopeLocations.js
@@ -0,0 +1,132 @@
+/* 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/>. */
+
+import { containsLocation, containsPosition } from "./utils/contains";
+
+import { getInternalSymbols } from "./getSymbols";
+
+function findSymbols(source) {
+ const { functions, comments } = getInternalSymbols(source);
+ return { functions, comments };
+}
+
+/**
+ * Returns the location for a given function path. If the path represents a
+ * function declaration, the location will begin after the function identifier
+ * but before the function parameters.
+ */
+
+function getLocation(func) {
+ const location = { ...func.location };
+
+ // if the function has an identifier, start the block after it so the
+ // identifier is included in the "scope" of its parent
+ const identifierEnd = func?.identifier?.loc?.end;
+ if (identifierEnd) {
+ location.start = identifierEnd;
+ }
+
+ return location;
+}
+
+/**
+ * Find the nearest location containing the input position and
+ * return inner locations under that nearest location
+ *
+ * @param {Array<Object>} locations Notice! The locations MUST be sorted by `sortByStart`
+ * so that we can do linear time complexity operation.
+ * @returns {Array<Object>}
+ */
+function getInnerLocations(locations, position) {
+ // First, let's find the nearest position-enclosing function location,
+ // which is to find the last location enclosing the position.
+ let parentIndex;
+ for (let i = locations.length - 1; i >= 0; i--) {
+ const loc = locations[i];
+ if (containsPosition(loc, position)) {
+ parentIndex = i;
+ break;
+ }
+ }
+
+ if (parentIndex == undefined) {
+ return [];
+ }
+ const parentLoc = locations[parentIndex];
+
+ // Then, from the nearest location, loop locations again and put locations into
+ // the innerLocations array until we get to a location not enclosed by the nearest location.
+ const innerLocations = [];
+ for (let i = parentIndex + 1; i < locations.length; i++) {
+ const loc = locations[i];
+ if (!containsLocation(parentLoc, loc)) {
+ break;
+ }
+
+ innerLocations.push(loc);
+ }
+
+ return innerLocations;
+}
+
+/**
+ * Return an new locations array which excludes
+ * items that are completely enclosed by another location in the input locations
+ *
+ * @param locations Notice! The locations MUST be sorted by `sortByStart`
+ * so that we can do linear time complexity operation.
+ */
+function removeOverlaps(locations) {
+ if (!locations.length) {
+ return [];
+ }
+ const firstParent = locations[0];
+ return locations.reduce(deduplicateNode, [firstParent]);
+}
+
+function deduplicateNode(nodes, location) {
+ const parent = nodes[nodes.length - 1];
+ if (!containsLocation(parent, location)) {
+ nodes.push(location);
+ }
+ return nodes;
+}
+
+/**
+ * Sorts an array of locations by start position
+ */
+function sortByStart(a, b) {
+ if (a.start.line < b.start.line) {
+ return -1;
+ } else if (a.start.line === b.start.line) {
+ return a.start.column - b.start.column;
+ }
+
+ return 1;
+}
+
+/**
+ * Returns an array of locations that are considered out of scope for the given
+ * location.
+ */
+function findOutOfScopeLocations(location) {
+ const { functions, comments } = findSymbols(location.source.id);
+ const commentLocations = comments.map(c => c.location);
+ const locations = functions
+ .map(getLocation)
+ .concat(commentLocations)
+ .sort(sortByStart);
+
+ const innerLocations = getInnerLocations(locations, location);
+ const outerLocations = locations.filter(loc => {
+ if (innerLocations.includes(loc)) {
+ return false;
+ }
+
+ return !containsPosition(loc, location);
+ });
+ return removeOverlaps(outerLocations);
+}
+
+export default findOutOfScopeLocations;
diff --git a/devtools/client/debugger/src/workers/parser/frameworks.js b/devtools/client/debugger/src/workers/parser/frameworks.js
new file mode 100644
index 0000000000..aacaa5186f
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/frameworks.js
@@ -0,0 +1,60 @@
+/* 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/>. */
+
+import * as t from "@babel/types";
+
+export function getFramework(symbols) {
+ if (isReactComponent(symbols)) {
+ return "React";
+ }
+ if (isAngularComponent(symbols)) {
+ return "Angular";
+ }
+ if (isVueComponent(symbols)) {
+ return "Vue";
+ }
+
+ return null;
+}
+
+function isReactComponent({ importsReact, classes, identifiers }) {
+ return (
+ importsReact ||
+ extendsReactComponent(classes) ||
+ isReact(identifiers) ||
+ isRedux(identifiers)
+ );
+}
+
+function extendsReactComponent(classes) {
+ return classes.some(
+ classObj =>
+ t.isIdentifier(classObj.parent, { name: "Component" }) ||
+ t.isIdentifier(classObj.parent, { name: "PureComponent" }) ||
+ (t.isMemberExpression(classObj.parent, { computed: false }) &&
+ t.isIdentifier(classObj.parent, { name: "Component" }))
+ );
+}
+
+function isAngularComponent({ memberExpressions }) {
+ return memberExpressions.some(
+ item =>
+ item.expression == "angular.controller" ||
+ item.expression == "angular.module"
+ );
+}
+
+function isVueComponent({ identifiers }) {
+ return identifiers.some(identifier => identifier.name == "Vue");
+}
+
+/* This identifies the react lib file */
+function isReact(identifiers) {
+ return identifiers.some(identifier => identifier.name == "isReactComponent");
+}
+
+/* This identifies the redux lib file */
+function isRedux(identifiers) {
+ return identifiers.some(identifier => identifier.name == "Redux");
+}
diff --git a/devtools/client/debugger/src/workers/parser/getScopes/index.js b/devtools/client/debugger/src/workers/parser/getScopes/index.js
new file mode 100644
index 0000000000..82631ab614
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/getScopes/index.js
@@ -0,0 +1,65 @@
+/* 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/>. */
+
+import { buildScopeList, parseSourceScopes } from "./visitor";
+
+const parsedScopesCache = new Map();
+
+export default function getScopes(location) {
+ const sourceId = location.source.id;
+ let parsedScopes = parsedScopesCache.get(sourceId);
+ if (!parsedScopes) {
+ parsedScopes = parseSourceScopes(sourceId);
+ parsedScopesCache.set(sourceId, parsedScopes);
+ }
+ return parsedScopes ? findScopes(parsedScopes, location) : [];
+}
+
+export function clearScopes(sourceIds) {
+ for (const sourceId of sourceIds) {
+ parsedScopesCache.delete(sourceId);
+ }
+}
+
+export { buildScopeList };
+
+/**
+ * Searches all scopes and their bindings at the specific location.
+ */
+function findScopes(scopes, location) {
+ // Find inner most in the tree structure.
+ let searchInScopes = scopes;
+ const found = [];
+ while (searchInScopes) {
+ const foundOne = searchInScopes.some(s => {
+ if (
+ compareLocations(s.start, location) <= 0 &&
+ compareLocations(location, s.end) < 0
+ ) {
+ // Found the next scope, trying to search recusevly in its children.
+ found.unshift(s);
+ searchInScopes = s.children;
+ return true;
+ }
+ return false;
+ });
+ if (!foundOne) {
+ break;
+ }
+ }
+ return found.map(i => ({
+ type: i.type,
+ scopeKind: i.scopeKind,
+ displayName: i.displayName,
+ start: i.start,
+ end: i.end,
+ bindings: i.bindings,
+ }));
+}
+
+function compareLocations(a, b) {
+ // According to type of Location.column can be undefined, if will not be the
+ // case here, ignoring flow error.
+ return a.line == b.line ? a.column - b.column : a.line - b.line;
+}
diff --git a/devtools/client/debugger/src/workers/parser/getScopes/visitor.js b/devtools/client/debugger/src/workers/parser/getScopes/visitor.js
new file mode 100644
index 0000000000..8046c7e89d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/getScopes/visitor.js
@@ -0,0 +1,909 @@
+/* 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/>. */
+
+import * as t from "@babel/types";
+
+import getFunctionName from "../utils/getFunctionName";
+import { getAst } from "../utils/ast";
+
+/**
+ * "implicit"
+ * Variables added automaticly like "this" and "arguments"
+ *
+ * "var"
+ * Variables declared with "var" or non-block function declarations
+ *
+ * "let"
+ * Variables declared with "let".
+ *
+ * "const"
+ * Variables declared with "const", or added as const
+ * bindings like inner function expressions and inner class names.
+ *
+ * "import"
+ * Imported binding names exposed from other modules.
+ *
+ * "global"
+ * Variables that reference undeclared global values.
+ */
+
+// Location information about the expression immediartely surrounding a
+// given binding reference.
+
+function isGeneratedId(id) {
+ return !/\/originalSource/.test(id);
+}
+
+export function parseSourceScopes(sourceId) {
+ const ast = getAst(sourceId);
+ if (!ast || !Object.keys(ast).length) {
+ return null;
+ }
+
+ return buildScopeList(ast, sourceId);
+}
+
+export function buildScopeList(ast, sourceId) {
+ const { global, lexical } = createGlobalScope(ast, sourceId);
+
+ const state = {
+ // The id for the source that scope list is generated for
+ sourceId,
+
+ // A map of any free variables(variables which are used within the current scope but not
+ // declared within the scope). This changes when a new scope is created.
+ freeVariables: new Map(),
+
+ // A stack of all the free variables created across all the scopes that have
+ // been created.
+ freeVariableStack: [],
+
+ inType: null,
+
+ // The current scope, a new scope is potentially created on a visit to each node
+ // depending in the criteria. Initially set to the lexical global scope which is the
+ // child to the global scope.
+ scope: lexical,
+
+ // A stack of all the existing scopes, this is mainly used retrieve the parent scope
+ // (which is the last scope push onto the stack) on exiting a visited node.
+ scopeStack: [],
+
+ declarationBindingIds: new Set(),
+ };
+ t.traverse(ast, scopeCollectionVisitor, state);
+
+ for (const [key, freeVariables] of state.freeVariables) {
+ let binding = global.bindings[key];
+ if (!binding) {
+ binding = {
+ type: "global",
+ refs: [],
+ };
+ global.bindings[key] = binding;
+ }
+
+ binding.refs = freeVariables.concat(binding.refs);
+ }
+
+ // TODO: This should probably check for ".mjs" extension on the
+ // original file, and should also be skipped if the the generated
+ // code is an ES6 module rather than a script.
+ if (
+ isGeneratedId(sourceId) ||
+ (ast.program.sourceType === "script" && !looksLikeCommonJS(global))
+ ) {
+ stripModuleScope(global);
+ }
+
+ return toParsedScopes([global], sourceId) || [];
+}
+
+function toParsedScopes(children, sourceId) {
+ if (!children || children.length === 0) {
+ return undefined;
+ }
+ return children.map(scope => ({
+ // Removing unneed information from TempScope such as parent reference.
+ // We also need to convert BabelLocation to the Location type.
+ start: scope.loc.start,
+ end: scope.loc.end,
+ type:
+ scope.type === "module" || scope.type === "function-body"
+ ? "block"
+ : scope.type,
+ scopeKind: "",
+ displayName: scope.displayName,
+ bindings: scope.bindings,
+ children: toParsedScopes(scope.children, sourceId),
+ }));
+}
+
+/**
+ * Create a new scope object and link the scope to it parent.
+ *
+ * @param {String} type - scope type
+ * @param {String} displayName - The scope display name
+ * @param {Object} parent - The parent object scope
+ * @param {Object} loc - The start and end postions (line/columns) of the scope
+ * @returns {Object} The newly created scope
+ */
+function createTempScope(type, displayName, parent, loc) {
+ const scope = {
+ type,
+ displayName,
+ parent,
+
+ // A list of all the child scopes
+ children: [],
+ loc,
+
+ // All the bindings defined in this scope
+ // bindings = [binding, ...]
+ // binding = { type: "", refs: []}
+ bindings: Object.create(null),
+ };
+
+ if (parent) {
+ parent.children.push(scope);
+ }
+ return scope;
+}
+
+// Sets a new current scope and creates a new map to store the free variables
+// that may exist in this scope.
+function pushTempScope(state, type, displayName, loc) {
+ const scope = createTempScope(type, displayName, state.scope, loc);
+
+ state.scope = scope;
+
+ state.freeVariableStack.push(state.freeVariables);
+ state.freeVariables = new Map();
+ return scope;
+}
+
+function isNode(node, type) {
+ return node ? node.type === type : false;
+}
+
+// Walks up the scope tree to the top most variable scope
+function getVarScope(scope) {
+ let s = scope;
+ while (s.type !== "function" && s.type !== "module") {
+ if (!s.parent) {
+ return s;
+ }
+ s = s.parent;
+ }
+ return s;
+}
+
+function fromBabelLocation(location, sourceId) {
+ return {
+ sourceId,
+ line: location.line,
+ column: location.column,
+ };
+}
+
+function parseDeclarator(
+ declaratorId,
+ targetScope,
+ type,
+ locationType,
+ declaration,
+ state
+) {
+ if (isNode(declaratorId, "Identifier")) {
+ let existing = targetScope.bindings[declaratorId.name];
+ if (!existing) {
+ existing = {
+ type,
+ refs: [],
+ };
+ targetScope.bindings[declaratorId.name] = existing;
+ }
+ state.declarationBindingIds.add(declaratorId);
+ existing.refs.push({
+ type: locationType,
+ start: fromBabelLocation(declaratorId.loc.start, state.sourceId),
+ end: fromBabelLocation(declaratorId.loc.end, state.sourceId),
+ declaration: {
+ start: fromBabelLocation(declaration.loc.start, state.sourceId),
+ end: fromBabelLocation(declaration.loc.end, state.sourceId),
+ },
+ });
+ } else if (isNode(declaratorId, "ObjectPattern")) {
+ declaratorId.properties.forEach(prop => {
+ parseDeclarator(
+ prop.value,
+ targetScope,
+ type,
+ locationType,
+ declaration,
+ state
+ );
+ });
+ } else if (isNode(declaratorId, "ArrayPattern")) {
+ declaratorId.elements.forEach(item => {
+ parseDeclarator(
+ item,
+ targetScope,
+ type,
+ locationType,
+ declaration,
+ state
+ );
+ });
+ } else if (isNode(declaratorId, "AssignmentPattern")) {
+ parseDeclarator(
+ declaratorId.left,
+ targetScope,
+ type,
+ locationType,
+ declaration,
+ state
+ );
+ } else if (isNode(declaratorId, "RestElement")) {
+ parseDeclarator(
+ declaratorId.argument,
+ targetScope,
+ type,
+ locationType,
+ declaration,
+ state
+ );
+ } else if (t.isTSParameterProperty(declaratorId)) {
+ parseDeclarator(
+ declaratorId.parameter,
+ targetScope,
+ type,
+ locationType,
+ declaration,
+ state
+ );
+ }
+}
+
+function isLetOrConst(node) {
+ return node.kind === "let" || node.kind === "const";
+}
+
+function hasLexicalDeclaration(node, parent) {
+ const nodes = [];
+ if (t.isSwitchStatement(node)) {
+ for (const caseNode of node.cases) {
+ nodes.push(...caseNode.consequent);
+ }
+ } else {
+ nodes.push(...node.body);
+ }
+
+ const isFunctionBody = t.isFunction(parent, { body: node });
+
+ return nodes.some(
+ child =>
+ isLexicalVariable(child) ||
+ t.isClassDeclaration(child) ||
+ (!isFunctionBody && t.isFunctionDeclaration(child))
+ );
+}
+function isLexicalVariable(node) {
+ return isNode(node, "VariableDeclaration") && isLetOrConst(node);
+}
+
+// Creates the global scopes for this source, the overall global scope
+// and a lexical global scope.
+function createGlobalScope(ast, sourceId) {
+ const global = createTempScope("object", "Global", null, {
+ start: fromBabelLocation(ast.loc.start, sourceId),
+ end: fromBabelLocation(ast.loc.end, sourceId),
+ });
+
+ const lexical = createTempScope("block", "Lexical Global", global, {
+ start: fromBabelLocation(ast.loc.start, sourceId),
+ end: fromBabelLocation(ast.loc.end, sourceId),
+ });
+
+ return { global, lexical };
+}
+
+const scopeCollectionVisitor = {
+ // eslint-disable-next-line complexity
+ enter(node, ancestors, state) {
+ state.scopeStack.push(state.scope);
+
+ const parentNode =
+ ancestors.length === 0 ? null : ancestors[ancestors.length - 1].node;
+
+ if (state.inType) {
+ return;
+ }
+
+ if (t.isProgram(node)) {
+ const scope = pushTempScope(state, "module", "Module", {
+ 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;
+
+ 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] = {
+ type: "const",
+ refs: [
+ {
+ type: "fn-expr",
+ start: fromBabelLocation(node.id.loc.start, state.sourceId),
+ end: fromBabelLocation(node.id.loc.end, state.sourceId),
+ declaration: {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ },
+ },
+ ],
+ };
+ }
+
+ if (t.isFunctionDeclaration(node) && isNode(node.id, "Identifier")) {
+ // This ignores Annex B function declaration hoisting, which
+ // is probably a fine assumption.
+ state.declarationBindingIds.add(node.id);
+ const refs = [
+ {
+ type: "fn-decl",
+ start: fromBabelLocation(node.id.loc.start, state.sourceId),
+ end: fromBabelLocation(node.id.loc.end, state.sourceId),
+ declaration: {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ },
+ },
+ ];
+
+ if (scope.type === "block") {
+ scope.bindings[node.id.name] = {
+ type: "let",
+ refs,
+ };
+ } else {
+ // Add the binding to the ancestor scope
+ getVarScope(scope).bindings[node.id.name] = {
+ type: "var",
+ refs,
+ };
+ }
+ }
+
+ scope = pushTempScope(
+ state,
+ "function",
+ getFunctionName(node, parentNode),
+ {
+ // Being at the start of a function doesn't count as
+ // being inside of it.
+ start: fromBabelLocation(
+ node.params[0] ? node.params[0].loc.start : node.loc.start,
+ state.sourceId
+ ),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ }
+ );
+
+ node.params.forEach(param =>
+ parseDeclarator(param, scope, "var", "fn-param", node, state)
+ );
+
+ if (!t.isArrowFunctionExpression(node)) {
+ scope.bindings.this = {
+ type: "implicit",
+ refs: [],
+ };
+ scope.bindings.arguments = {
+ type: "implicit",
+ refs: [],
+ };
+ }
+
+ if (
+ t.isBlockStatement(node.body) &&
+ hasLexicalDeclaration(node.body, node)
+ ) {
+ scope = pushTempScope(state, "function-body", "Function Body", {
+ start: fromBabelLocation(node.body.loc.start, state.sourceId),
+ end: fromBabelLocation(node.body.loc.end, state.sourceId),
+ });
+ }
+ } else if (t.isClass(node)) {
+ if (t.isIdentifier(node.id)) {
+ // For decorated classes, the AST considers the first the decorator
+ // to be the start of the class. For the purposes of mapping class
+ // declarations however, we really want to look for the "class Foo"
+ // piece. To achieve that, we estimate the location of the declaration
+ // instead.
+ let declStart = node.loc.start;
+ if (node.decorators && node.decorators.length) {
+ // Estimate the location of the "class" keyword since it
+ // is unlikely to be a different line than the class name.
+ declStart = {
+ line: node.id.loc.start.line,
+ column: node.id.loc.start.column - "class ".length,
+ };
+ }
+
+ const declaration = {
+ start: fromBabelLocation(declStart, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ };
+
+ if (t.isClassDeclaration(node)) {
+ state.declarationBindingIds.add(node.id);
+ state.scope.bindings[node.id.name] = {
+ type: "let",
+ refs: [
+ {
+ type: "class-decl",
+ start: fromBabelLocation(node.id.loc.start, state.sourceId),
+ end: fromBabelLocation(node.id.loc.end, state.sourceId),
+ declaration,
+ },
+ ],
+ };
+ }
+
+ const scope = pushTempScope(state, "block", "Class", {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ });
+
+ state.declarationBindingIds.add(node.id);
+ scope.bindings[node.id.name] = {
+ type: "const",
+ refs: [
+ {
+ type: "class-inner",
+ start: fromBabelLocation(node.id.loc.start, state.sourceId),
+ end: fromBabelLocation(node.id.loc.end, state.sourceId),
+ declaration,
+ },
+ ],
+ };
+ }
+ } else if (t.isForXStatement(node) || t.isForStatement(node)) {
+ const init = node.init || node.left;
+ if (isNode(init, "VariableDeclaration") && isLetOrConst(init)) {
+ // Debugger will create new lexical environment for the for.
+ pushTempScope(state, "block", "For", {
+ // Being at the start of a for loop doesn't count as
+ // being inside it.
+ start: fromBabelLocation(init.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ });
+ }
+ } else if (t.isCatchClause(node)) {
+ const scope = pushTempScope(state, "block", "Catch", {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ });
+ parseDeclarator(node.param, scope, "var", "catch", node, state);
+ } else if (
+ t.isBlockStatement(node) &&
+ // Function body's are handled in the function logic above.
+ !t.isFunction(parentNode) &&
+ hasLexicalDeclaration(node, parentNode)
+ ) {
+ // Debugger will create new lexical environment for the block.
+ pushTempScope(state, "block", "Block", {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ });
+ } else if (
+ t.isVariableDeclaration(node) &&
+ (node.kind === "var" ||
+ // Lexical declarations in for statements are handled above.
+ !t.isForStatement(parentNode, { init: node }) ||
+ !t.isForXStatement(parentNode, { left: node }))
+ ) {
+ // Finds right lexical environment
+ const hoistAt = !isLetOrConst(node)
+ ? getVarScope(state.scope)
+ : state.scope;
+ node.declarations.forEach(declarator => {
+ parseDeclarator(
+ declarator.id,
+ hoistAt,
+ node.kind,
+ node.kind,
+ node,
+ state
+ );
+ });
+ } else if (
+ t.isImportDeclaration(node) &&
+ (!node.importKind || node.importKind === "value")
+ ) {
+ node.specifiers.forEach(spec => {
+ if (spec.importKind && spec.importKind !== "value") {
+ return;
+ }
+
+ if (t.isImportNamespaceSpecifier(spec)) {
+ state.declarationBindingIds.add(spec.local);
+
+ state.scope.bindings[spec.local.name] = {
+ // Imported namespaces aren't live import bindings, they are
+ // just normal const bindings.
+ type: "const",
+ refs: [
+ {
+ type: "import-ns-decl",
+ start: fromBabelLocation(spec.local.loc.start, state.sourceId),
+ end: fromBabelLocation(spec.local.loc.end, state.sourceId),
+ declaration: {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ },
+ },
+ ],
+ };
+ } else {
+ state.declarationBindingIds.add(spec.local);
+
+ state.scope.bindings[spec.local.name] = {
+ type: "import",
+ refs: [
+ {
+ type: "import-decl",
+ start: fromBabelLocation(spec.local.loc.start, state.sourceId),
+ end: fromBabelLocation(spec.local.loc.end, state.sourceId),
+ importName: t.isImportDefaultSpecifier(spec)
+ ? "default"
+ : spec.imported.name,
+ declaration: {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ },
+ },
+ ],
+ };
+ }
+ });
+ } else if (t.isTSEnumDeclaration(node)) {
+ state.declarationBindingIds.add(node.id);
+ state.scope.bindings[node.id.name] = {
+ type: "const",
+ refs: [
+ {
+ type: "ts-enum-decl",
+ start: fromBabelLocation(node.id.loc.start, state.sourceId),
+ end: fromBabelLocation(node.id.loc.end, state.sourceId),
+ declaration: {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ },
+ },
+ ],
+ };
+ } else if (t.isTSModuleDeclaration(node)) {
+ state.declarationBindingIds.add(node.id);
+ state.scope.bindings[node.id.name] = {
+ type: "const",
+ refs: [
+ {
+ type: "ts-namespace-decl",
+ start: fromBabelLocation(node.id.loc.start, state.sourceId),
+ end: fromBabelLocation(node.id.loc.end, state.sourceId),
+ declaration: {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ },
+ },
+ ],
+ };
+ } else if (t.isTSModuleBlock(node)) {
+ pushTempScope(state, "block", "TypeScript Namespace", {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ });
+ } else if (
+ t.isIdentifier(node) &&
+ t.isReferenced(node, parentNode) &&
+ // Babel doesn't cover this in 'isReferenced' yet, but it should
+ // eventually.
+ !t.isTSEnumMember(parentNode, { id: node }) &&
+ !t.isTSModuleDeclaration(parentNode, { id: node }) &&
+ // isReferenced above fails to see `var { foo } = ...` as a non-reference
+ // because the direct parent is not enough to know that the pattern is
+ // used within a variable declaration.
+ !state.declarationBindingIds.has(node)
+ ) {
+ let freeVariables = state.freeVariables.get(node.name);
+ if (!freeVariables) {
+ freeVariables = [];
+ state.freeVariables.set(node.name, freeVariables);
+ }
+
+ freeVariables.push({
+ type: "ref",
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ meta: buildMetaBindings(state.sourceId, node, ancestors),
+ });
+ } else if (isOpeningJSXIdentifier(node, ancestors)) {
+ let freeVariables = state.freeVariables.get(node.name);
+ if (!freeVariables) {
+ freeVariables = [];
+ state.freeVariables.set(node.name, freeVariables);
+ }
+
+ freeVariables.push({
+ type: "ref",
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ meta: buildMetaBindings(state.sourceId, node, ancestors),
+ });
+ } else if (t.isThisExpression(node)) {
+ let freeVariables = state.freeVariables.get("this");
+ if (!freeVariables) {
+ freeVariables = [];
+ state.freeVariables.set("this", freeVariables);
+ }
+
+ freeVariables.push({
+ type: "ref",
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ meta: buildMetaBindings(state.sourceId, node, ancestors),
+ });
+ } else if (t.isClassProperty(parentNode, { value: node })) {
+ const scope = pushTempScope(state, "function", "Class Field", {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ });
+ scope.bindings.this = {
+ type: "implicit",
+ refs: [],
+ };
+ scope.bindings.arguments = {
+ type: "implicit",
+ refs: [],
+ };
+ } else if (
+ t.isSwitchStatement(node) &&
+ hasLexicalDeclaration(node, parentNode)
+ ) {
+ pushTempScope(state, "block", "Switch", {
+ start: fromBabelLocation(node.loc.start, state.sourceId),
+ end: fromBabelLocation(node.loc.end, state.sourceId),
+ });
+ }
+
+ if (
+ // In general Flow expressions are deleted, so they can't contain
+ // runtime bindings, but typecasts are the one exception there.
+ (t.isFlow(node) && !t.isTypeCastExpression(node)) ||
+ // In general TS items are deleted, but TS has a few wrapper node
+ // types that can contain general JS expressions.
+ (node.type.startsWith("TS") &&
+ !t.isTSTypeAssertion(node) &&
+ !t.isTSAsExpression(node) &&
+ !t.isTSNonNullExpression(node) &&
+ !t.isTSModuleDeclaration(node) &&
+ !t.isTSModuleBlock(node) &&
+ !t.isTSParameterProperty(node) &&
+ !t.isTSExportAssignment(node))
+ ) {
+ // Flag this node as a root "type" node. All items inside of this
+ // will be skipped entirely.
+ state.inType = node;
+ }
+ },
+ exit(node, ancestors, state) {
+ const currentScope = state.scope;
+ const parentScope = state.scopeStack.pop();
+ if (!parentScope) {
+ throw new Error("Assertion failure - unsynchronized pop");
+ }
+ state.scope = parentScope;
+
+ // It is possible, as in the case of function expressions, that a single
+ // node has added multiple scopes, so we need to traverse upward here
+ // rather than jumping stright to 'parentScope'.
+ for (
+ let scope = currentScope;
+ scope && scope !== parentScope;
+ scope = scope.parent
+ ) {
+ const { freeVariables } = state;
+ state.freeVariables = state.freeVariableStack.pop();
+ const parentFreeVariables = state.freeVariables;
+
+ // Match up any free variables that match this scope's bindings and
+ // merge then into the refs.
+ for (const key of Object.keys(scope.bindings)) {
+ const binding = scope.bindings[key];
+
+ const freeVars = freeVariables.get(key);
+ if (freeVars) {
+ binding.refs.push(...freeVars);
+ freeVariables.delete(key);
+ }
+ }
+
+ // Move any undeclared references in this scope into the parent for
+ // processing in higher scopes.
+ for (const [key, value] of freeVariables) {
+ let refs = parentFreeVariables.get(key);
+ if (!refs) {
+ refs = [];
+ parentFreeVariables.set(key, refs);
+ }
+
+ refs.push(...value);
+ }
+ }
+
+ if (state.inType === node) {
+ state.inType = null;
+ }
+ },
+};
+
+function isOpeningJSXIdentifier(node, ancestors) {
+ if (!t.isJSXIdentifier(node)) {
+ return false;
+ }
+
+ for (let i = ancestors.length - 1; i >= 0; i--) {
+ const { node: parent, key } = ancestors[i];
+
+ if (t.isJSXOpeningElement(parent) && key === "name") {
+ return true;
+ } else if (!t.isJSXMemberExpression(parent) || key !== "object") {
+ break;
+ }
+ }
+
+ return false;
+}
+
+function buildMetaBindings(
+ sourceId,
+ node,
+ ancestors,
+ parentIndex = ancestors.length - 1
+) {
+ 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, 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);
+ end.column += 1;
+ }
+
+ return {
+ type: "inherit",
+ start: fromBabelLocation(start, sourceId),
+ end: fromBabelLocation(end, sourceId),
+ parent: buildMetaBindings(sourceId, parent, ancestors, parentIndex - 1),
+ };
+ }
+
+ // Consider "Object(foo)", and "__webpack_require__.i(foo)" to be
+ // equivalent to "foo" since they are essentially identity functions.
+ if (
+ t.isCallExpression(parent) &&
+ (t.isIdentifier(parent.callee, { name: "Object" }) ||
+ (t.isMemberExpression(parent.callee, { computed: false }) &&
+ t.isIdentifier(parent.callee.object, { name: "__webpack_require__" }) &&
+ t.isIdentifier(parent.callee.property, { name: "i" }))) &&
+ parent.arguments.length === 1 &&
+ parent.arguments[0] === node
+ ) {
+ return {
+ type: "inherit",
+ start: fromBabelLocation(parent.loc.start, sourceId),
+ end: fromBabelLocation(parent.loc.end, sourceId),
+ parent: buildMetaBindings(sourceId, parent, ancestors, parentIndex - 1),
+ };
+ }
+
+ if (t.isMemberExpression(parent, { object: node })) {
+ if (parent.computed) {
+ if (t.isStringLiteral(parent.property)) {
+ return {
+ type: "member",
+ start: fromBabelLocation(parent.loc.start, sourceId),
+ end: fromBabelLocation(parent.loc.end, sourceId),
+ property: parent.property.value,
+ parent: buildMetaBindings(
+ sourceId,
+ parent,
+ ancestors,
+ parentIndex - 1
+ ),
+ };
+ }
+ } else {
+ return {
+ type: "member",
+ start: fromBabelLocation(parent.loc.start, sourceId),
+ end: fromBabelLocation(parent.loc.end, sourceId),
+ property: parent.property.name,
+ parent: buildMetaBindings(sourceId, parent, ancestors, parentIndex - 1),
+ };
+ }
+ }
+ if (
+ t.isCallExpression(parent, { callee: node }) &&
+ !parent.arguments.length
+ ) {
+ return {
+ type: "call",
+ start: fromBabelLocation(parent.loc.start, sourceId),
+ end: fromBabelLocation(parent.loc.end, sourceId),
+ parent: buildMetaBindings(sourceId, parent, ancestors, parentIndex - 1),
+ };
+ }
+
+ return null;
+}
+
+function looksLikeCommonJS(rootScope) {
+ const hasRefs = name =>
+ rootScope.bindings[name] && !!rootScope.bindings[name].refs.length;
+
+ return (
+ hasRefs("__dirname") ||
+ hasRefs("__filename") ||
+ hasRefs("require") ||
+ hasRefs("exports") ||
+ hasRefs("module")
+ );
+}
+
+function stripModuleScope(rootScope) {
+ const rootLexicalScope = rootScope.children[0];
+ const moduleScope = rootLexicalScope.children[0];
+ if (moduleScope.type !== "module") {
+ throw new Error("Assertion failure - should be module");
+ }
+
+ Object.keys(moduleScope.bindings).forEach(name => {
+ const binding = moduleScope.bindings[name];
+ if (binding.type === "let" || binding.type === "const") {
+ rootLexicalScope.bindings[name] = binding;
+ } else {
+ rootScope.bindings[name] = binding;
+ }
+ });
+ rootLexicalScope.children = moduleScope.children;
+ rootLexicalScope.children.forEach(child => {
+ child.parent = rootLexicalScope;
+ });
+}
diff --git a/devtools/client/debugger/src/workers/parser/getSymbols.js b/devtools/client/debugger/src/workers/parser/getSymbols.js
new file mode 100644
index 0000000000..fb288adcfb
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/getSymbols.js
@@ -0,0 +1,567 @@
+/* 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/>. */
+
+import * as t from "@babel/types";
+
+import createSimplePath from "./utils/simple-path";
+import { traverseAst } from "./utils/ast";
+import {
+ isFunction,
+ isObjectShorthand,
+ isComputedExpression,
+ getObjectExpressionValue,
+ addPatternIdentifiers,
+ getComments,
+ getCode,
+ nodeLocationKey,
+ getFunctionParameterNames,
+} from "./utils/helpers";
+
+import { inferClassName } from "./utils/inferClassName";
+import getFunctionName from "./utils/getFunctionName";
+import { getFramework } from "./frameworks";
+
+const symbolDeclarations = new Map();
+
+function extractFunctionSymbol(path, state, symbols) {
+ const name = getFunctionName(path.node, path.parent);
+
+ if (!state.fnCounts[name]) {
+ state.fnCounts[name] = 0;
+ }
+ const index = state.fnCounts[name]++;
+ symbols.functions.push({
+ name,
+ klass: inferClassName(path),
+ location: path.node.loc,
+ parameterNames: getFunctionParameterNames(path),
+ identifier: path.node.id,
+ // indicates the occurence of the function in a file
+ // e.g { name: foo, ... index: 4 } is the 4th foo function
+ // in the file
+ index,
+ });
+}
+
+function extractSymbol(path, symbols, state) {
+ if (isFunction(path)) {
+ extractFunctionSymbol(path, state, symbols);
+ }
+
+ if (t.isJSXElement(path)) {
+ symbols.hasJsx = true;
+ }
+
+ if (t.isGenericTypeAnnotation(path)) {
+ symbols.hasTypes = true;
+ }
+
+ if (t.isClassDeclaration(path)) {
+ symbols.classes.push(getClassDeclarationSymbol(path.node));
+ }
+
+ if (!symbols.importsReact) {
+ if (t.isImportDeclaration(path)) {
+ symbols.importsReact = isReactImport(path.node);
+ } else if (t.isCallExpression(path)) {
+ symbols.importsReact = isReactRequire(path.node);
+ }
+ }
+
+ if (t.isMemberExpression(path) || t.isOptionalMemberExpression(path)) {
+ symbols.memberExpressions.push(getMemberExpressionSymbol(path));
+ }
+
+ if (
+ (t.isStringLiteral(path) || t.isNumericLiteral(path)) &&
+ t.isMemberExpression(path.parentPath)
+ ) {
+ // We only need literals that are part of computed memeber expressions
+ const { start, end } = path.node.loc;
+ symbols.literals.push({
+ location: { start, end },
+ get expression() {
+ delete this.expression;
+ this.expression = getSnippet(path.parentPath);
+ return this.expression;
+ },
+ });
+ }
+
+ getIdentifierSymbols(symbols.identifiers, symbols.identifiersKeys, path);
+}
+
+function extractSymbols(sourceId) {
+ const symbols = {
+ functions: [],
+ memberExpressions: [],
+ comments: [],
+ identifiers: [],
+ // This holds a set of unique identifier location key (string)
+ // It helps registering only the first identifier when there is duplicated ones for the same location.
+ identifiersKeys: new Set(),
+ classes: [],
+ literals: [],
+ hasJsx: false,
+ hasTypes: false,
+ framework: undefined,
+ importsReact: false,
+ };
+
+ const state = {
+ fnCounts: Object.create(null),
+ };
+
+ const ast = traverseAst(sourceId, {
+ enter(node, ancestors) {
+ try {
+ const path = createSimplePath(ancestors);
+ if (path) {
+ extractSymbol(path, symbols, state);
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ },
+ });
+
+ // comments are extracted separately from the AST
+ symbols.comments = getComments(ast);
+ symbols.framework = getFramework(symbols);
+
+ return symbols;
+}
+
+function extendSnippet(name, expression, path, prevPath) {
+ const computed = path?.node.computed;
+ const optional = path?.node.optional;
+ const prevComputed = prevPath?.node.computed;
+ const prevArray = t.isArrayExpression(prevPath);
+ const array = t.isArrayExpression(path);
+ const value = path?.node.property?.extra?.raw || "";
+
+ if (expression === "") {
+ if (computed) {
+ return name === undefined ? `[${value}]` : `[${name}]`;
+ }
+ return name;
+ }
+
+ if (computed || array) {
+ if (prevComputed || prevArray) {
+ return `[${name}]${expression}`;
+ }
+ return `[${name === undefined ? value : name}].${expression}`;
+ }
+
+ if (prevComputed || prevArray) {
+ return `${name}${expression}`;
+ }
+
+ if (isComputedExpression(expression) && name !== undefined) {
+ return `${name}${expression}`;
+ }
+
+ if (optional) {
+ return `${name}?.${expression}`;
+ }
+
+ return `${name}.${expression}`;
+}
+
+function getMemberSnippet(node, expression = "", optional = false) {
+ if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) {
+ const name = t.isPrivateName(node.property)
+ ? `#${node.property.id.name}`
+ : node.property.name;
+ const snippet = getMemberSnippet(
+ node.object,
+ extendSnippet(name, expression, { node }),
+ node.optional
+ );
+ return snippet;
+ }
+
+ if (t.isCallExpression(node)) {
+ return "";
+ }
+
+ if (t.isThisExpression(node)) {
+ return `this.${expression}`;
+ }
+
+ if (t.isIdentifier(node)) {
+ if (isComputedExpression(expression)) {
+ return `${node.name}${expression}`;
+ }
+ if (optional) {
+ return `${node.name}?.${expression}`;
+ }
+ return `${node.name}.${expression}`;
+ }
+
+ return expression;
+}
+
+function getObjectSnippet(path, prevPath, expression = "") {
+ if (!path) {
+ return expression;
+ }
+
+ 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) {
+ throw new Error("Assertion failure - path should exist");
+ }
+
+ const index = `${prevPath.parentPath.containerIndex}`;
+ const extendedExpression = extendSnippet(index, expression, path, prevPath);
+
+ const nextPrevPath = path;
+ const nextPath = path.parentPath && path.parentPath.parentPath;
+
+ return getSnippet(nextPath, nextPrevPath, extendedExpression);
+}
+
+function getSnippet(path, prevPath, expression = "") {
+ if (!path) {
+ return expression;
+ }
+
+ if (t.isVariableDeclaration(path)) {
+ const node = path.node.declarations[0];
+ 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;
+ }
+
+ const prop = extendSnippet(node.name, expression, path, prevPath);
+ return prop;
+ }
+
+ if (t.isAssignmentExpression(path)) {
+ const node = path.node.left;
+ const name = t.isMemberExpression(node)
+ ? getMemberSnippet(node)
+ : node.name;
+
+ const prop = extendSnippet(name, expression, path, prevPath);
+ return prop;
+ }
+
+ if (isFunction(path)) {
+ return expression;
+ }
+
+ if (t.isIdentifier(path)) {
+ return `${path.node.name}.${expression}`;
+ }
+
+ if (t.isObjectProperty(path)) {
+ return getObjectSnippet(path, prevPath, expression);
+ }
+
+ if (t.isObjectExpression(path)) {
+ const parentPath = prevPath?.parentPath;
+ return getObjectSnippet(parentPath, prevPath, expression);
+ }
+
+ if (t.isMemberExpression(path) || t.isOptionalMemberExpression(path)) {
+ return getMemberSnippet(path.node, expression);
+ }
+
+ if (t.isArrayExpression(path)) {
+ if (!prevPath) {
+ throw new Error("Assertion failure - path should exist");
+ }
+
+ return getArraySnippet(path, prevPath, expression);
+ }
+
+ return "";
+}
+
+export function clearSymbols(sourceIds) {
+ for (const sourceId of sourceIds) {
+ symbolDeclarations.delete(sourceId);
+ }
+}
+
+export function getInternalSymbols(sourceId) {
+ if (symbolDeclarations.has(sourceId)) {
+ const symbols = symbolDeclarations.get(sourceId);
+ if (symbols) {
+ return symbols;
+ }
+ }
+
+ const symbols = extractSymbols(sourceId);
+
+ symbolDeclarations.set(sourceId, symbols);
+ return symbols;
+}
+
+export function getFunctionSymbols(sourceId, maxResults) {
+ const symbols = getInternalSymbols(sourceId);
+ if (!symbols) {
+ return [];
+ }
+ let { functions } = symbols;
+ // Avoid transferring more symbols than necessary
+ if (maxResults && functions.length > maxResults) {
+ functions = functions.slice(0, maxResults);
+ }
+ // The Outline & the Quick open panels do not need anonymous functions
+ return functions.filter(fn => fn.name !== "anonymous");
+}
+
+export function getClassSymbols(sourceId) {
+ const symbols = getInternalSymbols(sourceId);
+ if (!symbols) {
+ return [];
+ }
+
+ return symbols.classes;
+}
+
+function containsPosition(a, b) {
+ const bColumn = b.column || 0;
+ const startsBefore =
+ a.start.line < b.line ||
+ (a.start.line === b.line && a.start.column <= bColumn);
+ const endsAfter =
+ a.end.line > b.line || (a.end.line === b.line && a.end.column >= bColumn);
+
+ return startsBefore && endsAfter;
+}
+
+export function getClosestFunctionName(location) {
+ const symbols = getInternalSymbols(location.source.id);
+ if (!symbols || !symbols.functions) {
+ return "";
+ }
+
+ const closestFunction = symbols.functions.reduce((found, currNode) => {
+ if (
+ currNode.name === "anonymous" ||
+ !containsPosition(currNode.location, {
+ line: location.line,
+ column: location.column || 0,
+ })
+ ) {
+ return found;
+ }
+
+ if (!found) {
+ return currNode;
+ }
+
+ if (found.location.start.line > currNode.location.start.line) {
+ return found;
+ }
+ if (
+ found.location.start.line === currNode.location.start.line &&
+ found.location.start.column > currNode.location.start.column
+ ) {
+ return found;
+ }
+
+ return currNode;
+ }, null);
+
+ if (!closestFunction) {
+ return "";
+ }
+ return closestFunction.name;
+}
+
+// This is only called from the main thread and we return a subset of attributes
+export function getSymbols(sourceId) {
+ const symbols = getInternalSymbols(sourceId);
+ return {
+ // This is used in the main thread by:
+ // * The `getFunctionSymbols` function which is used by the Outline, QuickOpen panels.
+ // * The `getClosestFunctionName` function used in the mapping of frame function names.
+ // * The `findOutOfScopeLocations` function use to determine in scope lines.
+ // functions: symbols.functions,
+
+ // The three following attributes are only used by `findBestMatchExpression` within the worker thread
+ // `memberExpressions`, `literals`
+ // This one is also used within the worker for framework computation
+ // `identifiers`
+ //
+ // These three memberExpressions, literals and identifiers attributes are arrays containing objects whose attributes are:
+ // * name: string
+ // * location: object {start: number, end: number}
+ // * expression: string
+ // * computed: boolean (only for memberExpressions)
+ //
+ // `findBestMatchExpression` uses `location`, `computed` and `expression` (not name).
+ // `expression` isn't used from the worker thread implementation of `findBestMatchExpression`.
+ // The main thread only uses `expression` and `location`.
+ // framework computation uses only:
+ // * `name` for identifiers
+ // * `expression` for memberExpression
+
+ // This is used within the worker for framework computation,
+ // and in the `getClassSymbols` function
+ // `classes`
+
+ // The two following are only used by the main thread for computing CodeMirror "mode"
+ hasJsx: symbols.hasJsx,
+ hasTypes: symbols.hasTypes,
+
+ // This is used in the main thread only to compute the source icon
+ framework: symbols.framework,
+
+ // This is only used by `findOutOfScopeLocations`:
+ // `comments`
+ };
+}
+
+function getMemberExpressionSymbol(path) {
+ const { start, end } = path.node.property.loc;
+ return {
+ location: { start, end },
+ get expression() {
+ delete this.expression;
+ this.expression = getSnippet(path);
+ return this.expression;
+ },
+ computed: path.node.computed,
+ };
+}
+
+function isReactImport(node) {
+ return (
+ node.source.value == "react" &&
+ node.specifiers?.some(specifier => specifier.local?.name == "React")
+ );
+}
+
+function isReactRequire(node) {
+ const { callee } = node;
+ const name = t.isMemberExpression(callee)
+ ? callee.property.name
+ : callee.loc.identifierName;
+ return name == "require" && node.arguments.some(arg => arg.value == "react");
+}
+
+function getClassParentName(superClass) {
+ return t.isMemberExpression(superClass)
+ ? getCode(superClass)
+ : superClass.name;
+}
+
+function getClassParentSymbol(superClass) {
+ if (!superClass) {
+ return null;
+ }
+ return {
+ name: getClassParentName(superClass),
+ location: superClass.loc,
+ };
+}
+
+function getClassDeclarationSymbol(node) {
+ const { loc, superClass } = node;
+ return {
+ name: node.id.name,
+ parent: getClassParentSymbol(superClass),
+ location: loc,
+ };
+}
+
+/**
+ * Get a list of identifiers that are part of the given path.
+ *
+ * @param {Array.<Object>} identifiers
+ * the current list of identifiers where to push the new identifiers
+ * related to this path.
+ * @param {Set<String>} identifiersKeys
+ * List of currently registered identifier location key.
+ * @param {Object} path
+ */
+function getIdentifierSymbols(identifiers, identifiersKeys, path) {
+ if (t.isStringLiteral(path) && t.isProperty(path.parentPath)) {
+ if (!identifiersKeys.has(nodeLocationKey(path.node.loc))) {
+ identifiers.push({
+ name: path.node.value,
+ get expression() {
+ delete this.expression;
+ this.expression = getObjectExpressionValue(path.parent);
+ return this.expression;
+ },
+ location: path.node.loc,
+ });
+ }
+ return;
+ }
+
+ if (t.isIdentifier(path) && !t.isGenericTypeAnnotation(path.parent)) {
+ // We want to include function params, but exclude the function name
+ if (t.isClassMethod(path.parent) && !path.inList) {
+ return;
+ }
+
+ if (t.isProperty(path.parentPath) && !isObjectShorthand(path.parent)) {
+ if (!identifiersKeys.has(nodeLocationKey(path.node.loc))) {
+ identifiers.push({
+ name: path.node.name,
+ get expression() {
+ delete this.expression;
+ this.expression = getObjectExpressionValue(path.parent);
+ return this.expression;
+ },
+ location: path.node.loc,
+ });
+ }
+ return;
+ }
+
+ let { start, end } = path.node.loc;
+ if (path.node.typeAnnotation) {
+ const { column } = path.node.typeAnnotation.loc.start;
+ end = { ...end, column };
+ }
+
+ if (!identifiersKeys.has(nodeLocationKey({ start, end }))) {
+ identifiers.push({
+ name: path.node.name,
+ expression: path.node.name,
+ location: { start, end },
+ });
+ }
+ }
+
+ if (t.isThisExpression(path.node)) {
+ if (!identifiersKeys.has(nodeLocationKey(path.node.loc))) {
+ identifiers.push({
+ name: "this",
+ location: path.node.loc,
+ expression: "this",
+ });
+ }
+ }
+
+ if (t.isVariableDeclarator(path)) {
+ const nodeId = path.node.id;
+
+ addPatternIdentifiers(identifiers, identifiersKeys, nodeId);
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/index.js b/devtools/client/debugger/src/workers/parser/index.js
new file mode 100644
index 0000000000..d60c3d32aa
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/index.js
@@ -0,0 +1,55 @@
+/* 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/>. */
+
+import { WorkerDispatcher } from "devtools/client/shared/worker-utils";
+
+const WORKER_URL = "resource://devtools/client/debugger/dist/parser-worker.js";
+
+export class ParserDispatcher extends WorkerDispatcher {
+ constructor(jestUrl) {
+ super(jestUrl || WORKER_URL);
+ }
+
+ findOutOfScopeLocations = this.task("findOutOfScopeLocations");
+ findBestMatchExpression = this.task("findBestMatchExpression");
+
+ getScopes = this.task("getScopes");
+
+ getSymbols = this.task("getSymbols");
+ getFunctionSymbols = this.task("getFunctionSymbols");
+ getClassSymbols = this.task("getClassSymbols");
+ getClosestFunctionName = this.task("getClosestFunctionName");
+
+ async setSource(sourceId, content) {
+ const astSource = {
+ id: sourceId,
+ text: content.type === "wasm" ? "" : content.value,
+ contentType: content.contentType || null,
+ isWasm: content.type === "wasm",
+ };
+
+ return this.invoke("setSource", astSource);
+ }
+
+ mapExpression = this.task("mapExpression");
+
+ clearSources = this.task("clearSources");
+
+ /**
+ * Reports if the location's source can be parsed by this worker.
+ *
+ * @param {Object} location
+ * A debugger frontend location object. See createLocation().
+ * @return {Boolean}
+ * True, if the worker may be able to parse this source.
+ */
+ isLocationSupported(location) {
+ // There might be more sources that the worker doesn't support,
+ // like original sources which aren't JavaScript.
+ // But we can only know with the source's content type,
+ // which isn't available right away.
+ // These source will be ignored from within the worker.
+ return !location.source.isWasm;
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/mapAwaitExpression.js b/devtools/client/debugger/src/workers/parser/mapAwaitExpression.js
new file mode 100644
index 0000000000..ec29d6cf21
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/mapAwaitExpression.js
@@ -0,0 +1,208 @@
+/* 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/>. */
+
+import generate from "@babel/generator";
+import * as t from "@babel/types";
+
+import { hasNode, replaceNode } from "./utils/ast";
+import { isTopLevel } from "./utils/helpers";
+
+function hasTopLevelAwait(ast) {
+ const hasAwait = hasNode(
+ ast,
+ (node, ancestors, b) => t.isAwaitExpression(node) && isTopLevel(ancestors)
+ );
+
+ return hasAwait;
+}
+
+// translates new bindings `var a = 3` into `a = 3`.
+function translateDeclarationIntoAssignment(node) {
+ return node.declarations.reduce((acc, declaration) => {
+ // Don't translate declaration without initial assignment (e.g. `var a;`)
+ if (!declaration.init) {
+ return acc;
+ }
+ acc.push(
+ t.expressionStatement(
+ t.assignmentExpression("=", declaration.id, declaration.init)
+ )
+ );
+ return acc;
+ }, []);
+}
+
+/**
+ * Given an AST, modify it to return the last evaluated statement's expression value if possible.
+ * This is to preserve existing console behavior of displaying the last executed expression value.
+ */
+function addReturnNode(ast) {
+ const statements = ast.program.body;
+ const lastStatement = statements.pop();
+
+ // if the last expression is an awaitExpression, strip the `await` part and directly
+ // return the argument to avoid calling the argument's `then` function twice when the
+ // mapped expression gets evaluated (See Bug 1771428)
+ if (t.isAwaitExpression(lastStatement.expression)) {
+ lastStatement.expression = lastStatement.expression.argument;
+ }
+
+ // NOTE: For more complicated cases such as an if/for statement, the last evaluated
+ // expression value probably can not be displayed, unless doing hacky workarounds such
+ // as returning the `eval` of the final statement (won't always work due to CSP issues?)
+ // or SpiderMonkey support (See Bug 1839588) at which point this entire module can be removed.
+ statements.push(
+ t.isExpressionStatement(lastStatement)
+ ? t.returnStatement(lastStatement.expression)
+ : lastStatement
+ );
+ return statements;
+}
+
+function getDeclarations(node) {
+ const { kind, declarations } = node;
+ const declaratorNodes = declarations.reduce((acc, d) => {
+ const declarators = getVariableDeclarators(d.id);
+ return acc.concat(declarators);
+ }, []);
+
+ // We can't declare const variables outside of the async iife because we
+ // wouldn't be able to re-assign them. As a workaround, we transform them
+ // to `let` which should be good enough for those case.
+ return t.variableDeclaration(
+ kind === "const" ? "let" : kind,
+ declaratorNodes
+ );
+}
+
+function getVariableDeclarators(node) {
+ if (t.isIdentifier(node)) {
+ return t.variableDeclarator(t.identifier(node.name));
+ }
+
+ if (t.isObjectProperty(node)) {
+ return getVariableDeclarators(node.value);
+ }
+ if (t.isRestElement(node)) {
+ return getVariableDeclarators(node.argument);
+ }
+
+ if (t.isAssignmentPattern(node)) {
+ return getVariableDeclarators(node.left);
+ }
+
+ if (t.isArrayPattern(node)) {
+ return node.elements.reduce(
+ (acc, element) => acc.concat(getVariableDeclarators(element)),
+ []
+ );
+ }
+ if (t.isObjectPattern(node)) {
+ return node.properties.reduce(
+ (acc, property) => acc.concat(getVariableDeclarators(property)),
+ []
+ );
+ }
+ return [];
+}
+
+/**
+ * Given an AST and an array of variableDeclaration nodes, return a new AST with
+ * all the declarations at the top of the AST.
+ */
+function addTopDeclarationNodes(ast, declarationNodes) {
+ const statements = [];
+ declarationNodes.forEach(declarationNode => {
+ statements.push(getDeclarations(declarationNode));
+ });
+ statements.push(ast);
+ return t.program(statements);
+}
+
+/**
+ * Given an AST, return an object of the following shape:
+ * - newAst: {AST} the AST where variable declarations were transformed into
+ * variable assignments
+ * - declarations: {Array<Node>} An array of all the declaration nodes needed
+ * outside of the async iife.
+ */
+function translateDeclarationsIntoAssignment(ast) {
+ const declarations = [];
+ t.traverse(ast, (node, ancestors) => {
+ const parent = ancestors[ancestors.length - 1];
+
+ if (
+ t.isWithStatement(node) ||
+ !isTopLevel(ancestors) ||
+ t.isAssignmentExpression(node) ||
+ !t.isVariableDeclaration(node) ||
+ t.isForStatement(parent.node) ||
+ t.isForXStatement(parent.node) ||
+ !Array.isArray(node.declarations) ||
+ node.declarations.length === 0
+ ) {
+ return;
+ }
+
+ const newNodes = translateDeclarationIntoAssignment(node);
+ replaceNode(ancestors, newNodes);
+ declarations.push(node);
+ });
+
+ return {
+ newAst: ast,
+ declarations,
+ };
+}
+
+/**
+ * Given an AST, wrap its body in an async iife, transform variable declarations
+ * in assignments and move the variable declarations outside of the async iife.
+ * Example: With the AST for the following expression: `let a = await 123`, the
+ * function will return:
+ * let a;
+ * (async => {
+ * return a = await 123;
+ * })();
+ */
+function wrapExpressionFromAst(ast) {
+ // Transform let and var declarations into assignments, and get back an array
+ // of variable declarations.
+ let { newAst, declarations } = translateDeclarationsIntoAssignment(ast);
+ const body = addReturnNode(newAst);
+
+ // Create the async iife.
+ newAst = t.expressionStatement(
+ t.callExpression(
+ t.arrowFunctionExpression([], t.blockStatement(body), true),
+ []
+ )
+ );
+
+ // Now let's put all the variable declarations at the top of the async iife.
+ newAst = addTopDeclarationNodes(newAst, declarations);
+
+ return generate(newAst).code;
+}
+
+export default 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);
+}
diff --git a/devtools/client/debugger/src/workers/parser/mapBindings.js b/devtools/client/debugger/src/workers/parser/mapBindings.js
new file mode 100644
index 0000000000..f8260787f1
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/mapBindings.js
@@ -0,0 +1,120 @@
+/* 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/>. */
+
+import { replaceNode } from "./utils/ast";
+import { isTopLevel } from "./utils/helpers";
+
+import generate from "@babel/generator";
+import * as t from "@babel/types";
+
+function getAssignmentTarget(node, bindings) {
+ if (t.isObjectPattern(node)) {
+ for (const property of node.properties) {
+ if (t.isRestElement(property)) {
+ property.argument = getAssignmentTarget(property.argument, bindings);
+ } else {
+ property.value = getAssignmentTarget(property.value, bindings);
+ }
+ }
+
+ return node;
+ }
+
+ if (t.isArrayPattern(node)) {
+ for (const [i, element] of node.elements.entries()) {
+ node.elements[i] = getAssignmentTarget(element, bindings);
+ }
+
+ return node;
+ }
+
+ if (t.isAssignmentPattern(node)) {
+ node.left = getAssignmentTarget(node.left, bindings);
+
+ return node;
+ }
+
+ if (t.isRestElement(node)) {
+ node.argument = getAssignmentTarget(node.argument, bindings);
+
+ return node;
+ }
+
+ if (t.isIdentifier(node)) {
+ return bindings.includes(node.name)
+ ? node
+ : t.memberExpression(t.identifier("self"), node);
+ }
+
+ return node;
+}
+
+// translates new bindings `var a = 3` into `self.a = 3`
+// and existing bindings `var a = 3` into `a = 3` for re-assignments
+function globalizeDeclaration(node, bindings) {
+ return node.declarations.map(declaration =>
+ t.expressionStatement(
+ t.assignmentExpression(
+ "=",
+ getAssignmentTarget(declaration.id, bindings),
+ declaration.init || t.unaryExpression("void", t.numericLiteral(0))
+ )
+ )
+ );
+}
+
+// translates new bindings `a = 3` into `self.a = 3`
+// and keeps assignments the same for existing bindings.
+function globalizeAssignment(node, bindings) {
+ return t.assignmentExpression(
+ node.operator,
+ getAssignmentTarget(node.left, bindings),
+ node.right
+ );
+}
+
+export default function mapExpressionBindings(expression, ast, bindings = []) {
+ let isMapped = false;
+ let shouldUpdate = true;
+
+ t.traverse(ast, (node, ancestors) => {
+ const parent = ancestors[ancestors.length - 1];
+
+ if (t.isWithStatement(node)) {
+ shouldUpdate = false;
+ return;
+ }
+
+ if (!isTopLevel(ancestors)) {
+ return;
+ }
+
+ if (t.isAssignmentExpression(node)) {
+ if (t.isIdentifier(node.left) || t.isPattern(node.left)) {
+ const newNode = globalizeAssignment(node, bindings);
+ isMapped = true;
+ replaceNode(ancestors, newNode);
+ return;
+ }
+
+ return;
+ }
+
+ if (!t.isVariableDeclaration(node)) {
+ return;
+ }
+
+ if (!t.isForStatement(parent.node)) {
+ const newNodes = globalizeDeclaration(node, bindings);
+ isMapped = true;
+ replaceNode(ancestors, newNodes);
+ }
+ });
+
+ if (!shouldUpdate || !isMapped) {
+ return expression;
+ }
+
+ return generate(ast).code;
+}
diff --git a/devtools/client/debugger/src/workers/parser/mapExpression.js b/devtools/client/debugger/src/workers/parser/mapExpression.js
new file mode 100644
index 0000000000..71f3b016fc
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/mapExpression.js
@@ -0,0 +1,50 @@
+/* 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/>. */
+
+import { parseConsoleScript } from "./utils/ast";
+import mapOriginalExpression from "./mapOriginalExpression";
+import mapExpressionBindings from "./mapBindings";
+import mapTopLevelAwait from "./mapAwaitExpression";
+
+export default function mapExpression(
+ expression,
+ mappings,
+ bindings,
+ shouldMapBindings = true,
+ shouldMapAwait = true
+) {
+ const mapped = {
+ await: false,
+ bindings: false,
+ originalExpression: false,
+ };
+
+ const ast = parseConsoleScript(expression);
+ try {
+ if (mappings && ast) {
+ const beforeOriginalExpression = expression;
+ expression = mapOriginalExpression(expression, ast, mappings);
+ mapped.originalExpression = beforeOriginalExpression !== expression;
+ }
+
+ if (shouldMapBindings && ast) {
+ const beforeBindings = expression;
+ expression = mapExpressionBindings(expression, ast, bindings);
+ mapped.bindings = beforeBindings !== expression;
+ }
+
+ if (shouldMapAwait) {
+ const beforeAwait = expression;
+ expression = mapTopLevelAwait(expression, ast);
+ mapped.await = beforeAwait !== expression;
+ }
+ } catch (e) {
+ console.warn(`Error when mapping ${expression} expression:`, e);
+ }
+
+ return {
+ expression,
+ mapped,
+ };
+}
diff --git a/devtools/client/debugger/src/workers/parser/mapOriginalExpression.js b/devtools/client/debugger/src/workers/parser/mapOriginalExpression.js
new file mode 100644
index 0000000000..1724db9838
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/mapOriginalExpression.js
@@ -0,0 +1,106 @@
+/* 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/>. */
+
+import { parseScript } from "./utils/ast";
+import { buildScopeList } from "./getScopes";
+import generate from "@babel/generator";
+import * as t from "@babel/types";
+
+// NOTE: this will only work if we are replacing an original identifier
+function replaceNode(ancestors, node) {
+ const ancestor = ancestors[ancestors.length - 1];
+
+ if (typeof ancestor.index === "number") {
+ ancestor.node[ancestor.key][ancestor.index] = node;
+ } else {
+ ancestor.node[ancestor.key] = node;
+ }
+}
+
+function getFirstExpression(ast) {
+ const statements = ast.program.body;
+ if (!statements.length) {
+ return null;
+ }
+
+ return statements[0].expression;
+}
+
+function locationKey(start) {
+ return `${start.line}:${start.column}`;
+}
+
+export default function mapOriginalExpression(expression, ast, mappings) {
+ const scopes = buildScopeList(ast, "");
+ let shouldUpdate = false;
+
+ const nodes = new Map();
+ const replacements = new Map();
+
+ // The ref-only global bindings are the ones that are accessed, but not
+ // declared anywhere in the parsed code, meaning they are either global,
+ // or declared somewhere in a scope outside the parsed code, so we
+ // rewrite all of those specifically to avoid rewritting declarations that
+ // shadow outer mappings.
+ for (const name of Object.keys(scopes[0].bindings)) {
+ const { refs } = scopes[0].bindings[name];
+ const mapping = mappings[name];
+
+ if (
+ !refs.every(ref => ref.type === "ref") ||
+ !mapping ||
+ mapping === name
+ ) {
+ continue;
+ }
+
+ let node = nodes.get(name);
+ if (!node) {
+ node = getFirstExpression(parseScript(mapping));
+ nodes.set(name, node);
+ }
+
+ for (const ref of refs) {
+ let { line, column } = ref.start;
+
+ // This shouldn't happen, just keeping Flow happy.
+ if (typeof column !== "number") {
+ column = 0;
+ }
+
+ replacements.set(locationKey({ line, column }), node);
+ }
+ }
+
+ if (replacements.size === 0) {
+ // Avoid the extra code generation work and also avoid potentially
+ // reformatting the user's code unnecessarily.
+ return expression;
+ }
+
+ t.traverse(ast, (node, ancestors) => {
+ if (!t.isIdentifier(node) && !t.isThisExpression(node)) {
+ return;
+ }
+
+ const ancestor = ancestors[ancestors.length - 1];
+ // Shorthand properties can have a key and value with `node.loc.start` value
+ // and we only want to replace the value.
+ if (t.isObjectProperty(ancestor.node) && ancestor.key !== "value") {
+ return;
+ }
+
+ const replacement = replacements.get(locationKey(node.loc.start));
+ if (replacement) {
+ replaceNode(ancestors, t.cloneNode(replacement));
+ shouldUpdate = true;
+ }
+ });
+
+ if (shouldUpdate) {
+ return generate(ast).code;
+ }
+
+ return expression;
+}
diff --git a/devtools/client/debugger/src/workers/parser/moz.build b/devtools/client/debugger/src/workers/parser/moz.build
new file mode 100644
index 0000000000..b7223ac81a
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/moz.build
@@ -0,0 +1,10 @@
+# vim: set filetype=python:
+# 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/.
+
+DIRS += []
+
+CompiledModules(
+ "index.js",
+)
diff --git a/devtools/client/debugger/src/workers/parser/sources.js b/devtools/client/debugger/src/workers/parser/sources.js
new file mode 100644
index 0000000000..24d358c566
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/sources.js
@@ -0,0 +1,24 @@
+/* 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/>. */
+
+const cachedSources = new Map();
+
+export function setSource(source) {
+ cachedSources.set(source.id, source);
+}
+
+export function getSource(sourceId) {
+ const source = cachedSources.get(sourceId);
+ if (!source) {
+ throw new Error(`Parser: source ${sourceId} was not provided.`);
+ }
+
+ return source;
+}
+
+export function clearSources(sourceIds) {
+ for (const sourceId of sourceIds) {
+ cachedSources.delete(sourceId);
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/__snapshots__/findOutOfScopeLocations.spec.js.snap b/devtools/client/debugger/src/workers/parser/tests/__snapshots__/findOutOfScopeLocations.spec.js.snap
new file mode 100644
index 0000000000..4689f0c824
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/__snapshots__/findOutOfScopeLocations.spec.js.snap
@@ -0,0 +1,47 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Parser.findOutOfScopeLocations should exclude function for locations on declaration 1`] = `
+"(1, 0) -> (1, 16)
+(3, 14) -> (27, 1)
+(29, 16) -> (33, 1)
+(35, 20) -> (37, 1)
+(39, 26) -> (41, 1)
+(43, 20) -> (45, 1)
+(47, 31) -> (49, 1)
+(51, 19) -> (62, 1)"
+`;
+
+exports[`Parser.findOutOfScopeLocations should exclude non-enclosing function blocks 1`] = `
+"(1, 0) -> (1, 16)
+(8, 16) -> (10, 3)
+(12, 22) -> (14, 3)
+(16, 16) -> (18, 3)
+(20, 27) -> (22, 3)
+(24, 9) -> (26, 3)
+(29, 16) -> (33, 1)
+(35, 20) -> (37, 1)
+(39, 26) -> (41, 1)
+(43, 20) -> (45, 1)
+(47, 31) -> (49, 1)
+(51, 19) -> (62, 1)"
+`;
+
+exports[`Parser.findOutOfScopeLocations should not exclude in-scope inner locations 1`] = `
+"(1, 0) -> (1, 16)
+(3, 14) -> (27, 1)
+(29, 16) -> (33, 1)
+(35, 20) -> (37, 1)
+(39, 26) -> (41, 1)
+(43, 20) -> (45, 1)
+(47, 31) -> (49, 1)"
+`;
+
+exports[`Parser.findOutOfScopeLocations should roll up function blocks 1`] = `
+"(1, 0) -> (1, 16)
+(29, 16) -> (33, 1)
+(35, 20) -> (37, 1)
+(39, 26) -> (41, 1)
+(43, 20) -> (45, 1)
+(47, 31) -> (49, 1)
+(51, 19) -> (62, 1)"
+`;
diff --git a/devtools/client/debugger/src/workers/parser/tests/__snapshots__/getScopes.spec.js.snap b/devtools/client/debugger/src/workers/parser/tests/__snapshots__/getScopes.spec.js.snap
new file mode 100644
index 0000000000..b579b89587
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/__snapshots__/getScopes.spec.js.snap
@@ -0,0 +1,18895 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Parser.getScopes finds scope bindings and exclude Flowtype: getScopes finds scope bindings and exclude Flowtype at line 8 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "aConst": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 39,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ "root": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 9,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 9,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "start": Object {
+ "column": 24,
+ "line": 9,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 22,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 16,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings and exclude Flowtype: getScopes finds scope bindings and exclude Flowtype at line 10 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "root",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 9,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "aConst": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 39,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ "root": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 9,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 9,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "start": Object {
+ "column": 24,
+ "line": 9,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 22,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 16,
+ "line": 7,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/flowtype-bindings/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for arrow functions: getScopes finds scope bindings for arrow functions at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 18,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 13,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 13,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 17,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for arrow functions: getScopes finds scope bindings for arrow functions at line 4 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "p1": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 13,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "outer",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 13,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 18,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 13,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 13,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 17,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for arrow functions: getScopes finds scope bindings for arrow functions at line 7 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "inner": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 6,
+ "line": 9,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 22,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 18,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "anonymous",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 3,
+ "line": 6,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "p1": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 13,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "outer",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 13,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 18,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 13,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 13,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 17,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for arrow functions: getScopes finds scope bindings for arrow functions at line 8 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "p2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 5,
+ "line": 9,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 16,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 19,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 17,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "inner",
+ "end": Object {
+ "column": 5,
+ "line": 9,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 17,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "inner": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 6,
+ "line": 9,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 22,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 18,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "anonymous",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 3,
+ "line": 6,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "p1": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 13,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "outer",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 13,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 18,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 13,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 13,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 17,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/arrow-function/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for block statements: getScopes finds scope bindings for block statements at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "first": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "second": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 6,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 6,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seventh": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 13,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 13,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 13,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for block statements: getScopes finds scope bindings for block statements at line 6 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Fourth": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 17,
+ "line": 8,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 8,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 8,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 8,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "fifth": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 9,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 9,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 9,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "sixth": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 18,
+ "line": 10,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 10,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 10,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ "third": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 21,
+ "line": 7,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 7,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 16,
+ "line": 7,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Block",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "first": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "second": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 6,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 6,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seventh": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 13,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 13,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 13,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/block-statement/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class declarations: getScopes finds scope bindings for class declarations at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "Second": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 15,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 15,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 19,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "decorator": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 10,
+ "line": 13,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 13,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class declarations: getScopes finds scope bindings for class declarations at line 5 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Inner": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 5,
+ "line": 9,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Function Body",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 11,
+ "line": 4,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "method",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "Second": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 15,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 15,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 19,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "decorator": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 10,
+ "line": 13,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 13,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class declarations: getScopes finds scope bindings for class declarations at line 7 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 24,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 20,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "m",
+ "end": Object {
+ "column": 7,
+ "line": 8,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Inner": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 5,
+ "line": 9,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 5,
+ "line": 9,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Inner": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 5,
+ "line": 9,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 5,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Function Body",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 11,
+ "line": 4,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "method",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "Second": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 15,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 14,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 15,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 19,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "decorator": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 10,
+ "line": 13,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 13,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-declaration/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class expressions: getScopes finds scope bindings for class expressions at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 15,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 19,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class expressions: getScopes finds scope bindings for class expressions at line 5 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Inner": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 6,
+ "line": 9,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 5,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "method",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 23,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 18,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 15,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 19,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class expressions: getScopes finds scope bindings for class expressions at line 7 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 24,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 20,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "m",
+ "end": Object {
+ "column": 7,
+ "line": 8,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Inner": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 6,
+ "line": 9,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 5,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "method",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 23,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 18,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 15,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 19,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-expression/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class properties: getScopes finds scope bindings for class properties at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class properties: getScopes finds scope bindings for class properties at line 4 column 16 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 13,
+ "line": 4,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 18,
+ "line": 4,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 20,
+ "line": 4,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "parent": null,
+ "start": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "call",
+ },
+ "property": "init",
+ "start": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Class Field",
+ "end": Object {
+ "column": 20,
+ "line": 4,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class properties: getScopes finds scope bindings for class properties at line 6 column 12 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 7,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Class Field",
+ "end": Object {
+ "column": 3,
+ "line": 9,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 10,
+ "line": 6,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for class properties: getScopes finds scope bindings for class properties at line 7 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "two": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 8,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 8,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 8,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 8,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Block",
+ "end": Object {
+ "column": 3,
+ "line": 9,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 13,
+ "line": 6,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 7,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Class Field",
+ "end": Object {
+ "column": 3,
+ "line": 9,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 10,
+ "line": 6,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 10,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/class-property/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for complex binding nesting: getScopes finds scope bindings for complex binding nesting at line 16 column 4 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "_arguments": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 31,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "var",
+ },
+ Object {
+ "end": Object {
+ "column": 35,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 25,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "_this": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 31,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "var",
+ },
+ Object {
+ "end": Object {
+ "column": 23,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 18,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "arg": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 23,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 17,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "arguments": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 30,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 21,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 31,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 22,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "arrow": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 6,
+ "line": 21,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "var",
+ },
+ Object {
+ "end": Object {
+ "column": 9,
+ "line": 22,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 20,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 16,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 20,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 16,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "fn",
+ "end": Object {
+ "column": 3,
+ "line": 23,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 23,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 32,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 30,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 34,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 32,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 4,
+ "line": 25,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 9,
+ "line": 25,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "call",
+ "start": Object {
+ "column": 2,
+ "line": 25,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 25,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "root",
+ "end": Object {
+ "column": 1,
+ "line": 26,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "__webpack_require__": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 51,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 32,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "exports": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 23,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ Object {
+ "end": Object {
+ "column": 29,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 22,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "default",
+ "start": Object {
+ "column": 0,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 24,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 35,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "default",
+ "start": Object {
+ "column": 17,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 17,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "module": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 21,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 14,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "exports",
+ "start": Object {
+ "column": 0,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "root": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 26,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 10,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 22,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 18,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 38,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 34,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 40,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 36,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "named",
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 30,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Object": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 21,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "defineProperty",
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 13,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 17,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 6,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 13,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 17,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 6,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "named": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 30,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for complex binding nesting: getScopes finds scope bindings for complex binding nesting at line 20 column 6 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "argArrow": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 5,
+ "line": 21,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 16,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 39,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 31,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "arrow",
+ "end": Object {
+ "column": 5,
+ "line": 21,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 31,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "arrow": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 5,
+ "line": 21,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 16,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 30,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 25,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-expr",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Function Expression",
+ "end": Object {
+ "column": 5,
+ "line": 21,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 16,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "_arguments": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 31,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "var",
+ },
+ Object {
+ "end": Object {
+ "column": 35,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 25,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "_this": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 31,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "var",
+ },
+ Object {
+ "end": Object {
+ "column": 23,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 18,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "arg": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 23,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 17,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "arguments": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 30,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 21,
+ "line": 13,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 31,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 22,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "arrow": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 6,
+ "line": 21,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 18,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "var",
+ },
+ Object {
+ "end": Object {
+ "column": 9,
+ "line": 22,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 20,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 16,
+ "line": 12,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 20,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 16,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "fn",
+ "end": Object {
+ "column": 3,
+ "line": 23,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 23,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 11,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 32,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 30,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 34,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 32,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 4,
+ "line": 25,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 9,
+ "line": 25,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "call",
+ "start": Object {
+ "column": 2,
+ "line": 25,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 25,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "root",
+ "end": Object {
+ "column": 1,
+ "line": 26,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "__webpack_require__": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 51,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 32,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "exports": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 23,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ Object {
+ "end": Object {
+ "column": 29,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 22,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "default",
+ "start": Object {
+ "column": 0,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 24,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 35,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "default",
+ "start": Object {
+ "column": 17,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 17,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "module": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 21,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 14,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "exports",
+ "start": Object {
+ "column": 0,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 27,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "root": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 26,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 10,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 22,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 18,
+ "line": 9,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 38,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 34,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 40,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 36,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "named",
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 30,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Object": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 21,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "defineProperty",
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 15,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 16,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 13,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 17,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 6,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 19,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 13,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 17,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 6,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 20,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "named": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 29,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 30,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/complex-nesting/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for declarations with patterns: getScopes finds scope bindings for declarations with patterns at line 1 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 1,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 1,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "two": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 17,
+ "line": 2,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 2,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 2,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 2,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/pattern-declarations/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 3 column 17 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 4 column 17 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "two": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 4,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "For",
+ "end": Object {
+ "column": 18,
+ "line": 4,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 5,
+ "line": 4,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 5 column 25 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "three": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 20,
+ "line": 5,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 5,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 16,
+ "line": 5,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 5,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "For",
+ "end": Object {
+ "column": 26,
+ "line": 5,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 5,
+ "line": 5,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 7 column 22 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 8 column 22 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "five": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 8,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 8,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 8,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 8,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "For",
+ "end": Object {
+ "column": 23,
+ "line": 8,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 5,
+ "line": 8,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 9 column 23 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "six": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 9,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 9,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 9,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "For",
+ "end": Object {
+ "column": 24,
+ "line": 9,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 5,
+ "line": 9,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 11 column 23 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 12 column 23 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "eight": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 12,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 12,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 12,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 12,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "For",
+ "end": Object {
+ "column": 24,
+ "line": 12,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 5,
+ "line": 12,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for for loops: getScopes finds scope bindings for for loops at line 13 column 24 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "nine": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 15,
+ "line": 13,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 13,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 13,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 13,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "For",
+ "end": Object {
+ "column": 25,
+ "line": 13,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 5,
+ "line": 13,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "four": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "seven": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 11,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/for-loops/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for function declarations: getScopes finds scope bindings for function declarations at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 21,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for function declarations: getScopes finds scope bindings for function declarations at line 3 column 20 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "p1": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 21,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 17,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "outer",
+ "end": Object {
+ "column": 21,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 21,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for function declarations: getScopes finds scope bindings for function declarations at line 5 column 1 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "middle": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 17,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Block",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 21,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for function declarations: getScopes finds scope bindings for function declarations at line 9 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "inner": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 25,
+ "line": 7,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 7,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 7,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 13,
+ "line": 7,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "p2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 20,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 18,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 20,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 16,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "middle",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 18,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "middle": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 17,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 6,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Block",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "outer": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 21,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-declaration/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for function expressions: getScopes finds scope bindings for function expressions at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 25,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "fn2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 7,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 13,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for function expressions: getScopes finds scope bindings for function expressions at line 3 column 23 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "p1": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 24,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 20,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 18,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "fn",
+ "end": Object {
+ "column": 24,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 18,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 25,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "fn2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 7,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 13,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for function expressions: getScopes finds scope bindings for function expressions at line 6 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "p2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 7,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 30,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 28,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 18,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "withName",
+ "end": Object {
+ "column": 1,
+ "line": 7,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 28,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "withName": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 7,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 27,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 19,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "fn-expr",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Function Expression",
+ "end": Object {
+ "column": 1,
+ "line": 7,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 10,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 25,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "fn2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 2,
+ "line": 7,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 13,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/function-expression/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for out of order declarations: getScopes finds scope bindings for out of order declarations at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "aDefault": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 33,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "root": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 24,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 39,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 35,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 8,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for out of order declarations: getScopes finds scope bindings for out of order declarations at line 5 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "callback": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 16,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 19,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 33,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 25,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 10,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 12,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "parent": null,
+ "start": Object {
+ "column": 2,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "call",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 2,
+ "line": 8,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 10,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "root",
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "aDefault": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 33,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "root": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 24,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 39,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 35,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 8,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for out of order declarations: getScopes finds scope bindings for out of order declarations at line 11 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 19,
+ "line": 15,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 15,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 15,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 13,
+ "line": 15,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 23,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 21,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 45,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 41,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 13,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 13,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 13,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 13,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 16,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "callback",
+ "end": Object {
+ "column": 3,
+ "line": 16,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "callback": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 16,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 19,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 33,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 25,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 10,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 12,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "parent": null,
+ "start": Object {
+ "column": 2,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "call",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 2,
+ "line": 8,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 10,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "root",
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "aDefault": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 33,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "root": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 24,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 39,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 35,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 8,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for out of order declarations: getScopes finds scope bindings for out of order declarations at line 14 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 19,
+ "line": 15,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 15,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 15,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 13,
+ "line": 15,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 23,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 21,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 45,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 41,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 13,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 13,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 13,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 13,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 16,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "callback",
+ "end": Object {
+ "column": 3,
+ "line": 16,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "callback": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 16,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 19,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 33,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 25,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 10,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 12,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "parent": null,
+ "start": Object {
+ "column": 2,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "call",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 2,
+ "line": 8,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 10,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "root",
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "aDefault": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 33,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "root": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 24,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 39,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 35,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 8,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for out of order declarations: getScopes finds scope bindings for out of order declarations at line 17 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "callback": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 16,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 19,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 10,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 33,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 25,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 10,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 12,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "parent": null,
+ "start": Object {
+ "column": 2,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "call",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 18,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 6,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 2,
+ "line": 8,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 10,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 4,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "root",
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "aDefault": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 33,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 21,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "root": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 24,
+ "line": 3,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 39,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 35,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "val": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 8,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 15,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/out-of-order-declarations/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for switch statements: getScopes finds scope bindings for switch statements at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "zero": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for switch statements: getScopes finds scope bindings for switch statements at line 5 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "two": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Switch",
+ "end": Object {
+ "column": 1,
+ "line": 13,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "zero": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for switch statements: getScopes finds scope bindings for switch statements at line 7 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "two": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Switch",
+ "end": Object {
+ "column": 1,
+ "line": 13,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "zero": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for switch statements: getScopes finds scope bindings for switch statements at line 9 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "two": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Switch",
+ "end": Object {
+ "column": 1,
+ "line": 13,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "zero": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for switch statements: getScopes finds scope bindings for switch statements at line 11 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "three": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 14,
+ "line": 11,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 11,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 11,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Block",
+ "end": Object {
+ "column": 3,
+ "line": 12,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 16,
+ "line": 10,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 7,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "two": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 9,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Switch",
+ "end": Object {
+ "column": 1,
+ "line": 13,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "zero": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for switch statements: getScopes finds scope bindings for switch statements at line 17 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "two": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 20,
+ "line": 17,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 17,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 16,
+ "line": 17,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 13,
+ "line": 17,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Switch",
+ "end": Object {
+ "column": 1,
+ "line": 18,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "zero": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for switch statements: getScopes finds scope bindings for switch statements at line 21 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "three": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 18,
+ "line": 21,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 21,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 21,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 21,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Switch",
+ "end": Object {
+ "column": 1,
+ "line": 22,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "zero": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 5,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 3,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 15,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 8,
+ "line": 19,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 23,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/switch-statement/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for try..catch: getScopes finds scope bindings for try..catch at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "first": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "third": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for try..catch: getScopes finds scope bindings for try..catch at line 4 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "second": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 5,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 5,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 5,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 5,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Block",
+ "end": Object {
+ "column": 1,
+ "line": 6,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 4,
+ "line": 3,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "first": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "third": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings for try..catch: getScopes finds scope bindings for try..catch at line 7 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "fourth": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 8,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 8,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 8,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 8,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Block",
+ "end": Object {
+ "column": 1,
+ "line": 9,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 14,
+ "line": 6,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "err": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 9,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 6,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "catch",
+ },
+ ],
+ "type": "var",
+ },
+ },
+ "displayName": "Catch",
+ "end": Object {
+ "column": 1,
+ "line": 9,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 6,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "first": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 4,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "third": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/try-catch/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a JSX element: getScopes finds scope bindings in a JSX element at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "SomeComponent": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 29,
+ "line": 1,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 20,
+ "line": 1,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 14,
+ "line": 3,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 3,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 14,
+ "line": 4,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 4,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 14,
+ "line": 5,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 5,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 14,
+ "line": 6,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 6,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "import",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/jsx-component/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a module: getScopes finds scope bindings in a module at line 7 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 16,
+ "line": 9,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 9,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 9,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 9,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 22,
+ "line": 1,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 1,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 15,
+ "line": 3,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 12,
+ "line": 3,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "import",
+ },
+ "one": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 5,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 5,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 5,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 4,
+ "line": 11,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 0,
+ "line": 11,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "three": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 16,
+ "line": 7,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 7,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ "two": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 12,
+ "line": 6,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 6,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 6,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "console": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 3,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 11,
+ "line": 3,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "parent": null,
+ "property": "log",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 12,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/simple-module/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a typescript file: getScopes finds scope bindings in a typescript file at line 9 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Color": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 8,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ts-enum-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 16,
+ "line": 41,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 9,
+ "line": 41,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "let",
+ },
+ "TheSpace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ts-namespace-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 22,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Error": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 17,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 17,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 21,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 15,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 25,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 25,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 28,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 28,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a typescript file: getScopes finds scope bindings in a typescript file at line 13 column 4 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 14,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 12,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 24,
+ "line": 12,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 21,
+ "line": 12,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "constructor",
+ "end": Object {
+ "column": 3,
+ "line": 14,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 14,
+ "line": 12,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Color": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 8,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ts-enum-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 16,
+ "line": 41,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 9,
+ "line": 41,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "let",
+ },
+ "TheSpace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ts-namespace-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 22,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Error": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 17,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 17,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 21,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 15,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 25,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 25,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 28,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 28,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a typescript file: getScopes finds scope bindings in a typescript file at line 17 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "method",
+ "end": Object {
+ "column": 3,
+ "line": 18,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 16,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Color": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 8,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ts-enum-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 16,
+ "line": 41,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 9,
+ "line": 41,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "let",
+ },
+ "TheSpace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ts-namespace-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 22,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Error": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 17,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 17,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 21,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 15,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 25,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 25,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 28,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 28,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a typescript file: getScopes finds scope bindings in a typescript file at line 33 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "fn",
+ "end": Object {
+ "column": 3,
+ "line": 34,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 32,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 34,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 32,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 32,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 32,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "TypeScript Namespace",
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 19,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Color": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 8,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ts-enum-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 16,
+ "line": 41,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 9,
+ "line": 41,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "let",
+ },
+ "TheSpace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 31,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ts-namespace-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 22,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Error": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 17,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 17,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 21,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 15,
+ "line": 22,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 25,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 25,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 28,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 28,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/ts-sample/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a typescript-jsx file: getScopes finds scope bindings in a typescript-jsx file at line 9 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Color": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 8,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ts-enum-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 16,
+ "line": 41,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 9,
+ "line": 41,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "let",
+ },
+ "TheSpace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ts-namespace-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 28,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Error": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 17,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 17,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "any": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 14,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 11,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 25,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 25,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 28,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 28,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a typescript-jsx file: getScopes finds scope bindings in a typescript-jsx file at line 13 column 4 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 14,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 12,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 24,
+ "line": 12,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 21,
+ "line": 12,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "fn-param",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "constructor",
+ "end": Object {
+ "column": 3,
+ "line": 14,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 14,
+ "line": 12,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Color": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 8,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ts-enum-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 16,
+ "line": 41,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 9,
+ "line": 41,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "let",
+ },
+ "TheSpace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ts-namespace-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 28,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Error": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 17,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 17,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "any": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 14,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 11,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 25,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 25,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 28,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 28,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a typescript-jsx file: getScopes finds scope bindings in a typescript-jsx file at line 17 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "method",
+ "end": Object {
+ "column": 3,
+ "line": 18,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 16,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Color": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 8,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ts-enum-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 16,
+ "line": 41,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 9,
+ "line": 41,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "let",
+ },
+ "TheSpace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ts-namespace-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 28,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Error": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 17,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 17,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "any": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 14,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 11,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 25,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 25,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 28,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 28,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a typescript-jsx file: getScopes finds scope bindings in a typescript-jsx file at line 33 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "fn",
+ "end": Object {
+ "column": 3,
+ "line": 34,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 32,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 3,
+ "line": 34,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 32,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 32,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 32,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "TypeScript Namespace",
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 19,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Color": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 8,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 5,
+ "line": 3,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ts-enum-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "Example": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 19,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 10,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ Object {
+ "end": Object {
+ "column": 16,
+ "line": 41,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 9,
+ "line": 41,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "let",
+ },
+ "TheSpace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 35,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 31,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ts-namespace-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 28,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 7,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Error": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 17,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 14,
+ "line": 17,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "any": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 14,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 11,
+ "line": 22,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "window": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 25,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 25,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 28,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 1,
+ "line": 28,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 42,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/tsx-sample/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in a vue file: getScopes finds scope bindings in a vue file at line 14 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "fnVar": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 18,
+ "line": 13,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 13,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 13,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 13,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "data",
+ "end": Object {
+ "column": 3,
+ "line": 18,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 12,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "moduleVar": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 23,
+ "line": 8,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 8,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 8,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 8,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 1,
+ "line": 27,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 1,
+ "line": 27,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 1,
+ "line": 27,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/vue-sample/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in fn body with both lex and non-lex items: getScopes finds scope bindings in fn body with both lex and non-lex items at line 4 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "lex": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 10,
+ "line": 3,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 3,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 3,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Function Body",
+ "end": Object {
+ "column": 1,
+ "line": 5,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 14,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "nonlex": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 2,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 2,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 2,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 2,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "fn",
+ "end": Object {
+ "column": 1,
+ "line": 5,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 24,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 5,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn3": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 17,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn4": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 23,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 24,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in fn body with both lex and non-lex items: getScopes finds scope bindings in fn body with both lex and non-lex items at line 10 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "lex": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 10,
+ "line": 9,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 9,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 9,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 9,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Function Body",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "nonlex": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 21,
+ "line": 8,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 8,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 17,
+ "line": 8,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 8,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "fn2",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 24,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 5,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn3": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 17,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn4": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 23,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 24,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in fn body with both lex and non-lex items: getScopes finds scope bindings in fn body with both lex and non-lex items at line 16 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Thing": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 16,
+ "line": 15,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 15,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 15,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 15,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Function Body",
+ "end": Object {
+ "column": 1,
+ "line": 17,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "nonlex": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 13,
+ "line": 14,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 14,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 14,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 14,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "fn3",
+ "end": Object {
+ "column": 1,
+ "line": 17,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 24,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 5,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn3": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 17,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn4": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 23,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 24,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings in fn body with both lex and non-lex items: getScopes finds scope bindings in fn body with both lex and non-lex items at line 22 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "Thing": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 16,
+ "line": 21,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 21,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 13,
+ "line": 21,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 8,
+ "line": 21,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Function Body",
+ "end": Object {
+ "column": 1,
+ "line": 23,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 15,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "nonlex": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 21,
+ "line": 20,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 20,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 17,
+ "line": 20,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 20,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "fn4",
+ "end": Object {
+ "column": 1,
+ "line": 23,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 24,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 5,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn2": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn3": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 17,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 13,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "fn4": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 23,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 19,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 24,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/fn-body-lex-and-nonlex/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings with expression metadata: getScopes finds scope bindings with expression metadata at line 2 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "foo": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 15,
+ "line": 1,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 1,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 1,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "const",
+ },
+ Object {
+ "end": Object {
+ "column": 3,
+ "line": 3,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 7,
+ "line": 3,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 9,
+ "line": 3,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 13,
+ "line": 3,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": null,
+ "property": "baz",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "call",
+ },
+ "property": "bar",
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 7,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 11,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 14,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 18,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": null,
+ "property": "baz",
+ "start": Object {
+ "column": 0,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "call",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "inherit",
+ },
+ "property": "bar",
+ "start": Object {
+ "column": 4,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 4,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 10,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 14,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 15,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 17,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 21,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": null,
+ "property": "baz",
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "call",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "inherit",
+ },
+ "property": "bar",
+ "start": Object {
+ "column": 7,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 7,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "ref",
+ },
+ Object {
+ "end": Object {
+ "column": 25,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 29,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 30,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 32,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": Object {
+ "end": Object {
+ "column": 36,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": null,
+ "property": "baz",
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "call",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "inherit",
+ },
+ "property": "bar",
+ "start": Object {
+ "column": 22,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 22,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "Object": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 0,
+ "line": 5,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "__webpack_require__": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 19,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "meta": Object {
+ "end": Object {
+ "column": 21,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "parent": null,
+ "property": "i",
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "member",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "global",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/expressions/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings with proper types: getScopes finds scope bindings with proper types at line 5 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "aConst": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 18,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ "aLet": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "aVar": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "cls": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "def": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 19,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 16,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "named": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 25,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "named",
+ "start": Object {
+ "column": 9,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "namespace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 30,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 21,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-ns-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "otherNamed": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 39,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "thing",
+ "start": Object {
+ "column": 18,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings with proper types: getScopes finds scope bindings with proper types at line 9 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "method",
+ "end": Object {
+ "column": 3,
+ "line": 10,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 2,
+ "line": 8,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "cls": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "class-inner",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Class",
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "aConst": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 18,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ "aLet": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "aVar": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "cls": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "def": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 19,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 16,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "named": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 25,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "named",
+ "start": Object {
+ "column": 9,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "namespace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 30,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 21,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-ns-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "otherNamed": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 39,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "thing",
+ "start": Object {
+ "column": 18,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings with proper types: getScopes finds scope bindings with proper types at line 18 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "arguments": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 11,
+ "line": 19,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 2,
+ "line": 19,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ "this": Object {
+ "refs": Array [
+ Object {
+ "end": Object {
+ "column": 6,
+ "line": 18,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "meta": null,
+ "start": Object {
+ "column": 2,
+ "line": 18,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "ref",
+ },
+ ],
+ "type": "implicit",
+ },
+ },
+ "displayName": "inner",
+ "end": Object {
+ "column": 1,
+ "line": 20,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 1,
+ "line": 17,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "function",
+ },
+ Object {
+ "bindings": Object {
+ "inner": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 20,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 1,
+ "line": 17,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 15,
+ "line": 17,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 10,
+ "line": 17,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "fn-expr",
+ },
+ ],
+ "type": "const",
+ },
+ },
+ "displayName": "Function Expression",
+ "end": Object {
+ "column": 1,
+ "line": 20,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 1,
+ "line": 17,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "aConst": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 18,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ "aLet": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "aVar": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "cls": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "def": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 19,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 16,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "named": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 25,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "named",
+ "start": Object {
+ "column": 9,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "namespace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 30,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 21,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-ns-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "otherNamed": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 39,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "thing",
+ "start": Object {
+ "column": 18,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
+
+exports[`Parser.getScopes finds scope bindings with proper types: getScopes finds scope bindings with proper types at line 23 column 0 1`] = `
+Array [
+ Object {
+ "bindings": Object {
+ "blockFn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 22,
+ "line": 23,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 2,
+ "line": 23,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 18,
+ "line": 23,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 11,
+ "line": 23,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "let",
+ },
+ },
+ "displayName": "Block",
+ "end": Object {
+ "column": 1,
+ "line": 24,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 22,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {
+ "aConst": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 18,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 12,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 15,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "const",
+ },
+ ],
+ "type": "const",
+ },
+ "aLet": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 14,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "let",
+ },
+ ],
+ "type": "let",
+ },
+ "aVar": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 9,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 8,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 4,
+ "line": 13,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "var",
+ },
+ ],
+ "type": "var",
+ },
+ "cls": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 1,
+ "line": 11,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 9,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 6,
+ "line": 7,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "class-decl",
+ },
+ ],
+ "type": "let",
+ },
+ "def": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 19,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 10,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "default",
+ "start": Object {
+ "column": 7,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "fn": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 16,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 11,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 9,
+ "line": 6,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "fn-decl",
+ },
+ ],
+ "type": "var",
+ },
+ "named": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 25,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 14,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "named",
+ "start": Object {
+ "column": 9,
+ "line": 2,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "namespace": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 30,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 21,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 12,
+ "line": 4,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-ns-decl",
+ },
+ ],
+ "type": "const",
+ },
+ "otherNamed": Object {
+ "refs": Array [
+ Object {
+ "declaration": Object {
+ "end": Object {
+ "column": 39,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "start": Object {
+ "column": 0,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ },
+ "end": Object {
+ "column": 28,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "importName": "thing",
+ "start": Object {
+ "column": 18,
+ "line": 3,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "import-decl",
+ },
+ ],
+ "type": "import",
+ },
+ "this": Object {
+ "refs": Array [],
+ "type": "implicit",
+ },
+ },
+ "displayName": "Module",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Lexical Global",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "block",
+ },
+ Object {
+ "bindings": Object {},
+ "displayName": "Global",
+ "end": Object {
+ "column": 0,
+ "line": 25,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "scopeKind": "",
+ "start": Object {
+ "column": 0,
+ "line": 1,
+ "sourceId": "scopes/binding-types/originalSource-1",
+ },
+ "type": "object",
+ },
+]
+`;
diff --git a/devtools/client/debugger/src/workers/parser/tests/__snapshots__/getSymbols.spec.js.snap b/devtools/client/debugger/src/workers/parser/tests/__snapshots__/getSymbols.spec.js.snap
new file mode 100644
index 0000000000..d1fd35376d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/__snapshots__/getSymbols.spec.js.snap
@@ -0,0 +1,169 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Parser.getSymbols allSymbols 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols call expression 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols call sites 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols class 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols component 1`] = `
+"hasJsx: true
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols destruct 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols es6 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols expression 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols finds symbols in an html file 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols flow 1`] = `
+"hasJsx: false
+
+hasTypes: true
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols func 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols function names 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols jsx 1`] = `
+"hasJsx: true
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols math 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols object expressions 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols optional chaining 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols private fields 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols proto 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols react component 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: React"
+`;
+
+exports[`Parser.getSymbols regexp 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
+
+exports[`Parser.getSymbols var 1`] = `
+"hasJsx: false
+
+hasTypes: false
+
+framework: null"
+`;
diff --git a/devtools/client/debugger/src/workers/parser/tests/__snapshots__/validate.spec.js.snap b/devtools/client/debugger/src/workers/parser/tests/__snapshots__/validate.spec.js.snap
new file mode 100644
index 0000000000..a341538a5d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/__snapshots__/validate.spec.js.snap
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`has syntax error should return the error object for the invalid expression 1`] = `"SyntaxError : Missing semicolon. (1:3)"`;
diff --git a/devtools/client/debugger/src/workers/parser/tests/contains.spec.js b/devtools/client/debugger/src/workers/parser/tests/contains.spec.js
new file mode 100644
index 0000000000..741f1a29fc
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/contains.spec.js
@@ -0,0 +1,250 @@
+/* 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/>. */
+
+import { containsPosition, containsLocation } from "../utils/contains";
+
+function getTestLoc() {
+ return {
+ start: {
+ line: 10,
+ column: 2,
+ },
+ end: {
+ line: 12,
+ column: 10,
+ },
+ };
+}
+
+// AstPosition.column is typed as a number, but many parts of this test set it
+// to undefined. Using zero instead causes test failures, and allowing it to be
+// undefined causes many flow errors in code manipulating AstPosition.
+// Fake a coercion of undefined to number as a workaround for now.
+function undefinedColumn() {
+ return undefined;
+}
+
+function startPos(lineOffset, columnOffset) {
+ const { start } = getTestLoc();
+ return {
+ line: start.line + lineOffset,
+ column: start.column + columnOffset,
+ };
+}
+
+function endPos(lineOffset, columnOffset) {
+ const { end } = getTestLoc();
+ return {
+ line: end.line + lineOffset,
+ column: end.column + columnOffset,
+ };
+}
+
+function startLine(lineOffset = 0) {
+ const { start } = getTestLoc();
+ return {
+ line: start.line + lineOffset,
+ column: undefinedColumn(),
+ };
+}
+
+function endLine(lineOffset = 0) {
+ const { end } = getTestLoc();
+ return {
+ line: end.line + lineOffset,
+ column: undefinedColumn(),
+ };
+}
+
+function testContains(pos, bool) {
+ const loc = getTestLoc();
+ expect(containsPosition(loc, pos)).toEqual(bool);
+}
+
+describe("containsPosition", () => {
+ describe("location and postion both with the column criteria", () => {
+ /* eslint-disable jest/expect-expect */
+ it("should contain position within the location range", () =>
+ testContains(startPos(1, 1), true));
+
+ it("should not contain position out of the start line", () =>
+ testContains(startPos(-1, 0), false));
+
+ it("should not contain position out of the start column", () =>
+ testContains(startPos(0, -1), false));
+
+ it(`should contain position on the same start line and
+ within the start column`, () => testContains(startPos(0, 1), true));
+
+ it("should not contain position out of the end line", () =>
+ testContains(endPos(1, 0), false));
+
+ it("should not contain position out of the end column", () =>
+ testContains(endPos(0, 1), false));
+
+ // eslint-disable-next-line max-len
+ it("should contain position on the same end line and within the end column", () =>
+ testContains(endPos(0, -1), true));
+ /* eslint-enable jest/expect-expect */
+ });
+
+ describe("position without the column criterion", () => {
+ /* eslint-disable jest/expect-expect */
+ it("should contain position on the same start line", () =>
+ testContains(startLine(0), true));
+
+ it("should contain position on the same end line", () =>
+ testContains(endLine(0), true));
+ /* eslint-enable jest/expect-expect */
+ });
+
+ describe("location without the column criterion", () => {
+ it("should contain position on the same start line", () => {
+ const loc = getTestLoc();
+ loc.start.column = undefinedColumn();
+ const pos = {
+ line: loc.start.line,
+ column: 1,
+ };
+ expect(containsPosition(loc, pos)).toEqual(true);
+ });
+
+ it("should contain position on the same end line", () => {
+ const loc = getTestLoc();
+ loc.end.column = undefinedColumn();
+ const pos = {
+ line: loc.end.line,
+ column: 1,
+ };
+ expect(containsPosition(loc, pos)).toEqual(true);
+ });
+ });
+
+ describe("location and postion both without the column criterion", () => {
+ it("should contain position on the same start line", () => {
+ const loc = getTestLoc();
+ loc.start.column = undefinedColumn();
+ const pos = startLine();
+ expect(containsPosition(loc, pos)).toEqual(true);
+ });
+
+ it("should contain position on the same end line", () => {
+ const loc = getTestLoc();
+ loc.end.column = undefinedColumn();
+ const pos = endLine();
+ expect(containsPosition(loc, pos)).toEqual(true);
+ });
+ });
+});
+
+describe("containsLocation", () => {
+ describe("locations both with the column criteria", () => {
+ it("should contian location within the range", () => {
+ const locA = getTestLoc();
+ const locB = {
+ start: startPos(1, 1),
+ end: endPos(-1, -1),
+ };
+ expect(containsLocation(locA, locB)).toEqual(true);
+ });
+
+ it("should not contian location out of the start line", () => {
+ const locA = getTestLoc();
+ const locB = getTestLoc();
+ locB.start.line--;
+ expect(containsLocation(locA, locB)).toEqual(false);
+ });
+
+ it("should not contian location out of the start column", () => {
+ const locA = getTestLoc();
+ const locB = getTestLoc();
+ locB.start.column--;
+ expect(containsLocation(locA, locB)).toEqual(false);
+ });
+
+ it("should not contian location out of the end line", () => {
+ const locA = getTestLoc();
+ const locB = getTestLoc();
+ locB.end.line++;
+ expect(containsLocation(locA, locB)).toEqual(false);
+ });
+
+ it("should not contian location out of the end column", () => {
+ const locA = getTestLoc();
+ const locB = getTestLoc();
+ locB.end.column++;
+ expect(containsLocation(locA, locB)).toEqual(false);
+ });
+
+ it(`should contain location on the same start line and
+ within the start column`, () => {
+ const locA = getTestLoc();
+ const locB = {
+ start: startPos(0, 1),
+ end: endPos(-1, -1),
+ };
+ expect(containsLocation(locA, locB)).toEqual(true);
+ });
+
+ it(`should contain location on the same end line and
+ within the end column`, () => {
+ const locA = getTestLoc();
+ const locB = {
+ start: startPos(1, 1),
+ end: endPos(0, -1),
+ };
+ expect(containsLocation(locA, locB)).toEqual(true);
+ });
+ });
+
+ describe("location A without the column criterion", () => {
+ it("should contain location on the same start line", () => {
+ const locA = getTestLoc();
+ locA.start.column = undefinedColumn();
+ const locB = getTestLoc();
+ expect(containsLocation(locA, locB)).toEqual(true);
+ });
+
+ it("should contain location on the same end line", () => {
+ const locA = getTestLoc();
+ locA.end.column = undefinedColumn();
+ const locB = getTestLoc();
+ expect(containsLocation(locA, locB)).toEqual(true);
+ });
+ });
+
+ describe("location B without the column criterion", () => {
+ it("should contain location on the same start line", () => {
+ const locA = getTestLoc();
+ const locB = getTestLoc();
+ locB.start.column = undefinedColumn();
+ expect(containsLocation(locA, locB)).toEqual(true);
+ });
+
+ it("should contain location on the same end line", () => {
+ const locA = getTestLoc();
+ const locB = getTestLoc();
+ locB.end.column = undefinedColumn();
+ expect(containsLocation(locA, locB)).toEqual(true);
+ });
+ });
+
+ describe("locations both without the column criteria", () => {
+ it("should contain location on the same start line", () => {
+ const locA = getTestLoc();
+ const locB = getTestLoc();
+ locA.start.column = undefinedColumn();
+ locB.start.column = undefinedColumn();
+ expect(containsLocation(locA, locB)).toEqual(true);
+ });
+
+ it("should contain location on the same end line", () => {
+ const locA = getTestLoc();
+ const locB = getTestLoc();
+ locA.end.column = undefinedColumn();
+ locB.end.column = undefinedColumn();
+ expect(containsLocation(locA, locB)).toEqual(true);
+ });
+ });
+});
diff --git a/devtools/client/debugger/src/workers/parser/tests/findOutOfScopeLocations.spec.js b/devtools/client/debugger/src/workers/parser/tests/findOutOfScopeLocations.spec.js
new file mode 100644
index 0000000000..a2177c22eb
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/findOutOfScopeLocations.spec.js
@@ -0,0 +1,80 @@
+/* eslint max-nested-callbacks: ["error", 4]*/
+/* 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/>. */
+
+import findOutOfScopeLocations from "../findOutOfScopeLocations";
+
+import { populateSource } from "./helpers";
+
+function formatLines(actual) {
+ return actual
+ .map(
+ ({ start, end }) =>
+ `(${start.line}, ${start.column}) -> (${end.line}, ${end.column})`
+ )
+ .join("\n");
+}
+
+describe("Parser.findOutOfScopeLocations", () => {
+ it("should exclude non-enclosing function blocks", () => {
+ const source = populateSource("outOfScope");
+ const actual = findOutOfScopeLocations({
+ source,
+ line: 5,
+ column: 5,
+ });
+
+ expect(formatLines(actual)).toMatchSnapshot();
+ });
+
+ it("should roll up function blocks", () => {
+ const source = populateSource("outOfScope");
+ const actual = findOutOfScopeLocations({
+ source,
+ line: 24,
+ column: 0,
+ });
+
+ expect(formatLines(actual)).toMatchSnapshot();
+ });
+
+ it("should exclude function for locations on declaration", () => {
+ const source = populateSource("outOfScope");
+ const actual = findOutOfScopeLocations({
+ source,
+ line: 3,
+ column: 12,
+ });
+
+ expect(formatLines(actual)).toMatchSnapshot();
+ });
+
+ it("should treat comments as out of scope", () => {
+ const source = populateSource("outOfScopeComment");
+ const actual = findOutOfScopeLocations({
+ source,
+ line: 3,
+ column: 2,
+ });
+
+ expect(actual.length).toBe(1);
+
+ const location = actual[0];
+ expect(location.start.line).toBe(1);
+ expect(location.start.column).toBe(0);
+
+ expect(location.end.line).toBe(1);
+ expect(location.end.column).toBe(15);
+ });
+
+ it("should not exclude in-scope inner locations", () => {
+ const source = populateSource("outOfScope");
+ const actual = findOutOfScopeLocations({
+ source,
+ line: 61,
+ column: 0,
+ });
+ expect(formatLines(actual)).toMatchSnapshot();
+ });
+});
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/allSymbols.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/allSymbols.js
new file mode 100644
index 0000000000..bebda9f36a
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/allSymbols.js
@@ -0,0 +1,33 @@
+const TIME = 60;
+let count = 0;
+
+function incrementCounter(counter) {
+ return counter++;
+}
+
+const sum = (a, b) => a + b;
+
+const Obj = {
+ foo: 1,
+ doThing() {
+ console.log("hey");
+ },
+ doOtherThing: function() {
+ return 42;
+ }
+};
+
+Obj.property = () => {};
+Obj.otherProperty = 1;
+
+class Ultra {
+ constructor() {
+ this.awesome = true;
+ }
+
+ beAwesome(person) {
+ console.log(`${person} is Awesome!`);
+ }
+}
+
+this.props.history.push(`/dacs/${this.props.dac.id}`);
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/async.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/async.js
new file mode 100644
index 0000000000..43216be635
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/async.js
@@ -0,0 +1,10 @@
+async function foo() {
+ return new Promise(resolve => {
+ setTimeout(resolve, 10);
+ });
+}
+
+async function stuff() {
+ await foo(1);
+ await foo(2);
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/call-sites.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/call-sites.js
new file mode 100644
index 0000000000..aa73700d93
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/call-sites.js
@@ -0,0 +1,4 @@
+aaa(bbb(), ccc());
+dddd()
+ .eee()
+ .ffff();
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/callExpressions.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/callExpressions.js
new file mode 100644
index 0000000000..2771dede6a
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/callExpressions.js
@@ -0,0 +1,7 @@
+dispatch({ d });
+function evaluate(script, { frameId } = {frameId: 3}, {c} = {c: 2}) {}
+
+a(b(c()));
+
+a.b().c();
+a.b.c.d();
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/calls.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/calls.js
new file mode 100644
index 0000000000..f05d445db7
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/calls.js
@@ -0,0 +1,21 @@
+foo(1, '2', bar())
+
+foo()
+ .bar()
+ .bazz()
+
+console.log('yo')
+
+foo(
+ 1,
+ bar()
+)
+
+var a = 3;
+
+// set a step point at the first call expression in step expressions
+var x = { a: a(), b: b(), c: c() };
+var b = [ foo() ];
+[ a(), b(), c() ];
+(1, a(), b());
+x(1, a(), b());
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/class.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/class.js
new file mode 100644
index 0000000000..59d612ebfe
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/class.js
@@ -0,0 +1,28 @@
+class Test {
+ publicProperty;
+ #privateProperty = "default";
+ static myStatic = "static";
+ static hello() {
+ return "Hello " + this.myStatic
+ }
+ static {
+ const x = this.myStatic;
+ }
+
+ constructor() {
+ this.publicProperty = "foo";
+ this.#privateProperty = "bar";
+ }
+
+ bar(a) {
+ console.log("bar", a);
+ }
+
+ baz = b => {
+ return b * 2;
+ };
+}
+
+class Test2 {}
+
+let expressiveClass = class {};
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/component.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/component.js
new file mode 100644
index 0000000000..38d9b00096
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/component.js
@@ -0,0 +1,84 @@
+/*
+ * class
+ */
+
+class Punny extends Component {
+ constructor(props) {
+ super();
+ this.onClick = this.onClick.bind(this);
+ }
+
+ componentDidMount() {}
+
+ onClick() {}
+
+ renderMe() {
+ return <div onClick={this.onClick} />;
+ }
+
+ render() {}
+}
+
+/*
+ * CALL EXPRESSIONS - createClass, extend
+ */
+
+const TodoView = Backbone.View.extend({
+ tagName: "li",
+
+ render: function() {
+ console.log("yo");
+ }
+});
+
+const TodoClass = createClass({
+ tagName: "li",
+
+ render: function() {
+ console.log("yo");
+ }
+});
+
+TodoClass = createClass({
+ tagName: "li",
+
+ render: function() {
+ console.log("yo");
+ }
+});
+
+app.TodoClass = createClass({
+ tagName: "li",
+
+ render: function() {
+ console.log("yo");
+ }
+});
+
+/*
+ * PROTOTYPE
+ */
+
+function Button() {
+ if (!(this instanceof Button)) return new Button();
+ this.color = null;
+ Nanocomponent.call(this);
+}
+
+Button.prototype = Object.create(Nanocomponent.prototype);
+
+var x = function() {};
+
+Button.prototype.createElement = function(color) {
+ this.color = color;
+ return html`
+ <button style="background-color: ${color}">
+ Click Me
+ </button>
+ `;
+};
+
+// Implement conditional rendering
+Button.prototype.update = function(newColor) {
+ return newColor !== this.color;
+};
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/computed-props.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/computed-props.js
new file mode 100644
index 0000000000..4c0f182f33
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/computed-props.js
@@ -0,0 +1,8 @@
+(function(key) {
+ let obj = {
+ b: 5
+ };
+ obj[key] = 0;
+ const c = obj.b;
+ return obj;
+})("a");
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/control-flow.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/control-flow.js
new file mode 100644
index 0000000000..b9e859ff74
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/control-flow.js
@@ -0,0 +1,39 @@
+
+if (x) {
+ foo();
+}
+else if (y) {
+ foo();
+}
+else {
+ foo();
+}
+
+for (var i=0; i< 5; i++ ) {
+ foo();
+}
+
+while (x) {
+ foo();
+}
+
+switch (c) {
+ case a:
+ console.log('hi')
+}
+
+var a = 3;
+
+for (const val of [1, 2]) {
+ console.log("pause again", val);
+}
+
+for (const val of vals) {
+ console.log("pause again", val);
+}
+
+try {
+} catch (e) {
+}
+
+with (e) {}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/decorators.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/decorators.js
new file mode 100644
index 0000000000..22c0a1398d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/decorators.js
@@ -0,0 +1,2 @@
+@annotation
+class MyClass { }
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/destructuring.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/destructuring.js
new file mode 100644
index 0000000000..52686e6573
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/destructuring.js
@@ -0,0 +1,16 @@
+const { b, resty } = compute(stuff);
+const { first: f, last: l } = obj;
+
+const [a, ...rest] = compute(stuff);
+const [x] = ["a"];
+
+for (const [index, element] of arr.entries()) {
+ console.log(index, element);
+}
+
+const { a: aa = 10, b: bb = 5 } = { a: 3 };
+const { temp: [{ foo: foooo }] } = obj;
+
+let { [key]: foo } = { z: "bar" };
+
+let [, prefName] = prefsBlueprint[accessorName];
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/es6.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/es6.js
new file mode 100644
index 0000000000..90b53141f4
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/es6.js
@@ -0,0 +1 @@
+dispatch({ ...action, [PROMISE]: promise });
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/expression.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/expression.js
new file mode 100644
index 0000000000..fa80b68add
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/expression.js
@@ -0,0 +1,25 @@
+const obj = { a: { b: 2 } }; // e.g. obj.a.b
+const foo = obj2.c.secondProperty; // e.g. foo.obj2.c.secondProperty
+
+// computed properties
+const com = { [a]: { b: "c", [d]: "e" }, [b]: 3 }; // e.g. com[a].b
+const firstAuthor = collection.books[1].author;
+const firstActionDirector = collection.genres["sci-fi"].movies[0].director;
+
+app.TodoView = Backbone.extend({
+ render: function() {}
+});
+
+// assignments
+obj.foo = { a: { b: "c" }, b: 3 }; // e.g. obj.foo.a.b
+com = { a: { b: "c" }, b: 3 }; // e.g. com.a.b
+
+// arrays
+const res = [{ a: 2 }, { b: 3 }]; // e.g. res[1].b
+const res2 = { a: [{ b: 2 }] }; // e.g. res.a[0].b
+const res3 = { a: [{ b: 2 }], b: [{ c: 3 }] }; // e.g. res.a[0].b
+const res4 = [[{ a: 3 }], [{ b: a.b.c.v.d }]]; // e.g. res[1][0].b
+
+function params({ a, b }) {} // e.g. a
+var pars = function({ a, b }) {};
+const evil = obj2.doEvil().c.secondProperty; // e.g. obj2.doEvil or ""
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/flow.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/flow.js
new file mode 100644
index 0000000000..1135bd62a4
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/flow.js
@@ -0,0 +1,5 @@
+class App extends Component {
+ renderHello(name: string, action: ReduxAction, { todos }: Props) {
+ return `howdy ${name}`;
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/angular1FalsePositive.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/angular1FalsePositive.js
new file mode 100644
index 0000000000..5220f26c8c
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/angular1FalsePositive.js
@@ -0,0 +1,11 @@
+const frameworkStars = {
+ angular: 40779,
+ react: 111576,
+ vue: 114358,
+};
+
+const container = new Container();
+container.module("sum", (...args) => args.reduce((s, c) => s + c, 0));
+
+container.get("sum",
+ (sum) => sum(Object.values(frameworkStars)));
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/angular1Module.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/angular1Module.js
new file mode 100644
index 0000000000..f0e8c381ef
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/angular1Module.js
@@ -0,0 +1,4 @@
+angular.module('something', ['ngRoute', 'ngResource'])
+ .config(function ($routeProvider) {
+ 'use strict';
+ });
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/plainJavascript.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/plainJavascript.js
new file mode 100644
index 0000000000..41609f8715
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/plainJavascript.js
@@ -0,0 +1,8 @@
+"use strict"
+
+const a = 2;
+
+function test(a) {
+ return a;
+}
+
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactComponent.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactComponent.js
new file mode 100644
index 0000000000..37f3ac49e5
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactComponent.js
@@ -0,0 +1,3 @@
+import React, { Component } from "react";
+
+class PrimaryPanes extends Component {}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactComponentEs5.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactComponentEs5.js
new file mode 100644
index 0000000000..a4370b5369
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactComponentEs5.js
@@ -0,0 +1,3 @@
+var React = require("react");
+
+class PrimaryPanes extends React.Component {}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactLibrary.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactLibrary.js
new file mode 100644
index 0000000000..9ca048e77f
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reactLibrary.js
@@ -0,0 +1,19 @@
+/**
+ * Base class helpers for the updating state of a component.
+ */
+function Component(props, context, updater) {
+ this.props = props;
+ this.context = context;
+ // If a component has string refs, we will assign a different object later.
+ this.refs = emptyObject;
+ // We initialize the default updater but the real one gets injected by the
+ // renderer.
+ this.updater = updater || ReactNoopUpdateQueue;
+}
+
+Component.prototype.isReactComponent = {};
+Component.prototype.setState = function (partialState, callback) {
+ !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null)
+ ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : void 0;
+ this.updater.enqueueSetState(this, partialState, callback, 'setState');
+};
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reduxLibrary.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reduxLibrary.js
new file mode 100644
index 0000000000..b86c8fb0cf
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/reduxLibrary.js
@@ -0,0 +1,39 @@
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
+ (factory((global.Redux = {})));
+ }(this, (function (exports) { 'use strict';
+
+ function symbolObservablePonyfill(root) {
+ var result;
+ var Symbol = root.Symbol;
+
+ if (typeof Symbol === 'function') {
+ if (Symbol.observable) {
+ result = Symbol.observable;
+ } else {
+ result = Symbol('observable');
+ Symbol.observable = result;
+ }
+ } else {
+ result = '@@observable';
+ }
+
+ return result;
+ }
+
+ /* global window */
+
+ var root;
+
+ if (typeof self !== 'undefined') {
+ root = self;
+ } else if (typeof window !== 'undefined') {
+ root = window;
+ } else if (typeof global !== 'undefined') {
+ root = global;
+ } else if (typeof module !== 'undefined') {
+ root = module;
+ } else {
+ root = Function('return this')();
+ } \ No newline at end of file
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/vueFileComponent.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/vueFileComponent.js
new file mode 100644
index 0000000000..d41e55b72b
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/vueFileComponent.js
@@ -0,0 +1,3 @@
+Vue.component('test-item', {
+ template: '<li>This is a test item</li>'
+}) \ No newline at end of file
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/vueFileDeclarative.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/vueFileDeclarative.js
new file mode 100644
index 0000000000..844fce1451
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/frameworks/vueFileDeclarative.js
@@ -0,0 +1,6 @@
+var app = new Vue({
+ el: '#app',
+ data: {
+ message: 'Hello Vue!'
+ }
+}) \ No newline at end of file
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/func.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/func.js
new file mode 100644
index 0000000000..bb0d4c1b05
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/func.js
@@ -0,0 +1,50 @@
+function square(n) {
+ return n * n;
+}
+
+export function exFoo() {
+ return "yay";
+}
+
+async function slowFoo() {
+ return "meh";
+}
+
+export async function exSlowFoo() {
+ return "yay in a bit";
+}
+
+function ret() {
+ return foo();
+}
+
+child = function() {};
+
+(function() {
+ 2;
+})();
+
+const obj = {
+ foo: function name() {
+ 2 + 2;
+ },
+
+ bar() {
+ 2 + 2;
+ }
+};
+
+export default function root() {
+}
+
+function test(a1, a2 = 45, { a3, a4, a5: { a6: a7 } = {} } = {}) {
+ console.log("pause next here");
+}
+
+() => (x = 4);
+
+function ret2() {
+ return (
+ foo()
+ );
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/functionNames.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/functionNames.js
new file mode 100644
index 0000000000..2ae38fc548
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/functionNames.js
@@ -0,0 +1,50 @@
+/* eslint-disable */
+
+({
+ foo: function() {},
+ "foo": function() {},
+ 42: function() {},
+
+ foo() {},
+ "foo"() {},
+ 42() {},
+});
+
+foo = function() {};
+obj.foo = function() {};
+
+var foo = function(){};
+var [foo = function(){}] = [];
+var {foo = function(){}} = {};
+
+[foo = function(){}] = [];
+({foo = function(){}} = {});
+({bar: foo = function(){}} = {});
+
+function fn([foo = function(){}]){}
+function f2({foo = function(){}} = {}){}
+function f3({bar: foo = function(){}} = {}){}
+
+class Cls {
+ foo = function() {};
+ "foo" = function() {};
+ 42 = function() {};
+
+ foo() {}
+ "foo"() {}
+ 42() {}
+}
+
+(function(){});
+
+export default function (){}
+
+const defaultObj = {a: 1};
+const defaultArr = ['smthng'];
+function a(first, second){}
+function b(first = 'bla', second){}
+function c(first = {}, second){}
+function d(first = [], second){}
+function e(first = defaultObj, second){}
+function f(first = defaultArr, second){}
+function g(first = null, second){}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/generators.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/generators.js
new file mode 100644
index 0000000000..7c71838827
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/generators.js
@@ -0,0 +1,4 @@
+function* foo() {
+ yield 1;
+ yield 2;
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/jsx.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/jsx.js
new file mode 100644
index 0000000000..c781f7666f
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/jsx.js
@@ -0,0 +1,5 @@
+const jsxElement = <h1> Hi ! I'm here ! </h1>;
+
+<div id="3" res={foo()}>
+ <Item>{foo()}</Item>
+</div>
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/math.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/math.js
new file mode 100644
index 0000000000..508d28ca99
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/math.js
@@ -0,0 +1,15 @@
+function math(n) {
+ function square(n) {
+ // inline comment
+ n * n;
+ }
+
+ // document some lines
+ const two = square(2);
+
+ const four = squaare(4);
+ return two * four;
+}
+
+var child = function() {};
+child2 = function() {};
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/modules.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/modules.js
new file mode 100644
index 0000000000..8ba351497e
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/modules.js
@@ -0,0 +1,10 @@
+import {x} from "y"
+import z from "y";
+
+export class AppComponent {
+ title = 'app'
+}
+
+export default class AppComponent {
+ title = 'app'
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/object-expressions.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/object-expressions.js
new file mode 100644
index 0000000000..b7f4806e04
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/object-expressions.js
@@ -0,0 +1,6 @@
+const y = ({ params });
+const foo = ({ b });
+const bar = { x: 3, y: "434", z: true, a: null, s: c * 2, d : getValue(2) }
+const params = frameId ? { frameActor: frameId } : {}
+
+const collection = {genres: {"sci-fi": {movies: [{director: "yo"}]}}}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/optional-chaining.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/optional-chaining.js
new file mode 100644
index 0000000000..757335f78b
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/optional-chaining.js
@@ -0,0 +1,3 @@
+const obj = {};
+obj?.a;
+obj?.a?.b ?? [];
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/outOfScope.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/outOfScope.js
new file mode 100644
index 0000000000..30218f546b
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/outOfScope.js
@@ -0,0 +1,62 @@
+// Program Scope
+
+function outer() {
+ function inner() {
+ const x = 1;
+ }
+
+ const arrow = () => {
+ const x = 1;
+ };
+
+ const declaration = function() {
+ const x = 1;
+ };
+
+ assignment = (function() {
+ const x = 1;
+ })();
+
+ const iifeDeclaration = (function() {
+ const x = 1;
+ })();
+
+ return function() {
+ const x = 1;
+ };
+}
+
+function exclude() {
+ function another() {
+ const x = 1;
+ }
+}
+
+const globalArrow = () => {
+ const x = 1;
+};
+
+const globalDeclaration = function() {
+ const x = 1;
+};
+
+globalAssignment = (function() {
+ const x = 1;
+})();
+
+const globalIifeDeclaration = (function() {
+ const x = 1;
+})();
+
+function parentFunc() {
+ let MAX = 3;
+ let nums = [0, 1, 2, 3];
+ let x = 1;
+ let y = nums.find(function(n) {
+ return n == x;
+ });
+ function innerFunc(a) {
+ return Math.max(a, MAX);
+ }
+ return innerFunc(y);
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/outOfScopeComment.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/outOfScopeComment.js
new file mode 100644
index 0000000000..bc02f94671
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/outOfScopeComment.js
@@ -0,0 +1,4 @@
+// Some comment
+(function() {
+ const x = 1;
+})();
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/parseScriptTags.html b/devtools/client/debugger/src/workers/parser/tests/fixtures/parseScriptTags.html
new file mode 100644
index 0000000000..6283f0ee98
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/parseScriptTags.html
@@ -0,0 +1,42 @@
+<html>
+<head>
+ <script type="text/javascript">
+ var globalObject = {
+ first: "name",
+ last: "words"
+ };
+ function sayHello (name) {
+ return `Hello, ${name}!`;
+ }
+ </script>
+ <style>
+ BODY {
+ font-size: 48px;
+ color: rebeccapurple;
+ }
+ </style>
+</head>
+<body>
+ <h1>Testing Script Tags in HTML</h1>
+ <script>
+ const capitalize = name => {
+ return name[0].toUpperCase() + name.substring(1)
+ };
+ const greetAll = ["my friend", "buddy", "world"]
+ .map(capitalize)
+ .map(sayHello)
+ .join("\n");
+
+ globalObject.greetings = greetAll;
+ </script>
+ <p>
+ Some arbitrary intermediate content to affect the offsets of the scripts
+ </p>
+ <script>
+ (function iife() {
+ const greeting = sayHello("Ryan");
+ console.log(greeting);
+ })();
+ </script>
+</body>
+</html>
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/private-fields.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/private-fields.js
new file mode 100644
index 0000000000..ca9abc8f1d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/private-fields.js
@@ -0,0 +1,24 @@
+class MyClass {
+ constructor(secret, ...rest) {
+ const self = this;
+ this.#secret = secret;
+ self.#restParams = rest;
+ }
+
+ #secret;
+ #restParams;
+ #salt = "bloup";
+ creationDate = new Date();
+
+ #getSalt() {
+ return this.#salt;
+ }
+
+ debug() {
+ const self = this;
+ const creationDate = this.creationDate;
+ const secret = this.#secret;
+ const salt = self.#getSalt();
+ return `${creationDate}|${salt}|${secret}`;
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/proto.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/proto.js
new file mode 100644
index 0000000000..38c3b63ac7
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/proto.js
@@ -0,0 +1,14 @@
+const foo = function() {};
+
+const bar = () => {};
+
+const TodoView = Backbone.View.extend({
+ tagName: "li",
+ initialize: function() {},
+ doThing(b) {
+ console.log("hi", b);
+ },
+ render: function() {
+ return this;
+ }
+});
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/regexp.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/regexp.js
new file mode 100644
index 0000000000..fb0f13b0d0
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/regexp.js
@@ -0,0 +1 @@
+const re = /^\p{RGI_Emoji}$/v; \ No newline at end of file
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/resolveToken.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/resolveToken.js
new file mode 100644
index 0000000000..4660f0f568
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/resolveToken.js
@@ -0,0 +1,40 @@
+const a = 1;
+let b = 0;
+
+function getA() {
+ return a;
+}
+
+function setB(newB) {
+ b = newB;
+}
+
+const plusAB = (function(x, y) {
+ const obj = { x, y };
+ function insideClosure(alpha, beta) {
+ return alpha + beta + obj.x + obj.y;
+ }
+
+ return insideClosure;
+})(a, b);
+
+function withMultipleScopes() {
+ var outer = 1;
+ function innerScope() {
+ var inner = outer + 1;
+ return inner;
+ }
+
+ const fromIIFE = (function(toIIFE) {
+ return innerScope() + toIIFE;
+ })(1);
+
+ {
+ // random block
+ let x = outer + fromIIFE;
+ if (x) {
+ const y = x * x;
+ console.log(y);
+ }
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/arrow-function.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/arrow-function.js
new file mode 100644
index 0000000000..4ec72fd450
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/arrow-function.js
@@ -0,0 +1,11 @@
+export {};
+
+let outer = (p1) => {
+ console.log(this);
+
+ (function() {
+ var inner = (p2) => {
+ console.log(this);
+ };
+ })();
+};
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/binding-types.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/binding-types.js
new file mode 100644
index 0000000000..8c9cc05d1d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/binding-types.js
@@ -0,0 +1,24 @@
+import def from "";
+import { named } from "";
+import { thing as otherNamed } from "";
+import * as namespace from "";
+
+function fn() {}
+class cls {
+ method(){
+
+ }
+}
+
+var aVar;
+let aLet;
+const aConst = "";
+
+(function inner() {
+ this;
+ arguments;
+});
+
+{
+ function blockFn(){}
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/block-statement.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/block-statement.js
new file mode 100644
index 0000000000..5e64d1180f
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/block-statement.js
@@ -0,0 +1,13 @@
+export {};
+
+let first;
+
+{
+ var second;
+ function third() {}
+ class Fourth {}
+ let fifth;
+ const sixth = 6;
+}
+
+var seventh;
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-declaration.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-declaration.js
new file mode 100644
index 0000000000..1c2c74dcbc
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-declaration.js
@@ -0,0 +1,14 @@
+export {};
+
+class Outer {
+ method() {
+ class Inner {
+ m() {
+ console.log(this);
+ }
+ }
+ }
+}
+
+@decorator
+class Second {}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-expression.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-expression.js
new file mode 100644
index 0000000000..16b6841d71
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-expression.js
@@ -0,0 +1,11 @@
+export {};
+
+var Outer = class Outer {
+ method() {
+ var Inner = class {
+ m() {
+ console.log(this);
+ }
+ };
+ }
+};
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-property.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-property.js
new file mode 100644
index 0000000000..a80cad3a87
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/class-property.js
@@ -0,0 +1,10 @@
+export {};
+
+class Foo {
+ prop = this.init();
+
+ other = do {
+ var one;
+ let two;
+ };
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/complex-nesting.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/complex-nesting.js
new file mode 100644
index 0000000000..40763f556f
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/complex-nesting.js
@@ -0,0 +1,29 @@
+function named(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = root;
+function root() {
+ function fn(arg) {
+ var _this = this,
+ _arguments = arguments;
+
+ console.log(this, arguments);
+ console.log("pause here", fn, root);
+
+ var arrow = function arrow(argArrow) {
+ console.log(_this, _arguments);
+ console.log("pause here", fn, root);
+ };
+ arrow("arrow-arg");
+ }
+
+ fn.call("this-value", "arg-value");
+}
+module.exports = exports["default"];
+
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/expressions.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/expressions.js
new file mode 100644
index 0000000000..6698acd8e8
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/expressions.js
@@ -0,0 +1,6 @@
+const foo = {};
+
+foo.bar().baz;
+(0, foo.bar)().baz;
+Object(foo.bar)().baz;
+__webpack_require__.i(foo.bar)().baz;
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/flowtype-bindings.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/flowtype-bindings.js
new file mode 100644
index 0000000000..385797c044
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/flowtype-bindings.js
@@ -0,0 +1,11 @@
+import type { One, Two, Three } from "./src/mod";
+
+type Other = {
+ root: typeof root,
+};
+
+const aConst = (window: Array<string>);
+
+export default function root() {
+
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/fn-body-lex-and-nonlex.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/fn-body-lex-and-nonlex.js
new file mode 100644
index 0000000000..a7f6d7670a
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/fn-body-lex-and-nonlex.js
@@ -0,0 +1,23 @@
+function fn() {
+ var nonlex;
+ let lex;
+
+}
+
+function fn2() {
+ function nonlex(){}
+ let lex;
+
+}
+
+function fn3() {
+ var nonlex;
+ class Thing {}
+
+}
+
+function fn4() {
+ function nonlex(){}
+ class Thing {}
+
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/for-loops.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/for-loops.js
new file mode 100644
index 0000000000..747eeeae7d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/for-loops.js
@@ -0,0 +1,13 @@
+export {};
+
+for (var one;;) {}
+for (let two;;) {}
+for (const three = 3;;) {}
+
+for (var four in {}) {}
+for (let five in {}) {}
+for (const six in {}) {}
+
+for (var seven of {}) {}
+for (let eight of {}) {}
+for (const nine of {}) {}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/function-declaration.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/function-declaration.js
new file mode 100644
index 0000000000..759374b437
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/function-declaration.js
@@ -0,0 +1,11 @@
+export {};
+
+function outer(p1) {}
+
+{
+ function middle(p2) {
+ function inner(p3) {}
+
+ console.log(this);
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/function-expression.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/function-expression.js
new file mode 100644
index 0000000000..436413533e
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/function-expression.js
@@ -0,0 +1,7 @@
+export {};
+
+let fn = function(p1) {};
+
+let fn2 = function withName(p2) {
+ console.log(this);
+};
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/jsx-component.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/jsx-component.js
new file mode 100644
index 0000000000..ffe1c1dfce
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/jsx-component.js
@@ -0,0 +1,6 @@
+import SomeComponent from "";
+
+<SomeComponent attr="value" />;
+<SomeComponent attr="value"></SomeComponent>;
+<SomeComponent.prop attr="value" />;
+<SomeComponent.prop.child attr="value" />;
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/out-of-order-declarations.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/out-of-order-declarations.js
new file mode 100644
index 0000000000..4f36d9fc38
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/out-of-order-declarations.js
@@ -0,0 +1,21 @@
+var val;
+
+export default function root() {
+ var val;
+
+ var fn;
+
+ this;
+
+ function callback() {
+ console.log(val, fn, callback, root, this);
+
+ var val;
+
+ function fn(){};
+ }
+
+ callback();
+}
+
+import aDefault from "./src/mod";
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/pattern-declarations.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/pattern-declarations.js
new file mode 100644
index 0000000000..6810ef4614
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/pattern-declarations.js
@@ -0,0 +1,2 @@
+var { prop: one } = {};
+var [ two ] = [];
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/simple-module.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/simple-module.js
new file mode 100644
index 0000000000..b25cc7a863
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/simple-module.js
@@ -0,0 +1,11 @@
+import foo from "foo";
+
+console.log(foo);
+
+var one = 1;
+let two = 2;
+const three = 3;
+
+function fn() {}
+
+this;
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/switch-statement.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/switch-statement.js
new file mode 100644
index 0000000000..7163c3811d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/switch-statement.js
@@ -0,0 +1,22 @@
+export {};
+
+switch (foo) {
+ case "zero":
+ var zero;
+ case "one":
+ let one;
+ case "two":
+ let two;
+ case "three": {
+ let three;
+ }
+}
+
+switch (foo) {
+ case "":
+ function two(){}
+}
+switch (foo) {
+ case "":
+ class three {}
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/try-catch.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/try-catch.js
new file mode 100644
index 0000000000..8ccf4db592
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/try-catch.js
@@ -0,0 +1,9 @@
+export {};
+
+try {
+ var first;
+ let second;
+} catch (err) {
+ var third;
+ let fourth;
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/ts-sample.ts b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/ts-sample.ts
new file mode 100644
index 0000000000..e23ff83754
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/ts-sample.ts
@@ -0,0 +1,41 @@
+
+// TSEnumDeclaration
+enum Color {
+ // TSEnumMember
+ Red,
+ Green,
+ Blue,
+}
+
+class Example<T> {
+ // TSParameterProperty
+ constructor(public foo) {
+
+ }
+
+ method(): never {
+ throw new Error();
+ }
+}
+
+// TSTypeAssertion
+var foo = <any>window;
+
+// TSAsExpression
+(window as any);
+
+// TSNonNullExpression
+(window!);
+
+// TSModuleDeclaration
+namespace TheSpace {
+ function fn() {
+
+ }
+}
+
+// TSImportEqualsDeclaration
+import ImportedClass = require("mod");
+
+// TSExportAssignment
+export = Example;
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/tsx-sample.tsx b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/tsx-sample.tsx
new file mode 100644
index 0000000000..9e2b9faf8b
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/tsx-sample.tsx
@@ -0,0 +1,41 @@
+
+// TSEnumDeclaration
+enum Color {
+ // TSEnumMember
+ Red,
+ Green,
+ Blue,
+}
+
+class Example<T> {
+ // TSParameterProperty
+ constructor(public foo) {
+
+ }
+
+ method(): never {
+ throw new Error();
+ }
+}
+
+// JSXElement
+var foo = <any>window</any>;
+
+// TSAsExpression
+(window as any);
+
+// TSNonNullExpression
+(window!);
+
+// TSModuleDeclaration
+namespace TheSpace {
+ function fn() {
+
+ }
+}
+
+// TSImportEqualsDeclaration
+import ImportedClass = require("mod");
+
+// TSExportAssignment
+export = Example;
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/vue-sample.vue b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/vue-sample.vue
new file mode 100644
index 0000000000..0fceee99d1
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/scopes/vue-sample.vue
@@ -0,0 +1,26 @@
+<template>
+ <div class="hello">
+ <h1>{{ msg }}</h1>
+ </div>
+</template>
+
+<script>
+var moduleVar = "data";
+
+export default {
+ name: 'HelloWorld',
+ data () {
+ var fnVar = 4;
+
+ return {
+ msg: 'Welcome to Your Vue.js App'
+ };
+ }
+};
+</script>
+
+<style scoped>
+a {
+ color: red;
+}
+</style>
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/statements.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/statements.js
new file mode 100644
index 0000000000..f2c113570e
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/statements.js
@@ -0,0 +1,40 @@
+debugger; debugger;
+console.log("a"); console.log("a");
+
+// assignments with valid pause locations
+this.x = 3;
+var a = 4;
+var d = [foo()]
+var f = 3, e = 4;
+var g = [], h = {};
+
+// assignments with invalid pause locations
+var b = foo();
+c = foo();
+
+
+const arr = [
+ '1',
+ 2,
+ foo()
+]
+
+const obj = {
+ a: '1',
+ b: 2,
+ c: foo(),
+}
+
+foo(
+ 1,
+ foo(
+ 1
+ ),
+ 3
+)
+
+throw new Error("3");
+3;
+
+while (i < 6) { break }
+while (i < 6) { continue;}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/thisExpression.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/thisExpression.js
new file mode 100644
index 0000000000..dd398db426
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/thisExpression.js
@@ -0,0 +1,11 @@
+class Test {
+ constructor() {
+ this.foo = {
+ a: "foobar"
+ };
+ }
+
+ bar() {
+ console.log(this.foo.a);
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/fixtures/var.js b/devtools/client/debugger/src/workers/parser/tests/fixtures/var.js
new file mode 100644
index 0000000000..509ad368e8
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/fixtures/var.js
@@ -0,0 +1,21 @@
+var foo = 1;
+let bar = 2;
+const baz = 3;
+const a = 4,
+ b = 5;
+a = 5;
+
+var { foo: { baw } } = {}
+var {bap} = {}
+var {ll = 3} = {}
+
+
+var [first] = [1]
+
+var { a: _a } = 3
+
+var [oh, {my: god}] = [{},{}]
+
+var [[oj], [{oy, vey: _vey, mitzvot: _mitz = 4}]] = [{},{}]
+
+var [one, ...stuff] = []
diff --git a/devtools/client/debugger/src/workers/parser/tests/framework.spec.js b/devtools/client/debugger/src/workers/parser/tests/framework.spec.js
new file mode 100644
index 0000000000..d41f45b71c
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/framework.spec.js
@@ -0,0 +1,63 @@
+/* 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/>. */
+
+import { getSymbols } from "../getSymbols";
+import { populateOriginalSource } from "./helpers";
+import cases from "jest-in-case";
+
+cases(
+ "Parser.getFramework",
+ ({ name, file, value }) => {
+ const source = populateOriginalSource("frameworks/plainJavascript");
+ const symbols = getSymbols(source.id);
+ expect(symbols.framework).toBeNull();
+ },
+ [
+ {
+ name: "is undefined when no framework",
+ file: "frameworks/plainJavascript",
+ value: null,
+ },
+ {
+ name: "does not get confused with angular (#6833)",
+ file: "frameworks/angular1FalsePositive",
+ value: null,
+ },
+ {
+ name: "recognizes ES6 React component",
+ file: "frameworks/reactComponent",
+ value: "React",
+ },
+ {
+ name: "recognizes ES5 React component",
+ file: "frameworks/reactComponentEs5",
+ value: "React",
+ },
+ {
+ name: "recognizes Angular 1 module",
+ file: "frameworks/angular1Module",
+ value: "Angular",
+ },
+ {
+ name: "recognizes declarative Vue file",
+ file: "frameworks/vueFileDeclarative",
+ value: "Vue",
+ },
+ {
+ name: "recognizes component Vue file",
+ file: "frameworks/vueFileComponent",
+ value: "Vue",
+ },
+ {
+ name: "recognizes the react library file",
+ file: "framework/reactLibrary",
+ value: "React",
+ },
+ {
+ name: "recognizes the redux library file",
+ file: "framework/reduxLibrary",
+ value: "React",
+ },
+ ]
+);
diff --git a/devtools/client/debugger/src/workers/parser/tests/getScopes.spec.js b/devtools/client/debugger/src/workers/parser/tests/getScopes.spec.js
new file mode 100644
index 0000000000..a2d394ae96
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/getScopes.spec.js
@@ -0,0 +1,227 @@
+/* eslint max-nested-callbacks: ["error", 4]*/
+/* 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/>. */
+
+import getScopes from "../getScopes";
+import { populateOriginalSource } from "./helpers";
+import cases from "jest-in-case";
+
+cases(
+ "Parser.getScopes",
+ ({ name, file, type, locations }) => {
+ const source = populateOriginalSource(file, type);
+
+ locations.forEach(([line, column]) => {
+ const scopes = getScopes({
+ source,
+ line,
+ column,
+ });
+
+ expect(scopes).toMatchSnapshot(
+ `getScopes ${name} at line ${line} column ${column}`
+ );
+ });
+ },
+ [
+ {
+ name: "finds scope bindings in fn body with both lex and non-lex items",
+ file: "scopes/fn-body-lex-and-nonlex",
+ locations: [
+ [4, 0],
+ [10, 0],
+ [16, 0],
+ [22, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings in a vue file",
+ file: "scopes/vue-sample",
+ type: "vue",
+ locations: [[14, 0]],
+ },
+ {
+ name: "finds scope bindings in a typescript file",
+ file: "scopes/ts-sample",
+ type: "ts",
+ locations: [
+ [9, 0],
+ [13, 4],
+ [17, 0],
+ [33, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings in a typescript-jsx file",
+ file: "scopes/tsx-sample",
+ type: "tsx",
+ locations: [
+ [9, 0],
+ [13, 4],
+ [17, 0],
+ [33, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings in a module",
+ file: "scopes/simple-module",
+ locations: [[7, 0]],
+ },
+ {
+ name: "finds scope bindings in a JSX element",
+ file: "scopes/jsx-component",
+ locations: [[2, 0]],
+ },
+ {
+ name: "finds scope bindings for complex binding nesting",
+ file: "scopes/complex-nesting",
+ locations: [
+ [16, 4],
+ [20, 6],
+ ],
+ },
+ {
+ name: "finds scope bindings for function declarations",
+ file: "scopes/function-declaration",
+ locations: [
+ [2, 0],
+ [3, 20],
+ [5, 1],
+ [9, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings for function expressions",
+ file: "scopes/function-expression",
+ locations: [
+ [2, 0],
+ [3, 23],
+ [6, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings for arrow functions",
+ file: "scopes/arrow-function",
+ locations: [
+ [2, 0],
+ [4, 0],
+ [7, 0],
+ [8, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings for class declarations",
+ file: "scopes/class-declaration",
+ locations: [
+ [2, 0],
+ [5, 0],
+ [7, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings for class expressions",
+ file: "scopes/class-expression",
+ locations: [
+ [2, 0],
+ [5, 0],
+ [7, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings for for loops",
+ file: "scopes/for-loops",
+ locations: [
+ [2, 0],
+ [3, 17],
+ [4, 17],
+ [5, 25],
+ [7, 22],
+ [8, 22],
+ [9, 23],
+ [11, 23],
+ [12, 23],
+ [13, 24],
+ ],
+ },
+ {
+ name: "finds scope bindings for try..catch",
+ file: "scopes/try-catch",
+ locations: [
+ [2, 0],
+ [4, 0],
+ [7, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings for out of order declarations",
+ file: "scopes/out-of-order-declarations",
+ locations: [
+ [2, 0],
+ [5, 0],
+ [11, 0],
+ [14, 0],
+ [17, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings for block statements",
+ file: "scopes/block-statement",
+ locations: [
+ [2, 0],
+ [6, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings for class properties",
+ file: "scopes/class-property",
+ locations: [
+ [2, 0],
+ [4, 16],
+ [6, 12],
+ [7, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings and exclude Flowtype",
+ file: "scopes/flowtype-bindings",
+ locations: [
+ [8, 0],
+ [10, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings for declarations with patterns",
+ file: "scopes/pattern-declarations",
+ locations: [[1, 0]],
+ },
+ {
+ name: "finds scope bindings for switch statements",
+ file: "scopes/switch-statement",
+ locations: [
+ [2, 0],
+ [5, 0],
+ [7, 0],
+ [9, 0],
+ [11, 0],
+ [17, 0],
+ [21, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings with proper types",
+ file: "scopes/binding-types",
+ locations: [
+ [5, 0],
+ [9, 0],
+ [18, 0],
+ [23, 0],
+ ],
+ },
+ {
+ name: "finds scope bindings with expression metadata",
+ file: "scopes/expressions",
+ locations: [[2, 0]],
+ },
+ ]
+);
diff --git a/devtools/client/debugger/src/workers/parser/tests/getSymbols.spec.js b/devtools/client/debugger/src/workers/parser/tests/getSymbols.spec.js
new file mode 100644
index 0000000000..723eef1fd9
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/getSymbols.spec.js
@@ -0,0 +1,51 @@
+/* eslint max-nested-callbacks: ["error", 4]*/
+/* 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/>. */
+
+import { formatSymbols } from "../utils/formatSymbols";
+import { populateSource, populateOriginalSource } from "./helpers";
+import cases from "jest-in-case";
+
+cases(
+ "Parser.getSymbols",
+ ({ name, file, original, type }) => {
+ const source = original
+ ? populateOriginalSource(file, type)
+ : populateSource(file, type);
+
+ expect(formatSymbols(source.id)).toMatchSnapshot();
+ },
+ [
+ { name: "es6", file: "es6", original: true },
+ { name: "func", file: "func", original: true },
+ { name: "function names", file: "functionNames", original: true },
+ { name: "math", file: "math" },
+ { name: "proto", file: "proto" },
+ { name: "class", file: "class", original: true },
+ { name: "var", file: "var" },
+ { name: "expression", file: "expression" },
+ { name: "allSymbols", file: "allSymbols" },
+ { name: "call sites", file: "call-sites" },
+ { name: "call expression", file: "callExpressions" },
+ { name: "object expressions", file: "object-expressions" },
+ { name: "optional chaining", file: "optional-chaining" },
+ { name: "private fields", file: "private-fields" },
+ {
+ name: "finds symbols in an html file",
+ file: "parseScriptTags",
+ type: "html",
+ },
+ { name: "component", file: "component", original: true },
+ {
+ name: "react component",
+ file: "frameworks/reactComponent",
+ original: true,
+ },
+ { name: "flow", file: "flow", original: true },
+ { name: "jsx", file: "jsx", original: true },
+ { name: "destruct", file: "destructuring" },
+
+ { name: "regexp", file: "regexp" },
+ ]
+);
diff --git a/devtools/client/debugger/src/workers/parser/tests/helpers/index.js b/devtools/client/debugger/src/workers/parser/tests/helpers/index.js
new file mode 100644
index 0000000000..47c358ae66
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/helpers/index.js
@@ -0,0 +1,86 @@
+/* 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/>. */
+
+import fs from "fs";
+import path from "path";
+
+import { makeMockSourceAndContent } from "../../../../utils/test-mockup";
+import { setSource } from "../../sources";
+import * as asyncValue from "../../../../utils/async-value";
+
+export function getFixture(name, type = "js") {
+ return fs.readFileSync(
+ path.join(__dirname, `../fixtures/${name}.${type}`),
+ "utf8"
+ );
+}
+
+function getSourceContent(name, type = "js") {
+ const text = getFixture(name, type);
+ let contentType = "text/javascript";
+ if (type === "html") {
+ contentType = "text/html";
+ } else if (type === "vue") {
+ contentType = "text/vue";
+ } else if (type === "ts") {
+ contentType = "text/typescript";
+ } else if (type === "tsx") {
+ contentType = "text/typescript-jsx";
+ }
+
+ return {
+ type: "text",
+ value: text,
+ contentType,
+ };
+}
+
+export function getSource(name, type) {
+ const { value: text, contentType } = getSourceContent(name, type);
+
+ return makeMockSourceAndContent(undefined, name, contentType, text);
+}
+
+export function populateSource(name, type) {
+ const { content, ...source } = getSource(name, type);
+ setSource({
+ id: source.id,
+ text: content.value,
+ contentType: content.contentType,
+ isWasm: false,
+ });
+ return {
+ ...source,
+ content: asyncValue.fulfilled(content),
+ };
+}
+
+export function getOriginalSource(name, type) {
+ return getOriginalSourceWithContent(name, type);
+}
+
+export function getOriginalSourceWithContent(name, type) {
+ const { value: text, contentType } = getSourceContent(name, type);
+
+ return makeMockSourceAndContent(
+ undefined,
+ `${name}/originalSource-1`,
+ contentType,
+ text
+ );
+}
+
+export function populateOriginalSource(name, type) {
+ const { content, ...source } = getOriginalSourceWithContent(name, type);
+ setSource({
+ id: source.id,
+ text: content.value,
+ contentType: content.contentType,
+ isWasm: false,
+ });
+ return {
+ ...source,
+ content: asyncValue.fulfilled(content),
+ };
+}
diff --git a/devtools/client/debugger/src/workers/parser/tests/mapBindings.spec.js b/devtools/client/debugger/src/workers/parser/tests/mapBindings.spec.js
new file mode 100644
index 0000000000..8c23ab5873
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/mapBindings.spec.js
@@ -0,0 +1,161 @@
+/* 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/>. */
+
+import mapExpressionBindings from "../mapBindings";
+import { parseConsoleScript } from "../utils/ast";
+import cases from "jest-in-case";
+
+const prettier = require("prettier");
+
+function format(code) {
+ return prettier.format(code, { semi: false, parser: "babel" });
+}
+
+function excludedTest({ name, expression, bindings = [] }) {
+ const safeExpression = mapExpressionBindings(
+ expression,
+ parseConsoleScript(expression),
+ bindings
+ );
+ expect(format(safeExpression)).toEqual(format(expression));
+}
+
+function includedTest({ name, expression, newExpression, bindings }) {
+ const safeExpression = mapExpressionBindings(
+ expression,
+ parseConsoleScript(expression),
+ bindings
+ );
+ expect(format(safeExpression)).toEqual(format(newExpression));
+}
+
+describe("mapExpressionBindings", () => {
+ cases("included cases", includedTest, [
+ {
+ name: "single declaration",
+ expression: "const a = 2; let b = 3; var c = 4;",
+ newExpression: "self.a = 2; self.b = 3; self.c = 4;",
+ },
+ {
+ name: "multiple declarations",
+ expression: "const a = 2, b = 3",
+ newExpression: "self.a = 2; self.b = 3",
+ },
+ {
+ name: "declaration with separate assignment",
+ expression: "let a; a = 2;",
+ newExpression: "self.a = void 0; self.a = 2;",
+ },
+ {
+ name: "multiple declarations with no assignment",
+ expression: "let a = 2, b;",
+ newExpression: "self.a = 2; self.b = void 0;",
+ },
+ {
+ name: "local bindings become assignments",
+ bindings: ["a"],
+ expression: "var a = 2;",
+ newExpression: "a = 2;",
+ },
+ {
+ name: "assignments",
+ expression: "a = 2;",
+ newExpression: "self.a = 2;",
+ },
+ {
+ name: "assignments with +=",
+ expression: "a += 2;",
+ newExpression: "self.a += 2;",
+ },
+ {
+ name: "destructuring (objects)",
+ expression: "const { a } = {}; ",
+ newExpression: "({ a: self.a } = {})",
+ },
+ {
+ name: "destructuring (arrays)",
+ expression: " var [a, ...foo] = [];",
+ newExpression: "([self.a, ...self.foo] = [])",
+ },
+ {
+ name: "destructuring (declarations)",
+ expression: "var {d,e} = {}, {f} = {}; ",
+ newExpression: `({ d: self.d, e: self.e } = {});
+ ({ f: self.f } = {})
+ `,
+ },
+ {
+ name: "destructuring & declaration",
+ expression: "const { a } = {}; var b = 3",
+ newExpression: `({ a: self.a } = {});
+ self.b = 3
+ `,
+ },
+ {
+ name: "destructuring assignment",
+ expression: "[a] = [3]",
+ newExpression: "[self.a] = [3]",
+ },
+ {
+ name: "destructuring assignment (declarations)",
+ expression: "[a] = [3]; var b = 4",
+ newExpression: "[self.a] = [3];\n self.b = 4",
+ },
+ ]);
+
+ cases("excluded cases", excludedTest, [
+ { name: "local variables", expression: "function a() { var b = 2}" },
+ { name: "functions", expression: "function a() {}" },
+ { name: "classes", expression: "class a {}" },
+
+ { name: "with", expression: "with (obj) {var a = 2;}" },
+ {
+ name: "with & declaration",
+ expression: "with (obj) {var a = 2;}; ; var b = 3",
+ },
+ {
+ name: "hoisting",
+ expression: "{ const h = 3; }",
+ },
+ {
+ name: "assignments",
+ bindings: ["a"],
+ expression: "a = 2;",
+ },
+ {
+ name: "identifier",
+ expression: "a",
+ },
+ ]);
+
+ cases("cases that we should map in the future", excludedTest, [
+ { name: "blocks (IF)", expression: "if (true) { var a = 3; }" },
+ {
+ name: "hoisting",
+ expression: "{ var g = 5; }",
+ },
+ {
+ name: "for loops bindings",
+ expression: "for (let foo = 4; false;){}",
+ },
+ ]);
+
+ cases("cases that we shouldn't map in the future", includedTest, [
+ {
+ name: "window properties",
+ expression: "var innerHeight = 3; var location = 5;",
+ newExpression: "self.innerHeight = 3; self.location = 5;",
+ },
+ {
+ name: "self declaration",
+ expression: "var self = 3",
+ newExpression: "self.self = 3",
+ },
+ {
+ name: "self assignment",
+ expression: "self = 3",
+ newExpression: "self.self = 3",
+ },
+ ]);
+});
diff --git a/devtools/client/debugger/src/workers/parser/tests/mapExpression.spec.js b/devtools/client/debugger/src/workers/parser/tests/mapExpression.spec.js
new file mode 100644
index 0000000000..6c89231012
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/mapExpression.spec.js
@@ -0,0 +1,796 @@
+/* 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/>. */
+
+import mapExpression from "../mapExpression";
+import { format } from "prettier";
+import cases from "jest-in-case";
+
+function test({
+ expression,
+ newExpression,
+ bindings,
+ mappings,
+ shouldMapBindings,
+ expectedMapped,
+ parseExpression = true,
+}) {
+ const res = mapExpression(expression, mappings, bindings, shouldMapBindings);
+
+ if (parseExpression) {
+ expect(
+ format(res.expression, {
+ parser: "babel",
+ })
+ ).toEqual(format(newExpression, { parser: "babel" }));
+ } else {
+ expect(res.expression).toEqual(newExpression);
+ }
+
+ expect(res.mapped).toEqual(expectedMapped);
+}
+
+function formatAwait(body) {
+ return `(async () => { ${body} })();`;
+}
+
+describe("mapExpression", () => {
+ cases("mapExpressions", test, [
+ {
+ name: "await",
+ expression: "await a()",
+ newExpression: formatAwait("return a()"),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (multiple statements)",
+ expression: "const x = await a(); x + x",
+ newExpression: formatAwait("self.x = await a(); return x + x;"),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (inner)",
+ expression: "async () => await a();",
+ newExpression: "async () => await a();",
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (multiple awaits)",
+ expression: "const x = await a(); await b(x)",
+ newExpression: formatAwait("self.x = await a(); return b(x);"),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (assignment)",
+ expression: "let x = await sleep(100, 2)",
+ newExpression: formatAwait("return (self.x = await sleep(100, 2))"),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (destructuring)",
+ expression: "const { a, c: y } = await b()",
+ newExpression: formatAwait(
+ "return ({ a: self.a, c: self.y } = await b())"
+ ),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (array destructuring)",
+ expression: "const [a, y] = await b();",
+ newExpression: formatAwait("return ([self.a, self.y] = await b())"),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (mixed destructuring)",
+ expression: "const [{ a }] = await b();",
+ newExpression: formatAwait("return ([{ a: self.a }] = await b())"),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (destructuring, multiple statements)",
+ expression: "const { a, c: y } = await b(), { x } = await y()",
+ newExpression: formatAwait(`
+ ({ a: self.a, c: self.y } = await b())
+ return ({ x: self.x } = await y());
+ `),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (destructuring, bindings)",
+ expression: "const { a, c: y } = await b();",
+ newExpression: formatAwait("return ({ a, c: y } = await b())"),
+ bindings: ["a", "y"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (array destructuring, bindings)",
+ expression: "const [a, y] = await b();",
+ newExpression: formatAwait("return ([a, y] = await b())"),
+ bindings: ["a", "y"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (mixed destructuring, bindings)",
+ expression: "const [{ a }] = await b();",
+ newExpression: formatAwait("return ([{ a }] = await b())"),
+ bindings: ["a"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (destructuring with defaults, bindings)",
+ expression: "const { c, a = 5 } = await b();",
+ newExpression: formatAwait("return ({ c: self.c, a = 5 } = await b())"),
+ bindings: ["a", "y"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (array destructuring with defaults, bindings)",
+ expression: "const [a, y = 10] = await b();",
+ newExpression: formatAwait("return ([a, y = 10] = await b())"),
+ bindings: ["a", "y"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (mixed destructuring with defaults, bindings)",
+ expression: "const [{ c = 5 }, a = 5] = await b();",
+ newExpression: formatAwait(
+ "return ([ { c: self.c = 5 }, a = 5] = await b())"
+ ),
+ bindings: ["a"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (nested destructuring, bindings)",
+ expression: "const { a, c: { y } } = await b();",
+ newExpression: formatAwait(`
+ return ({
+ a,
+ c: { y }
+ } = await b());
+ `),
+ bindings: ["a", "y"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (nested destructuring with defaults)",
+ expression: "const { a, c: { y = 5 } = {} } = await b();",
+ newExpression: formatAwait(`return ({
+ a: self.a,
+ c: { y: self.y = 5 } = {},
+ } = await b());
+ `),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (very nested destructuring with defaults)",
+ expression:
+ "const { a, c: { y: { z = 10, b } = { b: 5 } } } = await b();",
+ newExpression: formatAwait(`
+ return ({
+ a: self.a,
+ c: {
+ y: { z: self.z = 10, b: self.b } = {
+ b: 5
+ }
+ }
+ } = await b());
+ `),
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (with SyntaxError)",
+ expression: "await new Promise())",
+ newExpression: formatAwait("await new Promise())"),
+ parseExpression: false,
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, let assignment)",
+ expression: "let a = await 123;",
+ newExpression: `let a;
+ (async () => {
+ return a = await 123;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, var assignment)",
+ expression: "var a = await 123;",
+ newExpression: `var a;
+ (async () => {
+ return a = await 123;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, const assignment)",
+ expression: "const a = await 123;",
+ newExpression: `let a;
+ (async () => {
+ return a = await 123;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, multiple assignments)",
+ expression: "let a = 1, b, c = 3; b = await 123; a + b + c",
+ newExpression: `let a, b, c;
+ (async () => {
+ a = 1;
+ c = 3;
+ b = await 123;
+ return a + b + c;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, object destructuring)",
+ expression: "let {a, b, c} = await x;",
+ newExpression: `let a, b, c;
+ (async () => {
+ return ({a, b, c} = await x);
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, object destructuring with rest)",
+ expression: "let {a, ...rest} = await x;",
+ newExpression: `let a, rest;
+ (async () => {
+ return ({a, ...rest} = await x);
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, object destructuring with renaming and default)",
+ expression: "let {a: hello, b, c: world, d: $ = 4} = await x;",
+ newExpression: `let hello, b, world, $;
+ (async () => {
+ return ({a: hello, b, c: world, d: $ = 4} = await x);
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, nested object destructuring + renaming + default)",
+ expression: `let {
+ a: hello, c: { y: { z = 10, b: bill, d: [e, f = 20] }}
+ } = await x; z;`,
+ newExpression: `let hello, z, bill, e, f;
+ (async () => {
+ ({ a: hello, c: { y: { z = 10, b: bill, d: [e, f = 20] }}} = await x);
+ return z;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, array destructuring)",
+ expression: "let [a, b, c] = await x; c;",
+ newExpression: `let a, b, c;
+ (async () => {
+ [a, b, c] = await x;
+ return c;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, array destructuring with default)",
+ expression: "let [a, b = 1, c = 2] = await x; c;",
+ newExpression: `let a, b, c;
+ (async () => {
+ [a, b = 1, c = 2] = await x;
+ return c;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, array destructuring with default and rest)",
+ expression: "let [a, b = 1, c = 2, ...rest] = await x; rest;",
+ newExpression: `let a, b, c, rest;
+ (async () => {
+ [a, b = 1, c = 2, ...rest] = await x;
+ return rest;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, nested array destructuring with default)",
+ expression: "let [a, b = 1, [c = 2, [d = 3, e = 4]]] = await x; c;",
+ newExpression: `let a, b, c, d, e;
+ (async () => {
+ [a, b = 1, [c = 2, [d = 3, e = 4]]] = await x;
+ return c;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (no bindings, dynamic import)",
+ expression: `
+ var {rainbowLog} = await import("./cool-module.js");
+ rainbowLog("dynamic");`,
+ newExpression: `var rainbowLog;
+ (async () => {
+ ({rainbowLog} = await import("./cool-module.js"));
+ return rainbowLog("dynamic");
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (nullish coalesce operator)",
+ expression: "await x; true ?? false",
+ newExpression: `(async () => {
+ await x;
+ return true ?? false;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (optional chaining operator)",
+ expression: "await x; x?.y?.z",
+ newExpression: `(async () => {
+ await x;
+ return x?.y?.z;
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (async function declaration with nullish coalesce operator)",
+ expression: "async function coalesce(x) { await x; return x ?? false; }",
+ newExpression:
+ "async function coalesce(x) { await x; return x ?? false; }",
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: false,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (async function declaration with optional chaining operator)",
+ expression: "async function chain(x) { await x; return x?.y?.z; }",
+ newExpression: "async function chain(x) { await x; return x?.y?.z; }",
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: false,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ // check that variable declaration in for loop is not put outside of the async iife
+ name: "await (for loop)",
+ expression: "for (let i=0;i<2;i++) {}; var b = await 1;",
+ newExpression: `var b;
+ (async () => {
+ for (let i=0;i<2;i++) {}
+ return (b = await 1);
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ // check that variable declaration in for-in loop is not put outside of the async iife
+ name: "await (for..in loop)",
+ expression: "for (let i in {}) {}; var b = await 1;",
+ newExpression: `var b;
+ (async () => {
+ for (let i in {}) {}
+ return (b = await 1);
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ // check that variable declaration in for-of loop is not put outside of the async iife
+ name: "await (for..of loop)",
+ expression: "for (let i of []) {}; var b = await 1;",
+ newExpression: `var b;
+ (async () => {
+ for (let i of []) {}
+ return (b = await 1);
+ })()`,
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (if condition)",
+ expression: "if (await true) console.log(1);",
+ newExpression: formatAwait("if (await true) console.log(1);"),
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "await (non-expression final statement: bug 1851759)",
+ expression: `j = { "foo": 1, "bar": 2 }; await 42; for (var k in j) { console.log(k); }`,
+ newExpression: formatAwait(`
+ j = {
+ foo: 1,
+ bar: 2,
+ };
+ await 42;
+ for (var k in j) {
+ console.log(k);
+ }`),
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: true,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "simple",
+ expression: "a",
+ newExpression: "a",
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "mappings",
+ expression: "a",
+ newExpression: "_a",
+ bindings: [],
+ mappings: {
+ a: "_a",
+ },
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: false,
+ originalExpression: true,
+ },
+ },
+ {
+ name: "declaration",
+ expression: "var a = 3;",
+ newExpression: "self.a = 3",
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "declaration + destructuring",
+ expression: "var { a } = { a: 3 };",
+ newExpression: "({ a: self.a } = {\n a: 3 \n})",
+ bindings: [],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "bindings",
+ expression: "var a = 3;",
+ newExpression: "a = 3",
+ bindings: ["a"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "bindings + destructuring",
+ expression: "var { a } = { a: 3 };",
+ newExpression: "({ a } = { \n a: 3 \n })",
+ bindings: ["a"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "bindings + destructuring + rest",
+ expression: "var { a, ...foo } = {}",
+ newExpression: "({ a, ...self.foo } = {})",
+ bindings: ["a"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "bindings + array destructuring + rest",
+ expression: "var [a, ...foo] = []",
+ newExpression: "([a, ...self.foo] = [])",
+ bindings: ["a"],
+ mappings: {},
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "bindings + mappings",
+ expression: "a = 3;",
+ newExpression: "self.a = 3",
+ bindings: ["_a"],
+ mappings: { a: "_a" },
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "bindings + mappings + destructuring",
+ expression: "var { a } = { a: 4 }",
+ newExpression: "({ a: self.a } = {\n a: 4 \n})",
+ bindings: ["_a"],
+ mappings: { a: "_a" },
+ shouldMapBindings: true,
+ expectedMapped: {
+ await: false,
+ bindings: true,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "bindings without mappings",
+ expression: "a = 3;",
+ newExpression: "a = 3",
+ bindings: [],
+ mappings: { a: "_a" },
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: false,
+ bindings: false,
+ originalExpression: false,
+ },
+ },
+ {
+ name: "object destructuring + bindings without mappings",
+ expression: "({ a } = {});",
+ newExpression: "({ a: _a } = {})",
+ bindings: [],
+ mappings: { a: "_a" },
+ shouldMapBindings: false,
+ expectedMapped: {
+ await: false,
+ bindings: false,
+ originalExpression: true,
+ },
+ },
+ ]);
+});
diff --git a/devtools/client/debugger/src/workers/parser/tests/mapOriginalExpression.spec.js b/devtools/client/debugger/src/workers/parser/tests/mapOriginalExpression.spec.js
new file mode 100644
index 0000000000..4949d65cd9
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/mapOriginalExpression.spec.js
@@ -0,0 +1,93 @@
+/* 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/>. */
+
+import mapExpression from "../mapExpression";
+import { format } from "prettier";
+
+const formatOutput = output =>
+ format(output, {
+ parser: "babel",
+ });
+
+const mapOriginalExpression = (expression, mappings) =>
+ mapExpression(expression, mappings, [], false, false).expression;
+
+describe("mapOriginalExpression", () => {
+ it("simple", () => {
+ const generatedExpression = mapOriginalExpression("a + b;", {
+ a: "foo",
+ b: "bar",
+ });
+ expect(generatedExpression).toEqual("foo + bar;");
+ });
+
+ it("this", () => {
+ const generatedExpression = mapOriginalExpression("this.prop;", {
+ this: "_this",
+ });
+ expect(generatedExpression).toEqual("_this.prop;");
+ });
+
+ it("member expressions", () => {
+ const generatedExpression = mapOriginalExpression("a + b", {
+ a: "_mod.foo",
+ b: "_mod.bar",
+ });
+ expect(generatedExpression).toEqual("_mod.foo + _mod.bar;");
+ });
+
+ it("block", () => {
+ // todo: maybe wrap with parens ()
+ const generatedExpression = mapOriginalExpression("{a}", {
+ a: "_mod.foo",
+ b: "_mod.bar",
+ });
+ expect(generatedExpression).toEqual("{\n _mod.foo;\n}");
+ });
+
+ it("skips codegen with no mappings", () => {
+ const generatedExpression = mapOriginalExpression("a + b", {
+ a: "a",
+ c: "_c",
+ });
+ expect(generatedExpression).toEqual("a + b");
+ });
+
+ it("object destructuring", () => {
+ const generatedExpression = mapOriginalExpression("({ a } = { a: 4 })", {
+ a: "_mod.foo",
+ });
+
+ expect(formatOutput(generatedExpression)).toEqual(
+ formatOutput("({ a: _mod.foo } = {\n a: 4 \n})")
+ );
+ });
+
+ it("nested object destructuring", () => {
+ const generatedExpression = mapOriginalExpression(
+ "({ a: { b, c } } = { a: 4 })",
+ {
+ a: "_mod.foo",
+ b: "_mod.bar",
+ }
+ );
+
+ expect(formatOutput(generatedExpression)).toEqual(
+ formatOutput("({ a: { b: _mod.bar, c } } = {\n a: 4 \n})")
+ );
+ });
+
+ it("shadowed bindings", () => {
+ const generatedExpression = mapOriginalExpression(
+ "window.thing = function fn(){ var a; a; b; }; a; b; ",
+ {
+ a: "_a",
+ b: "_b",
+ }
+ );
+ expect(generatedExpression).toEqual(
+ "window.thing = function fn() {\n var a;\n a;\n _b;\n};\n_a;\n_b;"
+ );
+ });
+});
diff --git a/devtools/client/debugger/src/workers/parser/tests/sources.spec.js b/devtools/client/debugger/src/workers/parser/tests/sources.spec.js
new file mode 100644
index 0000000000..e84ae4ad22
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/tests/sources.spec.js
@@ -0,0 +1,14 @@
+/* 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/>. */
+
+import { getSource } from "../sources";
+
+describe("sources", () => {
+ it("fail getSource", () => {
+ const sourceId = "some.nonexistent.source.id";
+ expect(() => {
+ getSource(sourceId);
+ }).toThrow();
+ });
+});
diff --git a/devtools/client/debugger/src/workers/parser/utils/ast.js b/devtools/client/debugger/src/workers/parser/utils/ast.js
new file mode 100644
index 0000000000..445645c12f
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/ast.js
@@ -0,0 +1,230 @@
+/* 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/>. */
+
+import { parseScriptTags } from "./parse-script-tags";
+import * as babelParser from "@babel/parser";
+import * as t from "@babel/types";
+import { getSource } from "../sources";
+
+const ASTs = new Map();
+
+function _parse(code, opts) {
+ return babelParser.parse(code, {
+ ...opts,
+ tokens: true,
+ });
+}
+
+const sourceOptions = {
+ generated: {
+ sourceType: "unambiguous",
+ tokens: true,
+ plugins: [
+ "classStaticBlock",
+ "classPrivateProperties",
+ "classPrivateMethods",
+ "classProperties",
+ "objectRestSpread",
+ "optionalChaining",
+ "privateIn",
+ "nullishCoalescingOperator",
+ "regexpUnicodeSets",
+ ],
+ },
+ original: {
+ sourceType: "unambiguous",
+ tokens: true,
+ plugins: [
+ "jsx",
+ "flow",
+ "doExpressions",
+ "optionalChaining",
+ "nullishCoalescingOperator",
+ "decorators-legacy",
+ "objectRestSpread",
+ "classStaticBlock",
+ "classPrivateProperties",
+ "classPrivateMethods",
+ "classProperties",
+ "exportDefaultFrom",
+ "exportNamespaceFrom",
+ "asyncGenerators",
+ "functionBind",
+ "functionSent",
+ "dynamicImport",
+ "react-jsx",
+ "regexpUnicodeSets",
+ ],
+ },
+};
+
+export function parse(text, opts) {
+ let ast = {};
+ if (!text) {
+ return ast;
+ }
+
+ try {
+ ast = _parse(text, opts);
+ } catch (error) {
+ console.error(error);
+ }
+
+ 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, ...sourceOptions.generated });
+}
+
+const VUE_COMPONENT_START = /^\s*</;
+function vueParser({ source, line }) {
+ return parse(source, {
+ startLine: line,
+ ...sourceOptions.original,
+ });
+}
+function parseVueScript(code) {
+ if (typeof code !== "string") {
+ return {};
+ }
+
+ let ast;
+
+ // .vue files go through several passes, so while there is a
+ // single-file-component Vue template, there are also generally .vue files
+ // that are still just JS as well.
+ if (code.match(VUE_COMPONENT_START)) {
+ ast = parseScriptTags(code, vueParser);
+ if (t.isFile(ast)) {
+ // parseScriptTags is currently hard-coded to return scripts, but Vue
+ // always expects ESM syntax, so we just hard-code it.
+ ast.program.sourceType = "module";
+ }
+ } else {
+ ast = parse(code, sourceOptions.original);
+ }
+ return ast;
+}
+
+export function parseConsoleScript(text, opts) {
+ try {
+ return _parse(text, {
+ plugins: [
+ "classStaticBlock",
+ "classPrivateProperties",
+ "classPrivateMethods",
+ "objectRestSpread",
+ "dynamicImport",
+ "nullishCoalescingOperator",
+ "optionalChaining",
+ "regexpUnicodeSets",
+ ],
+ ...opts,
+ allowAwaitOutsideFunction: true,
+ });
+ } catch (e) {
+ return null;
+ }
+}
+
+export function parseScript(text, opts) {
+ return _parse(text, opts);
+}
+
+export function getAst(sourceId) {
+ if (ASTs.has(sourceId)) {
+ return ASTs.get(sourceId);
+ }
+
+ const source = getSource(sourceId);
+
+ if (source.isWasm) {
+ return null;
+ }
+
+ let ast = {};
+ const { contentType } = source;
+ if (contentType == "text/html") {
+ ast = parseScriptTags(source.text, htmlParser) || {};
+ } else if (contentType && contentType === "text/vue") {
+ ast = parseVueScript(source.text) || {};
+ } else if (
+ contentType &&
+ contentType.match(/(javascript|jsx)/) &&
+ !contentType.match(/typescript-jsx/)
+ ) {
+ const type = source.id.includes("original") ? "original" : "generated";
+ const options = sourceOptions[type];
+ ast = parse(source.text, options);
+ } else if (contentType && contentType.match(/typescript/)) {
+ const options = {
+ ...sourceOptions.original,
+ plugins: [
+ ...sourceOptions.original.plugins.filter(
+ p =>
+ p !== "flow" &&
+ p !== "decorators" &&
+ p !== "decorators2" &&
+ (p !== "jsx" || contentType.match(/typescript-jsx/))
+ ),
+ "decorators-legacy",
+ "typescript",
+ ],
+ };
+ ast = parse(source.text, options);
+ }
+
+ ASTs.set(source.id, ast);
+ return ast;
+}
+
+export function clearASTs(sourceIds) {
+ for (const sourceId of sourceIds) {
+ ASTs.delete(sourceId);
+ }
+}
+
+export function traverseAst(sourceId, visitor, state) {
+ const ast = getAst(sourceId);
+ if (!ast || !Object.keys(ast).length) {
+ return null;
+ }
+
+ t.traverse(ast, visitor, state);
+ return ast;
+}
+
+export function hasNode(rootNode, predicate) {
+ try {
+ t.traverse(rootNode, {
+ enter: (node, ancestors) => {
+ if (predicate(node, ancestors)) {
+ throw new Error("MATCH");
+ }
+ },
+ });
+ } catch (e) {
+ if (e.message === "MATCH") {
+ return true;
+ }
+ }
+ return false;
+}
+
+export function replaceNode(ancestors, node) {
+ const parent = ancestors[ancestors.length - 1];
+
+ if (typeof parent.index === "number") {
+ if (Array.isArray(node)) {
+ parent.node[parent.key].splice(parent.index, 1, ...node);
+ } else {
+ parent.node[parent.key][parent.index] = node;
+ }
+ } else {
+ parent.node[parent.key] = node;
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/utils/contains.js b/devtools/client/debugger/src/workers/parser/utils/contains.js
new file mode 100644
index 0000000000..ed4cb31c1d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/contains.js
@@ -0,0 +1,29 @@
+/* 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 startsBefore(a, b) {
+ let before = a.start.line < b.line;
+ if (a.start.line === b.line) {
+ before =
+ a.start.column >= 0 && b.column >= 0 ? a.start.column <= b.column : true;
+ }
+ return before;
+}
+
+function endsAfter(a, b) {
+ let after = a.end.line > b.line;
+ if (a.end.line === b.line) {
+ after =
+ a.end.column >= 0 && b.column >= 0 ? a.end.column >= b.column : true;
+ }
+ return after;
+}
+
+export function containsPosition(a, b) {
+ return startsBefore(a, b) && endsAfter(a, b);
+}
+
+export function containsLocation(a, b) {
+ return containsPosition(a, b.start) && containsPosition(a, b.end);
+}
diff --git a/devtools/client/debugger/src/workers/parser/utils/formatSymbols.js b/devtools/client/debugger/src/workers/parser/utils/formatSymbols.js
new file mode 100644
index 0000000000..3bcf37e7c4
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/formatSymbols.js
@@ -0,0 +1,65 @@
+/* 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/>. */
+
+import { getSymbols } from "../getSymbols";
+
+function formatLocation(loc) {
+ if (!loc) {
+ return "";
+ }
+
+ const { start, end } = loc;
+ const startLoc = `(${start.line}, ${start.column})`;
+ const endLoc = `(${end.line}, ${end.column})`;
+
+ return `[${startLoc}, ${endLoc}]`;
+}
+
+function summarize(symbol) {
+ if (typeof symbol == "boolean") {
+ return symbol ? "true" : "false";
+ }
+
+ const loc = formatLocation(symbol.location);
+ const params = symbol.parameterNames
+ ? `(${symbol.parameterNames.join(", ")})`
+ : "";
+ const expression = symbol.expression || "";
+ const klass = symbol.klass || "";
+ const name = symbol.name == undefined ? "" : symbol.name;
+ const names = symbol.specifiers ? symbol.specifiers.join(", ") : "";
+ const values = symbol.values ? symbol.values.join(", ") : "";
+ const index = symbol.index ? symbol.index : "";
+
+ return `${loc} ${expression} ${name}${params} ${klass} ${names} ${values} ${index}`.trim(); // eslint-disable-line max-len
+}
+const bools = ["hasJsx", "hasTypes"];
+const strings = ["framework"];
+function formatBool(name, symbols) {
+ return `${name}: ${symbols[name] ? "true" : "false"}`;
+}
+
+function formatString(name, symbols) {
+ return `${name}: ${symbols[name]}`;
+}
+
+function formatKey(name, symbols) {
+ if (bools.includes(name)) {
+ return formatBool(name, symbols);
+ }
+
+ if (strings.includes(name)) {
+ return formatString(name, symbols);
+ }
+
+ return `${name}:\n${symbols[name].map(summarize).join("\n")}`;
+}
+
+export function formatSymbols(sourceId) {
+ const symbols = getSymbols(sourceId);
+
+ return Object.keys(symbols)
+ .map(name => formatKey(name, symbols))
+ .join("\n\n");
+}
diff --git a/devtools/client/debugger/src/workers/parser/utils/getFunctionName.js b/devtools/client/debugger/src/workers/parser/utils/getFunctionName.js
new file mode 100644
index 0000000000..1fe85a5c69
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/getFunctionName.js
@@ -0,0 +1,96 @@
+/* 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/>. */
+
+import * as t from "@babel/types";
+
+// Perform ES6's anonymous function name inference for all
+// locations where static analysis is possible.
+// eslint-disable-next-line complexity
+export default function getFunctionName(node, parent) {
+ if (t.isIdentifier(node.id)) {
+ return node.id.name;
+ }
+
+ if (
+ t.isObjectMethod(node, { computed: false }) ||
+ t.isClassMethod(node, { computed: false }) ||
+ t.isClassPrivateMethod(node)
+ ) {
+ const { key } = node;
+
+ if (t.isIdentifier(key)) {
+ return key.name;
+ }
+ if (t.isStringLiteral(key)) {
+ return key.value;
+ }
+ if (t.isNumericLiteral(key)) {
+ return `${key.value}`;
+ }
+
+ if (t.isPrivateName(key)) {
+ return `#${key.id.name}`;
+ }
+ }
+
+ if (
+ t.isObjectProperty(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) ||
+ (t.isClassPrivateProperty(parent, { value: node }) && !parent.computed)
+ ) {
+ const { key } = parent;
+
+ if (t.isIdentifier(key)) {
+ return key.name;
+ }
+ if (t.isStringLiteral(key)) {
+ return key.value;
+ }
+ if (t.isNumericLiteral(key)) {
+ return `${key.value}`;
+ }
+
+ if (t.isPrivateName(key)) {
+ return `#${key.id.name}`;
+ }
+ }
+
+ if (t.isAssignmentExpression(parent, { operator: "=", right: node })) {
+ if (t.isIdentifier(parent.left)) {
+ return parent.left.name;
+ }
+
+ // This case is not supported in standard ES6 name inference, but it
+ // is included here since it is still a helpful case during debugging.
+ if (t.isMemberExpression(parent.left, { computed: false })) {
+ return parent.left.property.name;
+ }
+ }
+
+ if (
+ t.isAssignmentPattern(parent, { right: node }) &&
+ t.isIdentifier(parent.left)
+ ) {
+ return parent.left.name;
+ }
+
+ if (
+ t.isVariableDeclarator(parent, { init: node }) &&
+ t.isIdentifier(parent.id)
+ ) {
+ return parent.id.name;
+ }
+
+ if (
+ t.isExportDefaultDeclaration(parent, { declaration: node }) &&
+ t.isFunctionDeclaration(node)
+ ) {
+ return "default";
+ }
+
+ return "anonymous";
+}
diff --git a/devtools/client/debugger/src/workers/parser/utils/helpers.js b/devtools/client/debugger/src/workers/parser/utils/helpers.js
new file mode 100644
index 0000000000..0045b54136
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/helpers.js
@@ -0,0 +1,232 @@
+/* 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/>. */
+
+import * as t from "@babel/types";
+import generate from "@babel/generator";
+
+export function isFunction(node) {
+ return (
+ t.isFunction(node) ||
+ t.isArrowFunctionExpression(node) ||
+ t.isObjectMethod(node) ||
+ t.isClassMethod(node)
+ );
+}
+
+export function isAwaitExpression(path) {
+ const { node, parent } = path;
+ return (
+ t.isAwaitExpression(node) ||
+ t.isAwaitExpression(parent.init) ||
+ t.isAwaitExpression(parent)
+ );
+}
+
+export function isYieldExpression(path) {
+ const { node, parent } = path;
+ return (
+ t.isYieldExpression(node) ||
+ t.isYieldExpression(parent.init) ||
+ t.isYieldExpression(parent)
+ );
+}
+
+export function isObjectShorthand(parent) {
+ if (!t.isObjectProperty(parent)) {
+ return false;
+ }
+
+ if (parent.value && parent.value.left) {
+ return (
+ parent.value.type === "AssignmentPattern" &&
+ parent.value.left.type === "Identifier"
+ );
+ }
+
+ return (
+ parent.value &&
+ parent.key.start == parent.value.start &&
+ parent.key.loc.identifierName === parent.value.loc.identifierName
+ );
+}
+
+export function getObjectExpressionValue(node) {
+ const { value } = node;
+
+ if (t.isIdentifier(value)) {
+ return value.name;
+ }
+
+ if (t.isCallExpression(value) || t.isFunctionExpression(value)) {
+ return "";
+ }
+ const code = generate(value).code;
+
+ const shouldWrap = t.isObjectExpression(value);
+ return shouldWrap ? `(${code})` : code;
+}
+
+export function getCode(node) {
+ return generate(node).code;
+}
+
+export function getComments(ast) {
+ if (!ast || !ast.comments) {
+ return [];
+ }
+ return ast.comments.map(comment => ({
+ name: comment.location,
+ location: comment.loc,
+ }));
+}
+
+export function isComputedExpression(expression) {
+ return /^\[/m.test(expression);
+}
+
+export function getMemberExpression(root) {
+ function _getMemberExpression(node, expr) {
+ if (t.isMemberExpression(node)) {
+ expr = [node.property.name].concat(expr);
+ return _getMemberExpression(node.object, expr);
+ }
+
+ if (t.isCallExpression(node)) {
+ return [];
+ }
+
+ if (t.isThisExpression(node)) {
+ return ["this"].concat(expr);
+ }
+
+ return [node.name].concat(expr);
+ }
+
+ const expr = _getMemberExpression(root, []);
+ return expr.join(".");
+}
+
+export function getVariables(dec) {
+ if (!dec.id) {
+ return [];
+ }
+
+ if (t.isArrayPattern(dec.id)) {
+ if (!dec.id.elements) {
+ return [];
+ }
+
+ // NOTE: it's possible that an element is empty or has several variables
+ // e.g. const [, a] = arr
+ // e.g. const [{a, b }] = 2
+ return dec.id.elements
+ .filter(Boolean)
+ .map(element => ({
+ name: t.isAssignmentPattern(element)
+ ? element.left.name
+ : element.name || element.argument?.name,
+ location: element.loc,
+ }))
+ .filter(({ name }) => name);
+ }
+
+ return [
+ {
+ name: dec.id.name,
+ location: dec.loc,
+ },
+ ];
+}
+
+/**
+ * Add the identifiers for a given object pattern.
+ *
+ * @param {Array.<Object>} identifiers
+ * the current list of identifiers where to push the new identifiers
+ * related to this path.
+ * @param {Set<String>} identifiersKeys
+ * List of currently registered identifier location key.
+ * @param {Object} pattern
+ */
+export function addPatternIdentifiers(identifiers, identifiersKeys, pattern) {
+ let items;
+ if (t.isObjectPattern(pattern)) {
+ items = pattern.properties.map(({ value }) => value);
+ }
+
+ if (t.isArrayPattern(pattern)) {
+ items = pattern.elements;
+ }
+
+ if (items) {
+ addIdentifiers(identifiers, identifiersKeys, items);
+ }
+}
+
+function addIdentifiers(identifiers, identifiersKeys, items) {
+ for (const item of items) {
+ if (t.isObjectPattern(item) || t.isArrayPattern(item)) {
+ addPatternIdentifiers(identifiers, identifiersKeys, item);
+ } else if (t.isIdentifier(item)) {
+ if (!identifiersKeys.has(nodeLocationKey(item.loc))) {
+ identifiers.push({
+ name: item.name,
+ expression: item.name,
+ location: item.loc,
+ });
+ }
+ }
+ }
+}
+
+// Top Level checks the number of "body" nodes in the ancestor chain
+// if the node is top-level, then it shoul only have one body.
+export function isTopLevel(ancestors) {
+ return ancestors.filter(ancestor => ancestor.key == "body").length == 1;
+}
+
+export function nodeLocationKey({ start, end }) {
+ return `${start.line}:${start.column}:${end.line}:${end.column}`;
+}
+
+export function getFunctionParameterNames(path) {
+ if (path.node.params != null) {
+ return path.node.params.map(param => {
+ if (param.type !== "AssignmentPattern") {
+ return param.name;
+ }
+
+ // Parameter with default value
+ if (
+ param.left.type === "Identifier" &&
+ param.right.type === "Identifier"
+ ) {
+ return `${param.left.name} = ${param.right.name}`;
+ } else if (
+ param.left.type === "Identifier" &&
+ param.right.type === "StringLiteral"
+ ) {
+ return `${param.left.name} = ${param.right.value}`;
+ } else if (
+ param.left.type === "Identifier" &&
+ param.right.type === "ObjectExpression"
+ ) {
+ return `${param.left.name} = {}`;
+ } else if (
+ param.left.type === "Identifier" &&
+ param.right.type === "ArrayExpression"
+ ) {
+ return `${param.left.name} = []`;
+ } else if (
+ param.left.type === "Identifier" &&
+ param.right.type === "NullLiteral"
+ ) {
+ return `${param.left.name} = null`;
+ }
+
+ return null;
+ });
+ }
+ return [];
+}
diff --git a/devtools/client/debugger/src/workers/parser/utils/inferClassName.js b/devtools/client/debugger/src/workers/parser/utils/inferClassName.js
new file mode 100644
index 0000000000..09d25f275d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/inferClassName.js
@@ -0,0 +1,93 @@
+/* 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/>. */
+
+import * as t from "@babel/types";
+
+// the function class is inferred from a call like
+// createClass or extend
+function fromCallExpression(callExpression) {
+ const allowlist = ["extend", "createClass"];
+ const { callee } = callExpression.node;
+ if (!callee) {
+ return null;
+ }
+
+ const name = t.isMemberExpression(callee)
+ ? callee.property.name
+ : callee.name;
+
+ if (!allowlist.includes(name)) {
+ return null;
+ }
+
+ const variable = callExpression.findParent(p =>
+ t.isVariableDeclarator(p.node)
+ );
+ if (variable) {
+ return variable.node.id.name;
+ }
+
+ const assignment = callExpression.findParent(p =>
+ t.isAssignmentExpression(p.node)
+ );
+
+ if (!assignment) {
+ return null;
+ }
+
+ 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;
+ if (!left) {
+ return null;
+ }
+
+ if (
+ t.isMemberExpression(left) &&
+ left.object &&
+ t.isMemberExpression(left.object) &&
+ left.object.property.identifier === "prototype"
+ ) {
+ return left.object.object.name;
+ }
+
+ return null;
+}
+
+// infer class finds an appropriate class for functions
+// that are defined inside of a class like thing.
+// e.g. `class Foo`, `TodoClass.prototype.foo`,
+// `Todo = createClass({ foo: () => {}})`
+export function inferClassName(path) {
+ const classDeclaration = path.findParent(p => t.isClassDeclaration(p.node));
+ if (classDeclaration) {
+ return classDeclaration.node.id.name;
+ }
+
+ const callExpression = path.findParent(p => t.isCallExpression(p.node));
+ if (callExpression) {
+ return fromCallExpression(callExpression);
+ }
+
+ const assignment = path.findParent(p => t.isAssignmentExpression(p.node));
+ if (assignment) {
+ return fromPrototype(assignment);
+ }
+
+ return null;
+}
diff --git a/devtools/client/debugger/src/workers/parser/utils/parse-script-tags/customParse.js b/devtools/client/debugger/src/workers/parser/utils/parse-script-tags/customParse.js
new file mode 100644
index 0000000000..5c7fed480d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/parse-script-tags/customParse.js
@@ -0,0 +1,132 @@
+/**
+ * https://github.com/ryanjduffy/parse-script-tags
+ *
+ * Copyright (c) by Ryan Duff
+ * Licensed under the MIT License.
+ */
+
+import * as types from "@babel/types";
+
+import parseFragment from "./parseScriptFragment.js";
+
+const startScript = /<script[^>]*>/im;
+const endScript = /<\/script\s*>/im;
+// https://stackoverflow.com/questions/5034781/js-regex-to-split-by-line#comment5633979_5035005
+const newLines = /\r\n|[\n\v\f\r\x85\u2028\u2029]/;
+
+function getType(tag) {
+ const fragment = parseFragment(tag);
+
+ if (fragment) {
+ const type = fragment.attributes.type;
+
+ return type ? type.toLowerCase() : null;
+ }
+
+ return null;
+}
+
+function getCandidateScriptLocations(source, index) {
+ const i = index || 0;
+ const str = source.substring(i);
+
+ const startMatch = startScript.exec(str);
+ if (startMatch) {
+ const startsAt = startMatch.index + startMatch[0].length;
+ const afterStart = str.substring(startsAt);
+ const endMatch = endScript.exec(afterStart);
+ if (endMatch) {
+ const locLength = endMatch.index;
+ const locIndex = i + startsAt;
+ const endIndex = locIndex + locLength + endMatch[0].length;
+
+ // extract the complete tag (incl start and end tags and content). if the
+ // type is invalid (= not JS), skip this tag and continue
+ const tag = source.substring(i + startMatch.index, endIndex);
+ const type = getType(tag);
+ if (
+ type &&
+ type !== "javascript" &&
+ type !== "text/javascript" &&
+ type !== "module"
+ ) {
+ return getCandidateScriptLocations(source, endIndex);
+ }
+
+ return [
+ adjustForLineAndColumn(source, {
+ index: locIndex,
+ length: locLength,
+ source: source.substring(locIndex, locIndex + locLength),
+ }),
+ ...getCandidateScriptLocations(source, endIndex),
+ ];
+ }
+ }
+
+ return [];
+}
+
+function parseScripts(locations, parser) {
+ return locations.map(parser);
+}
+
+function calcLineAndColumn(source, index) {
+ const lines = source.substring(0, index).split(newLines);
+ const line = lines.length;
+ const column = lines.pop().length + 1;
+
+ return {
+ column,
+ line,
+ };
+}
+
+function adjustForLineAndColumn(fullSource, location) {
+ const { column, line } = calcLineAndColumn(fullSource, location.index);
+ return Object.assign({}, location, {
+ line,
+ column,
+ // prepend whitespace for scripts that do not start on the first column
+ // NOTE: `column` is 1-based
+ source: " ".repeat(column - 1) + location.source,
+ });
+}
+
+function parseScriptTags(source, parser) {
+ const scripts = parseScripts(getCandidateScriptLocations(source), parser)
+ .filter(types.isFile)
+ .reduce(
+ (main, script) => {
+ return {
+ statements: main.statements.concat(script.program.body),
+ comments: main.comments.concat(script.comments),
+ tokens: main.tokens.concat(script.tokens),
+ };
+ },
+ {
+ statements: [],
+ comments: [],
+ tokens: [],
+ }
+ );
+
+ const program = types.program(scripts.statements);
+ const file = types.file(program, scripts.comments, scripts.tokens);
+
+ const end = calcLineAndColumn(source, source.length);
+ file.start = program.start = 0;
+ file.end = program.end = source.length;
+ file.loc = program.loc = {
+ start: {
+ line: 1,
+ column: 0,
+ },
+ end,
+ };
+
+ return file;
+}
+
+export default parseScriptTags;
+export { getCandidateScriptLocations, parseScripts, parseScriptTags };
diff --git a/devtools/client/debugger/src/workers/parser/utils/parse-script-tags/index.js b/devtools/client/debugger/src/workers/parser/utils/parse-script-tags/index.js
new file mode 100644
index 0000000000..e85d0cdc53
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/parse-script-tags/index.js
@@ -0,0 +1,60 @@
+/**
+ * https://github.com/ryanjduffy/parse-script-tags
+ *
+ * Copyright (c) by Ryan Duff
+ * Licensed under the MIT License.
+ */
+
+import * as types from "@babel/types";
+import * as babelParser from "@babel/parser";
+
+import {
+ getCandidateScriptLocations,
+ parseScripts as customParseScripts,
+ parseScriptTags as customParseScriptTags,
+} from "./customParse.js";
+
+function parseScript({ source, line }) {
+ // remove empty or only whitespace scripts
+ if (source.length === 0 || /^\s+$/.test(source)) {
+ return null;
+ }
+
+ try {
+ return babelParser.parse(source, {
+ sourceType: "script",
+ startLine: line,
+ });
+ } catch (e) {
+ return null;
+ }
+}
+
+function parseScripts(locations, parser = parseScript) {
+ return customParseScripts(locations, parser);
+}
+
+function extractScriptTags(source) {
+ return parseScripts(getCandidateScriptLocations(source), loc => {
+ const ast = parseScript(loc);
+
+ if (ast) {
+ return loc;
+ }
+
+ return null;
+ }).filter(types.isFile);
+}
+
+function parseScriptTags(source, parser = parseScript) {
+ return customParseScriptTags(source, parser);
+}
+
+export default parseScriptTags;
+export {
+ extractScriptTags,
+ getCandidateScriptLocations,
+ parseScript,
+ parseScripts,
+ parseScriptTags,
+};
diff --git a/devtools/client/debugger/src/workers/parser/utils/parse-script-tags/parseScriptFragment.js b/devtools/client/debugger/src/workers/parser/utils/parse-script-tags/parseScriptFragment.js
new file mode 100644
index 0000000000..11dfe4dc1b
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/parse-script-tags/parseScriptFragment.js
@@ -0,0 +1,155 @@
+/**
+ * https://github.com/ryanjduffy/parse-script-tags
+ *
+ * Copyright (c) by Ryan Duff
+ * Licensed under the MIT License.
+ */
+
+const alphanum = /[a-z0-9\-]/i;
+
+function parseToken(str, start) {
+ let i = start;
+ while (i < str.length && alphanum.test(str.charAt(i++))) {
+ continue;
+ }
+
+ if (i !== start) {
+ return {
+ token: str.substring(start, i - 1),
+ index: i,
+ };
+ }
+
+ return null;
+}
+
+function parseAttributes(str, start) {
+ let i = start;
+ const attributes = {};
+ let attribute = null;
+
+ while (i < str.length) {
+ const c = str.charAt(i);
+
+ if (attribute === null && c == ">") {
+ break;
+ } else if (attribute === null && alphanum.test(c)) {
+ attribute = {
+ name: null,
+ value: true,
+ bool: true,
+ terminator: null,
+ };
+
+ const attributeNameNode = parseToken(str, i);
+ if (attributeNameNode) {
+ attribute.name = attributeNameNode.token;
+ i = attributeNameNode.index - 2;
+ }
+ } else if (attribute !== null) {
+ if (c === "=") {
+ // once we've started an attribute, look for = to indicate
+ // it's a non-boolean attribute
+ attribute.bool = false;
+ if (attribute.value === true) {
+ attribute.value = "";
+ }
+ } else if (
+ !attribute.bool &&
+ attribute.terminator === null &&
+ (c === '"' || c === "'")
+ ) {
+ // once we've determined it's non-boolean, look for a
+ // value terminator (", ')
+ attribute.terminator = c;
+ } else if (attribute.terminator) {
+ if (c === attribute.terminator) {
+ // if we had a terminator and found another, we've
+ // reach the end of the attribute
+ attributes[attribute.name] = attribute.value;
+ attribute = null;
+ } else {
+ // otherwise, append the character to the attribute value
+ attribute.value += c;
+
+ // check for an escaped terminator and push it as well
+ // to avoid terminating prematurely
+ if (c === "\\") {
+ const next = str.charAt(i + 1);
+ if (next === attribute.terminator) {
+ attribute.value += next;
+ i += 1;
+ }
+ }
+ }
+ } else if (!/\s/.test(c)) {
+ // if we've hit a non-space character and aren't processing a value,
+ // we're starting a new attribute so push the attribute and clear the
+ // local variable
+ attributes[attribute.name] = attribute.value;
+ attribute = null;
+
+ // move the cursor back to re-find the start of the attribute
+ i -= 1;
+ }
+ }
+
+ i++;
+ }
+
+ if (i !== start) {
+ return {
+ attributes,
+ index: i,
+ };
+ }
+
+ return null;
+}
+
+function parseFragment(str, start = 0) {
+ let tag = null;
+ let open = false;
+ let attributes = {};
+
+ let i = start;
+ while (i < str.length) {
+ const c = str.charAt(i++);
+
+ if (!open && !tag && c === "<") {
+ // Open Start Tag
+ open = true;
+
+ const tagNode = parseToken(str, i);
+ if (!tagNode) {
+ return null;
+ }
+
+ i = tagNode.index - 1;
+ tag = tagNode.token;
+ } else if (open && c === ">") {
+ // Close Start Tag
+ break;
+ } else if (open) {
+ // Attributes
+ const attributeNode = parseAttributes(str, i - 1);
+
+ if (attributeNode) {
+ i = attributeNode.index;
+ attributes = attributeNode.attributes || attributes;
+ }
+ }
+ }
+
+ if (tag) {
+ return {
+ tag,
+ attributes,
+ };
+ }
+
+ return null;
+}
+
+export default parseFragment;
+export { parseFragment };
diff --git a/devtools/client/debugger/src/workers/parser/utils/simple-path.js b/devtools/client/debugger/src/workers/parser/utils/simple-path.js
new file mode 100644
index 0000000000..b3958dcf42
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/simple-path.js
@@ -0,0 +1,104 @@
+/* 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/>. */
+
+export default function createSimplePath(ancestors) {
+ if (ancestors.length === 0) {
+ return null;
+ }
+
+ // Slice the array because babel-types traverse may continue mutating
+ // the ancestors array in later traversal logic.
+ return new SimplePath(ancestors.slice());
+}
+
+/**
+ * Mimics @babel/traverse's NodePath API in a simpler fashion that isn't as
+ * heavy, but still allows the ease of passing paths around to process nested
+ * AST structures.
+ */
+class SimplePath {
+ _index;
+ _ancestors;
+ _ancestor;
+
+ _parentPath;
+
+ constructor(ancestors, index = ancestors.length - 1) {
+ if (index < 0 || index >= ancestors.length) {
+ console.error(ancestors);
+ throw new Error("Created invalid path");
+ }
+
+ this._ancestors = ancestors;
+ this._ancestor = ancestors[index];
+ this._index = index;
+ }
+
+ get parentPath() {
+ let path = this._parentPath;
+ if (path === undefined) {
+ if (this._index === 0) {
+ path = null;
+ } else {
+ path = new SimplePath(this._ancestors, this._index - 1);
+ }
+ this._parentPath = path;
+ }
+
+ return path;
+ }
+
+ get parent() {
+ return this._ancestor.node;
+ }
+
+ get node() {
+ const { node, key, index } = this._ancestor;
+
+ if (typeof index === "number") {
+ return node[key][index];
+ }
+
+ return node[key];
+ }
+
+ get key() {
+ return this._ancestor.key;
+ }
+
+ get type() {
+ return this.node.type;
+ }
+
+ get inList() {
+ return typeof this._ancestor.index === "number";
+ }
+
+ get containerIndex() {
+ const { index } = this._ancestor;
+
+ if (typeof index !== "number") {
+ throw new Error("Cannot get index of non-array node");
+ }
+
+ return index;
+ }
+
+ find(predicate) {
+ for (let path = this; path; path = path.parentPath) {
+ if (predicate(path)) {
+ return path;
+ }
+ }
+ return null;
+ }
+
+ findParent(predicate) {
+ if (!this.parentPath) {
+ throw new Error("Cannot use findParent on root path");
+ }
+
+ return this.parentPath.find(predicate);
+ }
+}
diff --git a/devtools/client/debugger/src/workers/parser/utils/tests/ast.spec.js b/devtools/client/debugger/src/workers/parser/utils/tests/ast.spec.js
new file mode 100644
index 0000000000..e8d2964205
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/utils/tests/ast.spec.js
@@ -0,0 +1,41 @@
+/* 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/>. */
+
+import { getAst } from "../ast";
+import { setSource } from "../../sources";
+import cases from "jest-in-case";
+
+import { makeMockSourceAndContent } from "../../../../utils/test-mockup";
+
+const astKeys = [
+ "type",
+ "start",
+ "end",
+ "loc",
+ "errors",
+ "program",
+ "comments",
+ "tokens",
+];
+
+cases(
+ "ast.getAst",
+ ({ name }) => {
+ const source = makeMockSourceAndContent(undefined, "foo", name, "2");
+ setSource({
+ id: source.id,
+ text: source.content.value || "",
+ contentType: source.content.contentType,
+ isWasm: false,
+ });
+ const ast = getAst("foo");
+ expect(ast && Object.keys(ast)).toEqual(astKeys);
+ },
+ [
+ { name: "text/javascript" },
+ { name: "application/javascript" },
+ { name: "application/x-javascript" },
+ { name: "text/jsx" },
+ ]
+);
diff --git a/devtools/client/debugger/src/workers/parser/worker.js b/devtools/client/debugger/src/workers/parser/worker.js
new file mode 100644
index 0000000000..e0c25632f3
--- /dev/null
+++ b/devtools/client/debugger/src/workers/parser/worker.js
@@ -0,0 +1,39 @@
+/* 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/>. */
+
+import {
+ getSymbols,
+ getFunctionSymbols,
+ getClassSymbols,
+ getClosestFunctionName,
+ clearSymbols,
+} from "./getSymbols";
+import { clearASTs } from "./utils/ast";
+import getScopes, { clearScopes } from "./getScopes";
+import { setSource, clearSources } from "./sources";
+import findOutOfScopeLocations from "./findOutOfScopeLocations";
+import findBestMatchExpression from "./findBestMatchExpression";
+import mapExpression from "./mapExpression";
+
+import { workerHandler } from "../../../../shared/worker-utils";
+
+function clearAllHelpersForSources(sourceIds) {
+ clearASTs(sourceIds);
+ clearScopes(sourceIds);
+ clearSources(sourceIds);
+ clearSymbols(sourceIds);
+}
+
+self.onmessage = workerHandler({
+ findOutOfScopeLocations,
+ findBestMatchExpression,
+ getSymbols,
+ getFunctionSymbols,
+ getClassSymbols,
+ getClosestFunctionName,
+ getScopes,
+ clearSources: clearAllHelpersForSources,
+ mapExpression,
+ setSource,
+});
diff --git a/devtools/client/debugger/src/workers/pretty-print/LICENSE.md b/devtools/client/debugger/src/workers/pretty-print/LICENSE.md
new file mode 100644
index 0000000000..cc8e9a752c
--- /dev/null
+++ b/devtools/client/debugger/src/workers/pretty-print/LICENSE.md
@@ -0,0 +1,23 @@
+Copyright (c) 2013, Nick Fitzgerald
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT HOLDER OR 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.
diff --git a/devtools/client/debugger/src/workers/pretty-print/index.js b/devtools/client/debugger/src/workers/pretty-print/index.js
new file mode 100644
index 0000000000..4b151b39e4
--- /dev/null
+++ b/devtools/client/debugger/src/workers/pretty-print/index.js
@@ -0,0 +1,30 @@
+/* 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/>. */
+
+import { WorkerDispatcher } from "devtools/client/shared/worker-utils";
+
+const WORKER_URL =
+ "resource://devtools/client/debugger/dist/pretty-print-worker.js";
+
+export class PrettyPrintDispatcher extends WorkerDispatcher {
+ constructor(jestUrl) {
+ super(jestUrl || WORKER_URL);
+ }
+
+ #prettyPrintTask = this.task("prettyPrint");
+ #prettyPrintInlineScriptTask = this.task("prettyPrintInlineScript");
+ #getSourceMapForTask = this.task("getSourceMapForTask");
+
+ prettyPrint(options) {
+ return this.#prettyPrintTask(options);
+ }
+
+ prettyPrintInlineScript(options) {
+ return this.#prettyPrintInlineScriptTask(options);
+ }
+
+ getSourceMap(taskId) {
+ return this.#getSourceMapForTask(taskId);
+ }
+}
diff --git a/devtools/client/debugger/src/workers/pretty-print/moz.build b/devtools/client/debugger/src/workers/pretty-print/moz.build
new file mode 100644
index 0000000000..b7223ac81a
--- /dev/null
+++ b/devtools/client/debugger/src/workers/pretty-print/moz.build
@@ -0,0 +1,10 @@
+# vim: set filetype=python:
+# 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/.
+
+DIRS += []
+
+CompiledModules(
+ "index.js",
+)
diff --git a/devtools/client/debugger/src/workers/pretty-print/pretty-fast.js b/devtools/client/debugger/src/workers/pretty-print/pretty-fast.js
new file mode 100644
index 0000000000..44b07f4eda
--- /dev/null
+++ b/devtools/client/debugger/src/workers/pretty-print/pretty-fast.js
@@ -0,0 +1,1178 @@
+/* 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/>. */
+
+/* eslint-disable complexity */
+
+var acorn = require("acorn");
+var sourceMap = require("source-map");
+const NEWLINE_CODE = 10;
+
+export function prettyFast(input, options) {
+ return new PrettyFast(options).getPrettifiedCodeAndSourceMap(input);
+}
+
+// If any of these tokens are seen before a "[" token, we know that "[" token
+// is the start of an array literal, rather than a property access.
+//
+// The only exception is "}", which would need to be disambiguated by
+// parsing. The majority of the time, an open bracket following a closing
+// curly is going to be an array literal, so we brush the complication under
+// the rug, and handle the ambiguity by always assuming that it will be an
+// array literal.
+const PRE_ARRAY_LITERAL_TOKENS = new Set([
+ "typeof",
+ "void",
+ "delete",
+ "case",
+ "do",
+ "=",
+ "in",
+ "of",
+ "...",
+ "{",
+ "*",
+ "/",
+ "%",
+ "else",
+ ";",
+ "++",
+ "--",
+ "+",
+ "-",
+ "~",
+ "!",
+ ":",
+ "?",
+ ">>",
+ ">>>",
+ "<<",
+ "||",
+ "&&",
+ "<",
+ ">",
+ "<=",
+ ">=",
+ "instanceof",
+ "&",
+ "^",
+ "|",
+ "==",
+ "!=",
+ "===",
+ "!==",
+ ",",
+ "}",
+]);
+
+// If any of these tokens are seen before a "{" token, we know that "{" token
+// is the start of an object literal, rather than the start of a block.
+const PRE_OBJECT_LITERAL_TOKENS = new Set([
+ "typeof",
+ "void",
+ "delete",
+ "=",
+ "in",
+ "of",
+ "...",
+ "*",
+ "/",
+ "%",
+ "++",
+ "--",
+ "+",
+ "-",
+ "~",
+ "!",
+ ">>",
+ ">>>",
+ "<<",
+ "<",
+ ">",
+ "<=",
+ ">=",
+ "instanceof",
+ "&",
+ "^",
+ "|",
+ "==",
+ "!=",
+ "===",
+ "!==",
+]);
+
+class PrettyFast {
+ /**
+ * @param {Object} options: Provides configurability of the pretty printing.
+ * @param {String} options.url: The URL string of the ugly JS code.
+ * @param {String} options.indent: The string to indent code by.
+ * @param {SourceMapGenerator} options.sourceMapGenerator: An optional sourceMapGenerator
+ * the mappings will be added to.
+ * @param {Boolean} options.prefixWithNewLine: When true, the pretty printed code will start
+ * with a line break
+ * @param {Integer} options.originalStartLine: The line the passed script starts at (1-based).
+ * This is used for inline scripts where we need to account for the lines
+ * before the script tag
+ * @param {Integer} options.originalStartColumn: The column the passed script starts at (1-based).
+ * This is used for inline scripts where we need to account for the position
+ * of the script tag within the line.
+ * @param {Integer} options.generatedStartLine: The line where the pretty printed script
+ * will start at (1-based). This is used for pretty printing HTML file,
+ * where we might have handle previous inline scripts that impact the
+ * position of this script.
+ */
+ constructor(options = {}) {
+ // The level of indents deep we are.
+ this.#indentLevel = 0;
+ this.#indentChar = options.indent;
+
+ // We will handle mappings between ugly and pretty printed code in this SourceMapGenerator.
+ this.#sourceMapGenerator =
+ options.sourceMapGenerator ||
+ new sourceMap.SourceMapGenerator({
+ file: options.url,
+ });
+
+ this.#file = options.url;
+ this.#hasOriginalStartLine = "originalStartLine" in options;
+ this.#hasOriginalStartColumn = "originalStartColumn" in options;
+ this.#hasGeneratedStartLine = "generatedStartLine" in options;
+ this.#originalStartLine = options.originalStartLine;
+ this.#originalStartColumn = options.originalStartColumn;
+ this.#generatedStartLine = options.generatedStartLine;
+ this.#prefixWithNewLine = options.prefixWithNewLine;
+ }
+
+ /* options */
+ #indentChar;
+ #indentLevel;
+ #file;
+ #hasOriginalStartLine;
+ #hasOriginalStartColumn;
+ #hasGeneratedStartLine;
+ #originalStartLine;
+ #originalStartColumn;
+ #prefixWithNewLine;
+ #generatedStartLine;
+ #sourceMapGenerator;
+
+ /* internals */
+
+ // Whether or not we added a newline on after we added the previous token.
+ #addedNewline = false;
+ // Whether or not we added a space after we added the previous token.
+ #addedSpace = false;
+ #currentCode = "";
+ #currentLine = 1;
+ #currentColumn = 0;
+ // The tokens parsed by acorn.
+ #tokenQueue;
+ // The index of the current token in this.#tokenQueue.
+ #currentTokenIndex;
+ // The previous token we added to the pretty printed code.
+ #previousToken;
+ // Stack of token types/keywords that can affect whether we want to add a
+ // newline or a space. We can make that decision based on what token type is
+ // on the top of the stack. For example, a comma in a parameter list should
+ // be followed by a space, while a comma in an object literal should be
+ // followed by a newline.
+ //
+ // Strings that go on the stack:
+ //
+ // - "{"
+ // - "{\n"
+ // - "("
+ // - "(\n"
+ // - "["
+ // - "[\n"
+ // - "do"
+ // - "?"
+ // - "switch"
+ // - "case"
+ // - "default"
+ //
+ // The difference between "[" and "[\n" (as well as "{" and "{\n", and "(" and "(\n")
+ // is that "\n" is used when we are treating (curly) brackets/parens as line delimiters
+ // and should increment and decrement the indent level when we find them.
+ // "[" can represent either a property access (e.g. `x["hi"]`), or an empty array literal
+ // "{" only represents an empty object literals
+ // "(" can represent lots of different things (wrapping expression, if/loop condition, function call, …)
+ #stack = [];
+
+ /**
+ * @param {String} input: The ugly JS code we want to pretty print.
+ * @returns {Object}
+ * An object with the following properties:
+ * - code: The pretty printed code string.
+ * - map: A SourceMapGenerator instance.
+ */
+ getPrettifiedCodeAndSourceMap(input) {
+ // Add the initial new line if needed
+ if (this.#prefixWithNewLine) {
+ this.#write("\n");
+ }
+
+ // Pass through acorn's tokenizer and append tokens and comments into a
+ // single queue to process. For example, the source file:
+ //
+ // foo
+ // // a
+ // // b
+ // bar
+ //
+ // After this process, tokenQueue has the following token stream:
+ //
+ // [ foo, '// a', '// b', bar]
+ this.#tokenQueue = this.#getTokens(input);
+
+ for (let i = 0, len = this.#tokenQueue.length; i < len; i++) {
+ this.#currentTokenIndex = i;
+ const token = this.#tokenQueue[i];
+ const nextToken = this.#tokenQueue[i + 1];
+ this.#handleToken(token, nextToken);
+
+ // Acorn's tokenizer re-uses tokens, so we have to copy the previous token on
+ // every iteration. We follow acorn's lead here, and reuse the previousToken
+ // object the same way that acorn reuses the token object. This allows us
+ // to avoid allocations and minimize GC pauses.
+ if (!this.#previousToken) {
+ this.#previousToken = { loc: { start: {}, end: {} } };
+ }
+ this.#previousToken.start = token.start;
+ this.#previousToken.end = token.end;
+ this.#previousToken.loc.start.line = token.loc.start.line;
+ this.#previousToken.loc.start.column = token.loc.start.column;
+ this.#previousToken.loc.end.line = token.loc.end.line;
+ this.#previousToken.loc.end.column = token.loc.end.column;
+ this.#previousToken.type = token.type;
+ this.#previousToken.value = token.value;
+ }
+
+ return { code: this.#currentCode, map: this.#sourceMapGenerator };
+ }
+
+ /**
+ * Write a pretty printed string to the prettified string and for tokens, add their
+ * mapping to the SourceMapGenerator.
+ *
+ * @param String str
+ * The string to be added to the result.
+ * @param Number line
+ * The line number the string came from in the ugly source.
+ * @param Number column
+ * The column number the string came from in the ugly source.
+ * @param Boolean isToken
+ * Set to true when writing tokens, so we can differentiate them from the
+ * whitespace we add.
+ */
+ #write(str, line, column, isToken) {
+ this.#currentCode += str;
+ if (isToken) {
+ this.#sourceMapGenerator.addMapping({
+ source: this.#file,
+ // We need to swap original and generated locations, as the prettified text should
+ // be seen by the sourcemap service as the "original" one.
+ generated: {
+ // originalStartLine is 1-based, and here we just want to offset by a number of
+ // lines, so we need to decrement it
+ line: this.#hasOriginalStartLine
+ ? line + (this.#originalStartLine - 1)
+ : line,
+ // We only need to adjust the column number if we're looking at the first line, to
+ // account for the html text before the opening <script> tag.
+ column:
+ line == 1 && this.#hasOriginalStartColumn
+ ? column + this.#originalStartColumn
+ : column,
+ },
+ original: {
+ // generatedStartLine is 1-based, and here we just want to offset by a number of
+ // lines, so we need to decrement it.
+ line: this.#hasGeneratedStartLine
+ ? this.#currentLine + (this.#generatedStartLine - 1)
+ : this.#currentLine,
+ column: this.#currentColumn,
+ },
+ name: null,
+ });
+ }
+
+ for (let idx = 0, length = str.length; idx < length; idx++) {
+ if (str.charCodeAt(idx) === NEWLINE_CODE) {
+ this.#currentLine++;
+ this.#currentColumn = 0;
+ } else {
+ this.#currentColumn++;
+ }
+ }
+ }
+
+ /**
+ * Add the given token to the pretty printed results.
+ *
+ * @param Object token
+ * The token to add.
+ */
+ #writeToken(token) {
+ if (token.type.label == "string") {
+ this.#write(
+ `'${sanitize(token.value)}'`,
+ token.loc.start.line,
+ token.loc.start.column,
+ true
+ );
+ } else if (token.type.label == "regexp") {
+ this.#write(
+ String(token.value.value),
+ token.loc.start.line,
+ token.loc.start.column,
+ true
+ );
+ } else {
+ let value;
+ if (token.value != null) {
+ value = token.value;
+ if (token.type.label === "privateId") {
+ value = `#${value}`;
+ }
+ } else {
+ value = token.type.label;
+ }
+ this.#write(
+ String(value),
+ token.loc.start.line,
+ token.loc.start.column,
+ true
+ );
+ }
+ }
+
+ /**
+ * Returns the tokens computed with acorn.
+ *
+ * @param String input
+ * The JS code we want the tokens of.
+ * @returns Array<Object>
+ */
+ #getTokens(input) {
+ const tokens = [];
+
+ const res = acorn.tokenizer(input, {
+ locations: true,
+ ecmaVersion: "latest",
+ onComment(block, text, start, end, startLoc, endLoc) {
+ tokens.push({
+ type: {},
+ comment: true,
+ block,
+ text,
+ loc: { start: startLoc, end: endLoc },
+ });
+ },
+ });
+
+ for (;;) {
+ const token = res.getToken();
+ tokens.push(token);
+ if (token.type.label == "eof") {
+ break;
+ }
+ }
+
+ return tokens;
+ }
+
+ /**
+ * Add the required whitespace before this token, whether that is a single
+ * space, newline, and/or the indent on fresh lines.
+ *
+ * @param Object token
+ * The token we are currently handling.
+ * @param {Object|undefined} nextToken
+ * The next token, might not exist if we're on the last token
+ */
+ #handleToken(token, nextToken) {
+ if (token.comment) {
+ let commentIndentLevel = this.#indentLevel;
+ if (this.#previousToken?.loc?.end?.line == token.loc.start.line) {
+ commentIndentLevel = 0;
+ this.#write(" ");
+ }
+ this.#addComment(
+ commentIndentLevel,
+ token.block,
+ token.text,
+ token.loc.start.line,
+ nextToken
+ );
+ return;
+ }
+
+ // Shorthand for token.type.keyword, so we don't have to repeatedly access
+ // properties.
+ const ttk = token.type.keyword;
+
+ if (ttk && this.#previousToken?.type?.label == ".") {
+ token.type = acorn.tokTypes.name;
+ }
+
+ // Shorthand for token.type.label, so we don't have to repeatedly access
+ // properties.
+ const ttl = token.type.label;
+
+ if (ttl == "eof") {
+ if (!this.#addedNewline) {
+ this.#write("\n");
+ }
+ return;
+ }
+
+ if (belongsOnStack(token)) {
+ let stackEntry;
+
+ if (isArrayLiteral(token, this.#previousToken)) {
+ // Don't add new lines for empty array literals
+ stackEntry = nextToken?.type?.label === "]" ? "[" : "[\n";
+ } else if (isObjectLiteral(token, this.#previousToken)) {
+ // Don't add new lines for empty object literals
+ stackEntry = nextToken?.type?.label === "}" ? "{" : "{\n";
+ } else if (
+ isRoundBracketStartingLongParenthesis(
+ token,
+ this.#tokenQueue,
+ this.#currentTokenIndex
+ )
+ ) {
+ stackEntry = "(\n";
+ } else if (ttl == "{") {
+ // We need to add a line break for "{" which are not empty object literals
+ stackEntry = "{\n";
+ } else {
+ stackEntry = ttl || ttk;
+ }
+
+ this.#stack.push(stackEntry);
+ }
+
+ this.#maybeDecrementIndent(token);
+ this.#prependWhiteSpace(token);
+ this.#writeToken(token);
+ this.#addedSpace = false;
+
+ // If the next token is going to be a comment starting on the same line,
+ // then no need to add a new line here
+ if (
+ !nextToken ||
+ !nextToken.comment ||
+ token.loc.end.line != nextToken.loc.start.line
+ ) {
+ this.#maybeAppendNewline(token);
+ }
+
+ this.#maybePopStack(token);
+ this.#maybeIncrementIndent(token);
+ }
+
+ /**
+ * Returns true if the given token should cause us to pop the stack.
+ */
+ #maybePopStack(token) {
+ const ttl = token.type.label;
+ const ttk = token.type.keyword;
+ const top = this.#stack.at(-1);
+
+ if (
+ ttl == "]" ||
+ ttl == ")" ||
+ ttl == "}" ||
+ (ttl == ":" && (top == "case" || top == "default" || top == "?")) ||
+ (ttk == "while" && top == "do")
+ ) {
+ this.#stack.pop();
+ if (ttl == "}" && this.#stack.at(-1) == "switch") {
+ this.#stack.pop();
+ }
+ }
+ }
+
+ #maybeIncrementIndent(token) {
+ if (
+ // Don't increment indent for empty object literals
+ (token.type.label == "{" && this.#stack.at(-1) === "{\n") ||
+ // Don't increment indent for empty array literals
+ (token.type.label == "[" && this.#stack.at(-1) === "[\n") ||
+ token.type.keyword == "switch" ||
+ (token.type.label == "(" && this.#stack.at(-1) === "(\n")
+ ) {
+ this.#indentLevel++;
+ }
+ }
+
+ #shouldDecrementIndent(token) {
+ const top = this.#stack.at(-1);
+ const ttl = token.type.label;
+ return (
+ (ttl == "}" && top == "{\n") ||
+ (ttl == "]" && top == "[\n") ||
+ (ttl == ")" && top == "(\n")
+ );
+ }
+
+ #maybeDecrementIndent(token) {
+ if (!this.#shouldDecrementIndent(token)) {
+ return;
+ }
+
+ const ttl = token.type.label;
+ this.#indentLevel--;
+ if (ttl == "}" && this.#stack.at(-2) == "switch") {
+ this.#indentLevel--;
+ }
+ }
+
+ /**
+ * Add a comment to the pretty printed code.
+ *
+ * @param Number indentLevel
+ * The number of indents deep we are (might be different from this.#indentLevel).
+ * @param Boolean block
+ * True if the comment is a multiline block style comment.
+ * @param String text
+ * The text of the comment.
+ * @param Number line
+ * The line number to comment appeared on.
+ * @param Object nextToken
+ * The next token if any.
+ */
+ #addComment(indentLevel, block, text, line, nextToken) {
+ const indentString = this.#indentChar.repeat(indentLevel);
+ const needNewLineAfter =
+ !block || !(nextToken && nextToken.loc.start.line == line);
+
+ if (block) {
+ const commentLinesText = text
+ .split(new RegExp(`/\n${indentString}/`, "g"))
+ .join(`\n${indentString}`);
+
+ this.#write(
+ `${indentString}/*${commentLinesText}*/${needNewLineAfter ? "\n" : " "}`
+ );
+ } else {
+ this.#write(`${indentString}//${text}\n`);
+ }
+
+ this.#addedNewline = needNewLineAfter;
+ this.#addedSpace = !needNewLineAfter;
+ }
+
+ /**
+ * Add the required whitespace before this token, whether that is a single
+ * space, newline, and/or the indent on fresh lines.
+ *
+ * @param Object token
+ * The token we are about to add to the pretty printed code.
+ */
+ #prependWhiteSpace(token) {
+ const ttk = token.type.keyword;
+ const ttl = token.type.label;
+ let newlineAdded = this.#addedNewline;
+ let spaceAdded = this.#addedSpace;
+ const ltt = this.#previousToken?.type?.label;
+
+ // Handle whitespace and newlines after "}" here instead of in
+ // `isLineDelimiter` because it is only a line delimiter some of the
+ // time. For example, we don't want to put "else if" on a new line after
+ // the first if's block.
+ if (this.#previousToken && ltt == "}") {
+ if (
+ (ttk == "while" && this.#stack.at(-1) == "do") ||
+ needsSpaceBeforeClosingCurlyBracket(ttk)
+ ) {
+ this.#write(" ");
+ spaceAdded = true;
+ } else if (needsLineBreakBeforeClosingCurlyBracket(ttl)) {
+ this.#write("\n");
+ newlineAdded = true;
+ }
+ }
+
+ if (
+ (ttl == ":" && this.#stack.at(-1) == "?") ||
+ (ttl == "}" && this.#stack.at(-1) == "${")
+ ) {
+ this.#write(" ");
+ spaceAdded = true;
+ }
+
+ if (this.#previousToken && ltt != "}" && ltt != "." && ttk == "else") {
+ this.#write(" ");
+ spaceAdded = true;
+ }
+
+ const ensureNewline = () => {
+ if (!newlineAdded) {
+ this.#write("\n");
+ newlineAdded = true;
+ }
+ };
+
+ if (isASI(token, this.#previousToken)) {
+ ensureNewline();
+ }
+
+ if (this.#shouldDecrementIndent(token)) {
+ ensureNewline();
+ }
+
+ if (newlineAdded) {
+ let indentLevel = this.#indentLevel;
+ if (ttk == "case" || ttk == "default") {
+ indentLevel--;
+ }
+ this.#write(this.#indentChar.repeat(indentLevel));
+ } else if (!spaceAdded && needsSpaceAfter(token, this.#previousToken)) {
+ this.#write(" ");
+ spaceAdded = true;
+ }
+ }
+
+ /**
+ * Append the necessary whitespace to the result after we have added the given
+ * token.
+ *
+ * @param Object token
+ * The token that was just added to the result.
+ */
+ #maybeAppendNewline(token) {
+ if (!isLineDelimiter(token, this.#stack)) {
+ this.#addedNewline = false;
+ return;
+ }
+
+ this.#write("\n");
+ this.#addedNewline = true;
+ }
+}
+
+/**
+ * Determines if we think that the given token starts an array literal.
+ *
+ * @param Object token
+ * The token we want to determine if it is an array literal.
+ * @param Object previousToken
+ * The previous token we added to the pretty printed results.
+ *
+ * @returns Boolean
+ * True if we believe it is an array literal, false otherwise.
+ */
+function isArrayLiteral(token, previousToken) {
+ if (token.type.label != "[") {
+ return false;
+ }
+ if (!previousToken) {
+ return true;
+ }
+ if (previousToken.type.isAssign) {
+ return true;
+ }
+
+ return PRE_ARRAY_LITERAL_TOKENS.has(
+ previousToken.type.keyword ||
+ // Some tokens ('of', 'yield', …) have a `token.type.keyword` of 'name' and their
+ // actual value in `token.value`
+ (previousToken.type.label == "name"
+ ? previousToken.value
+ : previousToken.type.label)
+ );
+}
+
+/**
+ * Determines if we think that the given token starts an object literal.
+ *
+ * @param Object token
+ * The token we want to determine if it is an object literal.
+ * @param Object previousToken
+ * The previous token we added to the pretty printed results.
+ *
+ * @returns Boolean
+ * True if we believe it is an object literal, false otherwise.
+ */
+function isObjectLiteral(token, previousToken) {
+ if (token.type.label != "{") {
+ return false;
+ }
+ if (!previousToken) {
+ return false;
+ }
+ if (previousToken.type.isAssign) {
+ return true;
+ }
+ return PRE_OBJECT_LITERAL_TOKENS.has(
+ previousToken.type.keyword || previousToken.type.label
+ );
+}
+
+/**
+ * Determines if we think that the given token starts a long parenthesis
+ *
+ * @param {Object} token
+ * The token we want to determine if it is the beginning of a long paren.
+ * @param {Array<Object>} tokenQueue
+ * The whole list of tokens parsed by acorn
+ * @param {Integer} currentTokenIndex
+ * The index of `token` in `tokenQueue`
+ * @returns
+ */
+function isRoundBracketStartingLongParenthesis(
+ token,
+ tokenQueue,
+ currentTokenIndex
+) {
+ if (token.type.label !== "(") {
+ return false;
+ }
+
+ // If we're just wrapping an object, we'll have a new line right after
+ if (tokenQueue[currentTokenIndex + 1].type.label == "{") {
+ return false;
+ }
+
+ // We're going to iterate through the following tokens until :
+ // - we find the closing parent
+ // - or we reached the maximum character we think should be in parenthesis
+ const longParentContentLength = 60;
+
+ // Keep track of other parens so we know when we get the closing one for `token`
+ let parenCount = 0;
+ let parenContentLength = 0;
+ for (let i = currentTokenIndex + 1, len = tokenQueue.length; i < len; i++) {
+ const currToken = tokenQueue[i];
+ const ttl = currToken.type.label;
+
+ if (ttl == "(") {
+ parenCount++;
+ } else if (ttl == ")") {
+ if (parenCount == 0) {
+ // Matching closing paren, if we got here, we didn't reach the length limit,
+ // as we return when parenContentLength is greater than the limit.
+ return false;
+ }
+ parenCount--;
+ }
+
+ // Aside block comments, all tokens start and end location are on the same line, so
+ // we can use `start` and `end` to deduce the token length.
+ const tokenLength = currToken.comment
+ ? currToken.text.length
+ : currToken.end - currToken.start;
+ parenContentLength += tokenLength;
+
+ // If we didn't find the matching closing paren yet and the characters from the
+ // tokens we evaluated so far are longer than the limit, so consider the token
+ // a long paren.
+ if (parenContentLength > longParentContentLength) {
+ return true;
+ }
+ }
+
+ // if we get to here, we didn't found a closing paren, which shouldn't happen
+ // (scripts with syntax error are not displayed in the debugger), but just to
+ // be safe, return false.
+ return false;
+}
+
+// If any of these tokens are followed by a token on a new line, we know that
+// ASI cannot happen.
+const PREVENT_ASI_AFTER_TOKENS = new Set([
+ // Binary operators
+ "*",
+ "/",
+ "%",
+ "+",
+ "-",
+ "<<",
+ ">>",
+ ">>>",
+ "<",
+ ">",
+ "<=",
+ ">=",
+ "instanceof",
+ "in",
+ "==",
+ "!=",
+ "===",
+ "!==",
+ "&",
+ "^",
+ "|",
+ "&&",
+ "||",
+ ",",
+ ".",
+ "=",
+ "*=",
+ "/=",
+ "%=",
+ "+=",
+ "-=",
+ "<<=",
+ ">>=",
+ ">>>=",
+ "&=",
+ "^=",
+ "|=",
+ // Unary operators
+ "delete",
+ "void",
+ "typeof",
+ "~",
+ "!",
+ "new",
+ // Function calls and grouped expressions
+ "(",
+]);
+
+// If any of these tokens are on a line after the token before it, we know
+// that ASI cannot happen.
+const PREVENT_ASI_BEFORE_TOKENS = new Set([
+ // Binary operators
+ "*",
+ "/",
+ "%",
+ "<<",
+ ">>",
+ ">>>",
+ "<",
+ ">",
+ "<=",
+ ">=",
+ "instanceof",
+ "in",
+ "==",
+ "!=",
+ "===",
+ "!==",
+ "&",
+ "^",
+ "|",
+ "&&",
+ "||",
+ ",",
+ ".",
+ "=",
+ "*=",
+ "/=",
+ "%=",
+ "+=",
+ "-=",
+ "<<=",
+ ">>=",
+ ">>>=",
+ "&=",
+ "^=",
+ "|=",
+ // Function calls
+ "(",
+]);
+
+/**
+ * Determine if a token can look like an identifier. More precisely,
+ * this determines if the token may end or start with a character from
+ * [A-Za-z0-9_].
+ *
+ * @param Object token
+ * The token we are looking at.
+ *
+ * @returns Boolean
+ * True if identifier-like.
+ */
+function isIdentifierLike(token) {
+ const ttl = token.type.label;
+ return (
+ ttl == "name" || ttl == "num" || ttl == "privateId" || !!token.type.keyword
+ );
+}
+
+/**
+ * Determines if Automatic Semicolon Insertion (ASI) occurs between these
+ * tokens.
+ *
+ * @param Object token
+ * The current token.
+ * @param Object previousToken
+ * The previous token we added to the pretty printed results.
+ *
+ * @returns Boolean
+ * True if we believe ASI occurs.
+ */
+function isASI(token, previousToken) {
+ if (!previousToken) {
+ return false;
+ }
+ if (token.loc.start.line === previousToken.loc.start.line) {
+ return false;
+ }
+ if (
+ previousToken.type.keyword == "return" ||
+ previousToken.type.keyword == "yield" ||
+ (previousToken.type.label == "name" && previousToken.value == "yield")
+ ) {
+ return true;
+ }
+ if (
+ PREVENT_ASI_AFTER_TOKENS.has(
+ previousToken.type.label || previousToken.type.keyword
+ )
+ ) {
+ return false;
+ }
+ if (PREVENT_ASI_BEFORE_TOKENS.has(token.type.label || token.type.keyword)) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Determine if we should add a newline after the given token.
+ *
+ * @param Object token
+ * The token we are looking at.
+ * @param Array stack
+ * The stack of open parens/curlies/brackets/etc.
+ *
+ * @returns Boolean
+ * True if we should add a newline.
+ */
+function isLineDelimiter(token, stack) {
+ const ttl = token.type.label;
+ const top = stack.at(-1);
+ return (
+ (ttl == ";" && top != "(") ||
+ // Don't add a new line for empty object literals
+ (ttl == "{" && top == "{\n") ||
+ // Don't add a new line for empty array literals
+ (ttl == "[" && top == "[\n") ||
+ ((ttl == "," || ttl == "||" || ttl == "&&") && top != "(") ||
+ (ttl == ":" && (top == "case" || top == "default")) ||
+ (ttl == "(" && top == "(\n")
+ );
+}
+
+/**
+ * Determines if we need to add a space after the token we are about to add.
+ *
+ * @param Object token
+ * The token we are about to add to the pretty printed code.
+ * @param Object [previousToken]
+ * Optional previous token added to the pretty printed code.
+ */
+function needsSpaceAfter(token, previousToken) {
+ if (previousToken && needsSpaceBetweenTokens(token, previousToken)) {
+ return true;
+ }
+
+ if (token.type.isAssign) {
+ return true;
+ }
+ if (token.type.binop != null && previousToken) {
+ return true;
+ }
+ if (token.type.label == "?") {
+ return true;
+ }
+ if (token.type.label == "=>") {
+ return true;
+ }
+
+ return false;
+}
+
+function needsSpaceBeforePreviousToken(previousToken) {
+ if (previousToken.type.isLoop) {
+ return true;
+ }
+ if (previousToken.type.isAssign) {
+ return true;
+ }
+ if (previousToken.type.binop != null) {
+ return true;
+ }
+ if (previousToken.value == "of") {
+ return true;
+ }
+
+ const previousTokenTypeLabel = previousToken.type.label;
+ if (previousTokenTypeLabel == "?") {
+ return true;
+ }
+ if (previousTokenTypeLabel == ":") {
+ return true;
+ }
+ if (previousTokenTypeLabel == ",") {
+ return true;
+ }
+ if (previousTokenTypeLabel == ";") {
+ return true;
+ }
+ if (previousTokenTypeLabel == "${") {
+ return true;
+ }
+ if (previousTokenTypeLabel == "=>") {
+ return true;
+ }
+ return false;
+}
+
+function isBreakContinueOrReturnStatement(previousTokenKeyword) {
+ return (
+ previousTokenKeyword == "break" ||
+ previousTokenKeyword == "continue" ||
+ previousTokenKeyword == "return"
+ );
+}
+
+function needsSpaceBeforePreviousTokenKeywordAfterNotDot(previousTokenKeyword) {
+ return (
+ previousTokenKeyword != "debugger" &&
+ previousTokenKeyword != "null" &&
+ previousTokenKeyword != "true" &&
+ previousTokenKeyword != "false" &&
+ previousTokenKeyword != "this" &&
+ previousTokenKeyword != "default"
+ );
+}
+
+function needsSpaceBeforeClosingParen(tokenTypeLabel) {
+ return (
+ tokenTypeLabel != ")" &&
+ tokenTypeLabel != "]" &&
+ tokenTypeLabel != ";" &&
+ tokenTypeLabel != "," &&
+ tokenTypeLabel != "."
+ );
+}
+
+/**
+ * Determines if we need to add a space between the previous token we added and
+ * the token we are about to add.
+ *
+ * @param Object token
+ * The token we are about to add to the pretty printed code.
+ * @param Object previousToken
+ * The previous token added to the pretty printed code.
+ */
+function needsSpaceBetweenTokens(token, previousToken) {
+ if (needsSpaceBeforePreviousToken(previousToken)) {
+ return true;
+ }
+
+ const ltt = previousToken.type.label;
+ if (ltt == "num" && token.type.label == ".") {
+ return true;
+ }
+
+ const ltk = previousToken.type.keyword;
+ const ttl = token.type.label;
+ if (ltk != null && ttl != ".") {
+ if (isBreakContinueOrReturnStatement(ltk)) {
+ return ttl != ";";
+ }
+ if (needsSpaceBeforePreviousTokenKeywordAfterNotDot(ltk)) {
+ return true;
+ }
+ }
+
+ if (ltt == ")" && needsSpaceBeforeClosingParen(ttl)) {
+ return true;
+ }
+
+ if (isIdentifierLike(token) && isIdentifierLike(previousToken)) {
+ // We must emit a space to avoid merging the tokens.
+ return true;
+ }
+
+ if (token.type.label == "{" && previousToken.type.label == "name") {
+ return true;
+ }
+
+ return false;
+}
+
+function needsSpaceBeforeClosingCurlyBracket(tokenTypeKeyword) {
+ return (
+ tokenTypeKeyword == "else" ||
+ tokenTypeKeyword == "catch" ||
+ tokenTypeKeyword == "finally"
+ );
+}
+
+function needsLineBreakBeforeClosingCurlyBracket(tokenTypeLabel) {
+ return (
+ tokenTypeLabel != "(" &&
+ tokenTypeLabel != ";" &&
+ tokenTypeLabel != "," &&
+ tokenTypeLabel != ")" &&
+ tokenTypeLabel != "." &&
+ tokenTypeLabel != "template" &&
+ tokenTypeLabel != "`"
+ );
+}
+
+const escapeCharacters = {
+ // Backslash
+ "\\": "\\\\",
+ // Newlines
+ "\n": "\\n",
+ // Carriage return
+ "\r": "\\r",
+ // Tab
+ "\t": "\\t",
+ // Vertical tab
+ "\v": "\\v",
+ // Form feed
+ "\f": "\\f",
+ // Null character
+ "\0": "\\x00",
+ // Line separator
+ "\u2028": "\\u2028",
+ // Paragraph separator
+ "\u2029": "\\u2029",
+ // Single quotes
+ "'": "\\'",
+};
+
+// eslint-disable-next-line prefer-template
+const regExpString = "(" + Object.values(escapeCharacters).join("|") + ")";
+const escapeCharactersRegExp = new RegExp(regExpString, "g");
+
+function sanitizerReplaceFunc(_, c) {
+ return escapeCharacters[c];
+}
+
+/**
+ * Make sure that we output the escaped character combination inside string
+ * literals instead of various problematic characters.
+ */
+function sanitize(str) {
+ return str.replace(escapeCharactersRegExp, sanitizerReplaceFunc);
+}
+
+/**
+ * Returns true if the given token type belongs on the stack.
+ */
+function belongsOnStack(token) {
+ const ttl = token.type.label;
+ const ttk = token.type.keyword;
+ return (
+ ttl == "{" ||
+ ttl == "(" ||
+ ttl == "[" ||
+ ttl == "?" ||
+ ttl == "${" ||
+ ttk == "do" ||
+ ttk == "switch" ||
+ ttk == "case" ||
+ ttk == "default"
+ );
+}
diff --git a/devtools/client/debugger/src/workers/pretty-print/tests/__snapshots__/prettyFast.spec.js.snap b/devtools/client/debugger/src/workers/pretty-print/tests/__snapshots__/prettyFast.spec.js.snap
new file mode 100644
index 0000000000..498bee267e
--- /dev/null
+++ b/devtools/client/debugger/src/workers/pretty-print/tests/__snapshots__/prettyFast.spec.js.snap
@@ -0,0 +1,1974 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ASI return 1`] = `
+"function f() {
+ return
+ {
+ }
+}
+"
+`;
+
+exports[`ASI return 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 9) -> (1, 9)",
+ "(1, 10) -> (1, 10)",
+ "(1, 11) -> (1, 11)",
+ "(1, 13) -> (1, 13)",
+ "(2, 2) -> (2, 13)",
+ "(3, 2) -> (3, 13)",
+ "(4, 2) -> (3, 14)",
+ "(5, 0) -> (4, 11)",
+]
+`;
+
+exports[`Arrays 1`] = `
+"var a = [
+ 1,
+ 2,
+ 3
+];
+"
+`;
+
+exports[`Arrays 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(2, 2) -> (1, 7)",
+ "(2, 3) -> (1, 8)",
+ "(3, 2) -> (1, 9)",
+ "(3, 3) -> (1, 10)",
+ "(4, 2) -> (1, 11)",
+ "(5, 0) -> (1, 12)",
+ "(5, 1) -> (1, 13)",
+]
+`;
+
+exports[`Arrays and spread operator 1`] = `
+"var a = [
+ 1,
+ ...[
+ 2,
+ 3
+ ],
+ ...[],
+ 4
+];
+"
+`;
+
+exports[`Arrays and spread operator 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(2, 2) -> (1, 7)",
+ "(2, 3) -> (1, 8)",
+ "(3, 2) -> (1, 9)",
+ "(3, 5) -> (1, 12)",
+ "(4, 4) -> (1, 13)",
+ "(4, 5) -> (1, 14)",
+ "(5, 4) -> (1, 15)",
+ "(6, 2) -> (1, 16)",
+ "(6, 3) -> (1, 17)",
+ "(7, 2) -> (1, 18)",
+ "(7, 5) -> (1, 21)",
+ "(7, 6) -> (1, 22)",
+ "(7, 7) -> (1, 23)",
+ "(8, 2) -> (1, 25)",
+ "(9, 0) -> (1, 26)",
+ "(9, 1) -> (1, 27)",
+]
+`;
+
+exports[`Binary operators 1`] = `
+"var a = 5 * 30;
+var b = 5 >> 3;
+"
+`;
+
+exports[`Binary operators 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(1, 10) -> (1, 7)",
+ "(1, 12) -> (1, 8)",
+ "(1, 14) -> (1, 10)",
+ "(2, 0) -> (1, 11)",
+ "(2, 4) -> (1, 15)",
+ "(2, 6) -> (1, 16)",
+ "(2, 8) -> (1, 17)",
+ "(2, 10) -> (1, 18)",
+ "(2, 13) -> (1, 20)",
+ "(2, 14) -> (1, 21)",
+]
+`;
+
+exports[`Bug 975477 don't move end of line comments to next line 1`] = `
+"switch (request.action) {
+ case 'show': //$NON-NLS-0$
+ if (localStorage.hideicon !== 'true') { //$NON-NLS-0$
+ chrome.pageAction.show(sender.tab.id);
+ }
+ break;
+ case 'hide': /*Multiline
+ Comment */
+ break;
+ default:
+ console.warn('unknown request'); //$NON-NLS-0$
+ // don't respond if you don't understand the message.
+ return;
+}
+"
+`;
+
+exports[`Bug 975477 don't move end of line comments to next line 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 7) -> (1, 7)",
+ "(1, 8) -> (1, 8)",
+ "(1, 15) -> (1, 15)",
+ "(1, 16) -> (1, 16)",
+ "(1, 22) -> (1, 22)",
+ "(1, 24) -> (1, 24)",
+ "(2, 2) -> (2, 13)",
+ "(2, 7) -> (2, 18)",
+ "(2, 13) -> (2, 24)",
+ "(3, 4) -> (3, 15)",
+ "(3, 7) -> (3, 18)",
+ "(3, 8) -> (3, 19)",
+ "(3, 20) -> (3, 31)",
+ "(3, 21) -> (3, 32)",
+ "(3, 30) -> (3, 41)",
+ "(3, 34) -> (3, 45)",
+ "(3, 40) -> (3, 51)",
+ "(3, 42) -> (3, 53)",
+ "(4, 6) -> (4, 17)",
+ "(4, 12) -> (4, 23)",
+ "(4, 13) -> (4, 24)",
+ "(4, 23) -> (4, 34)",
+ "(4, 24) -> (4, 35)",
+ "(4, 28) -> (4, 39)",
+ "(4, 29) -> (4, 40)",
+ "(4, 35) -> (4, 46)",
+ "(4, 36) -> (4, 47)",
+ "(4, 39) -> (4, 50)",
+ "(4, 40) -> (4, 51)",
+ "(4, 42) -> (4, 53)",
+ "(4, 43) -> (4, 54)",
+ "(5, 4) -> (5, 15)",
+ "(6, 4) -> (6, 15)",
+ "(6, 9) -> (6, 20)",
+ "(7, 2) -> (7, 13)",
+ "(7, 7) -> (7, 18)",
+ "(7, 13) -> (7, 24)",
+ "(9, 4) -> (9, 15)",
+ "(9, 9) -> (9, 20)",
+ "(10, 2) -> (10, 13)",
+ "(10, 9) -> (10, 20)",
+ "(11, 4) -> (11, 15)",
+ "(11, 11) -> (11, 22)",
+ "(11, 12) -> (11, 23)",
+ "(11, 16) -> (11, 27)",
+ "(11, 17) -> (11, 28)",
+ "(11, 34) -> (11, 45)",
+ "(11, 35) -> (11, 46)",
+ "(13, 4) -> (13, 15)",
+ "(13, 10) -> (13, 21)",
+ "(14, 0) -> (14, 11)",
+]
+`;
+
+exports[`Bug 977082 - space between grouping operator and dot notation 1`] = `
+"JSON.stringify(3).length;
+([1,
+2,
+3]).length;
+(new Date()).toLocaleString();
+"
+`;
+
+exports[`Bug 977082 - space between grouping operator and dot notation 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 5) -> (1, 5)",
+ "(1, 14) -> (1, 14)",
+ "(1, 15) -> (1, 15)",
+ "(1, 16) -> (1, 16)",
+ "(1, 17) -> (1, 17)",
+ "(1, 18) -> (1, 18)",
+ "(1, 24) -> (1, 24)",
+ "(2, 0) -> (2, 11)",
+ "(2, 1) -> (2, 12)",
+ "(2, 2) -> (2, 13)",
+ "(2, 3) -> (2, 14)",
+ "(3, 0) -> (2, 15)",
+ "(3, 1) -> (2, 16)",
+ "(4, 0) -> (2, 17)",
+ "(4, 1) -> (2, 18)",
+ "(4, 2) -> (2, 19)",
+ "(4, 3) -> (2, 20)",
+ "(4, 4) -> (2, 21)",
+ "(4, 10) -> (2, 27)",
+ "(5, 0) -> (3, 11)",
+ "(5, 1) -> (3, 12)",
+ "(5, 5) -> (3, 16)",
+ "(5, 9) -> (3, 20)",
+ "(5, 10) -> (3, 21)",
+ "(5, 11) -> (3, 22)",
+ "(5, 12) -> (3, 23)",
+ "(5, 13) -> (3, 24)",
+ "(5, 27) -> (3, 38)",
+ "(5, 28) -> (3, 39)",
+ "(5, 29) -> (3, 40)",
+]
+`;
+
+exports[`Bug 1206633 - spaces in for of 1`] = `
+"for (let tab of tabs) {
+}
+"
+`;
+
+exports[`Bug 1206633 - spaces in for of 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 5) -> (1, 5)",
+ "(1, 9) -> (1, 9)",
+ "(1, 13) -> (1, 13)",
+ "(1, 16) -> (1, 16)",
+ "(1, 20) -> (1, 20)",
+ "(1, 22) -> (1, 22)",
+ "(2, 0) -> (1, 23)",
+]
+`;
+
+exports[`Bug 1261971 - indentation after switch statement 1`] = `
+"{
+ switch (x) {
+ }
+ if (y) {
+ }
+ done();
+}
+"
+`;
+
+exports[`Bug 1261971 - indentation after switch statement 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(2, 2) -> (1, 1)",
+ "(2, 9) -> (1, 7)",
+ "(2, 10) -> (1, 8)",
+ "(2, 11) -> (1, 9)",
+ "(2, 13) -> (1, 10)",
+ "(3, 2) -> (1, 11)",
+ "(4, 2) -> (1, 12)",
+ "(4, 5) -> (1, 14)",
+ "(4, 6) -> (1, 15)",
+ "(4, 7) -> (1, 16)",
+ "(4, 9) -> (1, 17)",
+ "(5, 2) -> (1, 18)",
+ "(6, 2) -> (1, 19)",
+ "(6, 6) -> (1, 23)",
+ "(6, 7) -> (1, 24)",
+ "(6, 8) -> (1, 25)",
+ "(7, 0) -> (1, 26)",
+]
+`;
+
+exports[`Bug pretty-sure-3 - escaping line and paragraph separators 1`] = `
+"x = '\\\\u2029\\\\u2028';
+"
+`;
+
+exports[`Bug pretty-sure-3 - escaping line and paragraph separators 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 2) -> (1, 2)",
+ "(1, 4) -> (1, 4)",
+ "(1, 18) -> (1, 18)",
+]
+`;
+
+exports[`Bug pretty-sure-4 - escaping null character before digit 1`] = `
+"x = '\\\\x001';
+"
+`;
+
+exports[`Bug pretty-sure-4 - escaping null character before digit 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 2) -> (1, 2)",
+ "(1, 4) -> (1, 4)",
+ "(1, 11) -> (1, 13)",
+]
+`;
+
+exports[`Bug pretty-sure-5 - empty multiline comment shouldn't throw exception 1`] = `
+"{
+ /*
+ */
+ return;
+}
+"
+`;
+
+exports[`Bug pretty-sure-5 - empty multiline comment shouldn't throw exception 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(4, 2) -> (4, 13)",
+ "(4, 8) -> (4, 19)",
+ "(5, 0) -> (5, 11)",
+]
+`;
+
+exports[`Bug pretty-sure-6 - inline comment shouldn't move parenthesis to next line 1`] = `
+"return /* inline comment */ (1 + 1);
+"
+`;
+
+exports[`Bug pretty-sure-6 - inline comment shouldn't move parenthesis to next line 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 28) -> (1, 28)",
+ "(1, 29) -> (2, 13)",
+ "(1, 31) -> (2, 14)",
+ "(1, 33) -> (2, 15)",
+ "(1, 34) -> (2, 16)",
+ "(1, 35) -> (2, 17)",
+]
+`;
+
+exports[`Bug pretty-sure-7 - accessing a literal number property requires a space 1`] = `
+"0 .toString() + x.toString();
+"
+`;
+
+exports[`Bug pretty-sure-7 - accessing a literal number property requires a space 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 2) -> (1, 2)",
+ "(1, 3) -> (1, 3)",
+ "(1, 11) -> (1, 11)",
+ "(1, 12) -> (1, 12)",
+ "(1, 14) -> (1, 13)",
+ "(1, 16) -> (1, 14)",
+ "(1, 17) -> (1, 15)",
+ "(1, 18) -> (1, 16)",
+ "(1, 26) -> (1, 24)",
+ "(1, 27) -> (1, 25)",
+ "(1, 28) -> (1, 26)",
+]
+`;
+
+exports[`Bug pretty-sure-8 - return and yield only accept arguments when on the same line 1`] = `
+"{
+ return
+ (x)
+ yield
+ (x)
+ yield
+ * x
+}
+"
+`;
+
+exports[`Bug pretty-sure-8 - return and yield only accept arguments when on the same line 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(2, 2) -> (2, 13)",
+ "(3, 2) -> (3, 13)",
+ "(3, 3) -> (3, 14)",
+ "(3, 4) -> (3, 15)",
+ "(4, 2) -> (4, 13)",
+ "(5, 2) -> (5, 13)",
+ "(5, 3) -> (5, 14)",
+ "(5, 4) -> (5, 15)",
+ "(6, 2) -> (6, 13)",
+ "(7, 2) -> (7, 13)",
+ "(7, 4) -> (7, 14)",
+ "(8, 0) -> (8, 11)",
+]
+`;
+
+exports[`Bug pretty-sure-9 - accept unary operator at start of file 1`] = `
+"+ 0
+"
+`;
+
+exports[`Bug pretty-sure-9 - accept unary operator at start of file 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 2) -> (1, 2)",
+]
+`;
+
+exports[`Class extension within a function 1`] = `
+"(function () {
+ class X extends Y {
+ constructor() {
+ }
+ }
+}) ()
+"
+`;
+
+exports[`Class extension within a function 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 1) -> (1, 1)",
+ "(1, 10) -> (1, 9)",
+ "(1, 11) -> (1, 10)",
+ "(1, 13) -> (1, 12)",
+ "(2, 2) -> (1, 15)",
+ "(2, 8) -> (1, 21)",
+ "(2, 10) -> (1, 23)",
+ "(2, 18) -> (1, 31)",
+ "(2, 20) -> (1, 33)",
+ "(3, 4) -> (1, 35)",
+ "(3, 15) -> (1, 46)",
+ "(3, 16) -> (1, 47)",
+ "(3, 18) -> (1, 49)",
+ "(4, 4) -> (1, 50)",
+ "(5, 2) -> (1, 52)",
+ "(6, 0) -> (1, 55)",
+ "(6, 1) -> (1, 56)",
+ "(6, 3) -> (1, 57)",
+ "(6, 4) -> (1, 58)",
+]
+`;
+
+exports[`Class handling 1`] = `
+"class Class {
+ constructor() {
+ }
+}
+"
+`;
+
+exports[`Class handling 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 6) -> (1, 7)",
+ "(1, 12) -> (1, 12)",
+ "(2, 2) -> (1, 13)",
+ "(2, 13) -> (1, 24)",
+ "(2, 14) -> (1, 25)",
+ "(2, 16) -> (1, 26)",
+ "(3, 2) -> (1, 27)",
+ "(4, 0) -> (1, 28)",
+]
+`;
+
+exports[`Code that relies on ASI 1`] = `
+"var foo = 10
+var bar = 20
+function g() {
+ a()
+ b()
+}
+"
+`;
+
+exports[`Code that relies on ASI 2`] = `
+Array [
+ "(1, 0) -> (2, 11)",
+ "(1, 4) -> (2, 15)",
+ "(1, 8) -> (2, 19)",
+ "(1, 10) -> (2, 21)",
+ "(2, 0) -> (3, 11)",
+ "(2, 4) -> (3, 15)",
+ "(2, 8) -> (3, 19)",
+ "(2, 10) -> (3, 21)",
+ "(3, 0) -> (4, 11)",
+ "(3, 9) -> (4, 20)",
+ "(3, 10) -> (4, 21)",
+ "(3, 11) -> (4, 22)",
+ "(3, 13) -> (4, 24)",
+ "(4, 2) -> (5, 13)",
+ "(4, 3) -> (5, 14)",
+ "(4, 4) -> (5, 15)",
+ "(5, 2) -> (6, 13)",
+ "(5, 3) -> (6, 14)",
+ "(5, 4) -> (6, 15)",
+ "(6, 0) -> (7, 11)",
+]
+`;
+
+exports[`Const handling 1`] = `
+"const d = 'yes';
+"
+`;
+
+exports[`Const handling 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 6) -> (1, 6)",
+ "(1, 8) -> (1, 8)",
+ "(1, 10) -> (1, 10)",
+ "(1, 15) -> (1, 15)",
+]
+`;
+
+exports[`Continue/break statements 1`] = `
+"while (1) {
+ if (x) {
+ continue
+ }
+ if (y) {
+ break
+ }
+ if (z) {
+ break foo
+ }
+}
+"
+`;
+
+exports[`Continue/break statements 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 6) -> (1, 5)",
+ "(1, 7) -> (1, 6)",
+ "(1, 8) -> (1, 7)",
+ "(1, 10) -> (1, 8)",
+ "(2, 2) -> (1, 9)",
+ "(2, 5) -> (1, 11)",
+ "(2, 6) -> (1, 12)",
+ "(2, 7) -> (1, 13)",
+ "(2, 9) -> (1, 14)",
+ "(3, 4) -> (1, 15)",
+ "(4, 2) -> (1, 23)",
+ "(5, 2) -> (1, 24)",
+ "(5, 5) -> (1, 26)",
+ "(5, 6) -> (1, 27)",
+ "(5, 7) -> (1, 28)",
+ "(5, 9) -> (1, 29)",
+ "(6, 4) -> (1, 30)",
+ "(7, 2) -> (1, 35)",
+ "(8, 2) -> (1, 36)",
+ "(8, 5) -> (1, 38)",
+ "(8, 6) -> (1, 39)",
+ "(8, 7) -> (1, 40)",
+ "(8, 9) -> (1, 41)",
+ "(9, 4) -> (1, 42)",
+ "(9, 10) -> (1, 48)",
+ "(10, 2) -> (1, 51)",
+ "(11, 0) -> (1, 52)",
+]
+`;
+
+exports[`Delete 1`] = `
+"delete obj.prop;
+"
+`;
+
+exports[`Delete 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 7) -> (1, 7)",
+ "(1, 10) -> (1, 10)",
+ "(1, 11) -> (1, 11)",
+ "(1, 15) -> (1, 15)",
+]
+`;
+
+exports[`Do/while loop 1`] = `
+"do {
+ x
+} while (y)
+"
+`;
+
+exports[`Do/while loop 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 3) -> (1, 2)",
+ "(2, 2) -> (1, 3)",
+ "(3, 0) -> (1, 4)",
+ "(3, 2) -> (1, 5)",
+ "(3, 8) -> (1, 10)",
+ "(3, 9) -> (1, 11)",
+ "(3, 10) -> (1, 12)",
+]
+`;
+
+exports[`Dot handling with keywords which are identifier name 1`] = `
+"y.await.break.const.delete.else.return.new.yield = 1.23;
+"
+`;
+
+exports[`Dot handling with keywords which are identifier name 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 1) -> (1, 1)",
+ "(1, 2) -> (1, 2)",
+ "(1, 7) -> (1, 7)",
+ "(1, 8) -> (1, 8)",
+ "(1, 13) -> (1, 13)",
+ "(1, 14) -> (1, 14)",
+ "(1, 19) -> (1, 19)",
+ "(1, 20) -> (1, 20)",
+ "(1, 26) -> (1, 26)",
+ "(1, 27) -> (1, 27)",
+ "(1, 31) -> (1, 31)",
+ "(1, 32) -> (1, 32)",
+ "(1, 38) -> (1, 38)",
+ "(1, 39) -> (1, 39)",
+ "(1, 42) -> (1, 42)",
+ "(1, 43) -> (1, 43)",
+ "(1, 49) -> (1, 49)",
+ "(1, 51) -> (1, 51)",
+ "(1, 55) -> (1, 55)",
+]
+`;
+
+exports[`Dot handling with let which is identifier name 1`] = `
+"y.let.let = 1.23;
+"
+`;
+
+exports[`Dot handling with let which is identifier name 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 1) -> (1, 1)",
+ "(1, 2) -> (1, 2)",
+ "(1, 5) -> (1, 5)",
+ "(1, 6) -> (1, 6)",
+ "(1, 10) -> (1, 10)",
+ "(1, 12) -> (1, 12)",
+ "(1, 16) -> (1, 16)",
+]
+`;
+
+exports[`Empty object/array literals 1`] = `
+"let a = [];
+const b = {};
+c = {
+ ...{},
+ d: 42
+};
+for (let x of []) {
+ for (let y in {}) {
+ }
+}
+"
+`;
+
+exports[`Empty object/array literals 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(1, 9) -> (1, 7)",
+ "(1, 10) -> (1, 8)",
+ "(2, 0) -> (1, 9)",
+ "(2, 6) -> (1, 15)",
+ "(2, 8) -> (1, 16)",
+ "(2, 10) -> (1, 17)",
+ "(2, 11) -> (1, 18)",
+ "(2, 12) -> (1, 19)",
+ "(3, 0) -> (1, 20)",
+ "(3, 2) -> (1, 21)",
+ "(3, 4) -> (1, 22)",
+ "(4, 2) -> (1, 23)",
+ "(4, 5) -> (1, 26)",
+ "(4, 6) -> (1, 27)",
+ "(4, 7) -> (1, 28)",
+ "(5, 2) -> (1, 29)",
+ "(5, 3) -> (1, 30)",
+ "(5, 5) -> (1, 32)",
+ "(6, 0) -> (1, 34)",
+ "(6, 1) -> (1, 35)",
+ "(7, 0) -> (1, 36)",
+ "(7, 4) -> (1, 39)",
+ "(7, 5) -> (1, 40)",
+ "(7, 9) -> (1, 44)",
+ "(7, 11) -> (1, 46)",
+ "(7, 14) -> (1, 49)",
+ "(7, 15) -> (1, 50)",
+ "(7, 16) -> (1, 51)",
+ "(7, 18) -> (1, 52)",
+ "(8, 2) -> (1, 53)",
+ "(8, 6) -> (1, 56)",
+ "(8, 7) -> (1, 57)",
+ "(8, 11) -> (1, 61)",
+ "(8, 13) -> (1, 63)",
+ "(8, 16) -> (1, 66)",
+ "(8, 17) -> (1, 67)",
+ "(8, 18) -> (1, 68)",
+ "(8, 20) -> (1, 69)",
+ "(9, 2) -> (1, 70)",
+ "(10, 0) -> (1, 71)",
+]
+`;
+
+exports[`Escaping backslashes in strings 1`] = `
+"'\\\\\\\\'
+"
+`;
+
+exports[`Escaping backslashes in strings 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+]
+`;
+
+exports[`Escaping carriage return in strings 1`] = `
+"'\\\\r'
+"
+`;
+
+exports[`Escaping carriage return in strings 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+]
+`;
+
+exports[`Escaping form feed in strings 1`] = `
+"'\\\\f'
+"
+`;
+
+exports[`Escaping form feed in strings 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+]
+`;
+
+exports[`Escaping null character in strings 1`] = `
+"'\\\\x00'
+"
+`;
+
+exports[`Escaping null character in strings 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+]
+`;
+
+exports[`Escaping tab in strings 1`] = `
+"'\\\\t'
+"
+`;
+
+exports[`Escaping tab in strings 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+]
+`;
+
+exports[`Escaping vertical tab in strings 1`] = `
+"'\\\\v'
+"
+`;
+
+exports[`Escaping vertical tab in strings 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+]
+`;
+
+exports[`False assignment 1`] = `
+"var foo = false;
+"
+`;
+
+exports[`False assignment 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 8) -> (1, 7)",
+ "(1, 10) -> (1, 8)",
+ "(1, 15) -> (1, 13)",
+]
+`;
+
+exports[`Fat arrow function 1`] = `
+"const a = () => 42
+addEventListener('click', e => {
+ return false
+});
+const sum = (c, d) => c + d
+"
+`;
+
+exports[`Fat arrow function 2`] = `
+Array [
+ "(1, 0) -> (2, 6)",
+ "(1, 6) -> (2, 12)",
+ "(1, 8) -> (2, 14)",
+ "(1, 10) -> (2, 16)",
+ "(1, 11) -> (2, 17)",
+ "(1, 13) -> (2, 19)",
+ "(1, 16) -> (2, 22)",
+ "(2, 0) -> (3, 6)",
+ "(2, 16) -> (3, 22)",
+ "(2, 17) -> (3, 23)",
+ "(2, 24) -> (3, 30)",
+ "(2, 26) -> (3, 32)",
+ "(2, 28) -> (3, 34)",
+ "(2, 31) -> (3, 37)",
+ "(3, 2) -> (3, 39)",
+ "(3, 9) -> (3, 46)",
+ "(4, 0) -> (3, 52)",
+ "(4, 1) -> (3, 53)",
+ "(4, 2) -> (3, 54)",
+ "(5, 0) -> (4, 6)",
+ "(5, 6) -> (4, 12)",
+ "(5, 10) -> (4, 16)",
+ "(5, 12) -> (4, 18)",
+ "(5, 13) -> (4, 19)",
+ "(5, 14) -> (4, 20)",
+ "(5, 16) -> (4, 21)",
+ "(5, 17) -> (4, 22)",
+ "(5, 19) -> (4, 24)",
+ "(5, 22) -> (4, 27)",
+ "(5, 24) -> (4, 28)",
+ "(5, 26) -> (4, 29)",
+]
+`;
+
+exports[`For loop 1`] = `
+"for (var i = 0; i < n; i++) {
+ console.log(i);
+}
+"
+`;
+
+exports[`For loop 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 5) -> (1, 5)",
+ "(1, 9) -> (1, 9)",
+ "(1, 11) -> (1, 11)",
+ "(1, 13) -> (1, 13)",
+ "(1, 14) -> (1, 14)",
+ "(1, 16) -> (1, 16)",
+ "(1, 18) -> (1, 18)",
+ "(1, 20) -> (1, 20)",
+ "(1, 21) -> (1, 21)",
+ "(1, 23) -> (1, 23)",
+ "(1, 24) -> (1, 24)",
+ "(1, 26) -> (1, 26)",
+ "(1, 28) -> (1, 28)",
+ "(2, 2) -> (1, 30)",
+ "(2, 9) -> (1, 37)",
+ "(2, 10) -> (1, 38)",
+ "(2, 13) -> (1, 41)",
+ "(2, 14) -> (1, 42)",
+ "(2, 15) -> (1, 43)",
+ "(2, 16) -> (1, 44)",
+ "(3, 0) -> (1, 46)",
+]
+`;
+
+exports[`Function calls 1`] = `
+"var result = func(a, b, c, d);
+"
+`;
+
+exports[`Function calls 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 11) -> (1, 10)",
+ "(1, 13) -> (1, 11)",
+ "(1, 17) -> (1, 15)",
+ "(1, 18) -> (1, 16)",
+ "(1, 19) -> (1, 17)",
+ "(1, 21) -> (1, 18)",
+ "(1, 22) -> (1, 19)",
+ "(1, 24) -> (1, 20)",
+ "(1, 25) -> (1, 21)",
+ "(1, 27) -> (1, 22)",
+ "(1, 28) -> (1, 23)",
+ "(1, 29) -> (1, 24)",
+]
+`;
+
+exports[`Getter and setter literals 1`] = `
+"var obj = {
+ get foo() {
+ return this._foo
+ },
+ set foo(v) {
+ this._foo = v
+ }
+}
+"
+`;
+
+exports[`Getter and setter literals 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 8) -> (1, 7)",
+ "(1, 10) -> (1, 8)",
+ "(2, 2) -> (1, 9)",
+ "(2, 6) -> (1, 13)",
+ "(2, 9) -> (1, 16)",
+ "(2, 10) -> (1, 17)",
+ "(2, 12) -> (1, 18)",
+ "(3, 4) -> (1, 19)",
+ "(3, 11) -> (1, 26)",
+ "(3, 15) -> (1, 30)",
+ "(3, 16) -> (1, 31)",
+ "(4, 2) -> (1, 35)",
+ "(4, 3) -> (1, 36)",
+ "(5, 2) -> (1, 37)",
+ "(5, 6) -> (1, 41)",
+ "(5, 9) -> (1, 44)",
+ "(5, 10) -> (1, 45)",
+ "(5, 11) -> (1, 46)",
+ "(5, 13) -> (1, 47)",
+ "(6, 4) -> (1, 48)",
+ "(6, 8) -> (1, 52)",
+ "(6, 9) -> (1, 53)",
+ "(6, 14) -> (1, 57)",
+ "(6, 16) -> (1, 58)",
+ "(7, 2) -> (1, 59)",
+ "(8, 0) -> (1, 60)",
+]
+`;
+
+exports[`If/else statement 1`] = `
+"if (c) {
+ then()
+} else {
+ other()
+}
+"
+`;
+
+exports[`If/else statement 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 3) -> (1, 2)",
+ "(1, 4) -> (1, 3)",
+ "(1, 5) -> (1, 4)",
+ "(1, 7) -> (1, 5)",
+ "(2, 2) -> (1, 6)",
+ "(2, 6) -> (1, 10)",
+ "(2, 7) -> (1, 11)",
+ "(3, 0) -> (1, 12)",
+ "(3, 2) -> (1, 13)",
+ "(3, 7) -> (1, 17)",
+ "(4, 2) -> (1, 18)",
+ "(4, 7) -> (1, 23)",
+ "(4, 8) -> (1, 24)",
+ "(5, 0) -> (1, 25)",
+]
+`;
+
+exports[`If/else without curlies 1`] = `
+"if (c) a else b
+"
+`;
+
+exports[`If/else without curlies 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 3) -> (1, 2)",
+ "(1, 4) -> (1, 3)",
+ "(1, 5) -> (1, 4)",
+ "(1, 7) -> (1, 6)",
+ "(1, 9) -> (1, 8)",
+ "(1, 14) -> (1, 13)",
+]
+`;
+
+exports[`Immediately invoked function expression 1`] = `
+"(function () {
+ thingy()
+}())
+"
+`;
+
+exports[`Immediately invoked function expression 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 1) -> (1, 1)",
+ "(1, 10) -> (1, 9)",
+ "(1, 11) -> (1, 10)",
+ "(1, 13) -> (1, 11)",
+ "(2, 2) -> (1, 12)",
+ "(2, 8) -> (1, 18)",
+ "(2, 9) -> (1, 19)",
+ "(3, 0) -> (1, 20)",
+ "(3, 1) -> (1, 21)",
+ "(3, 2) -> (1, 22)",
+ "(3, 3) -> (1, 23)",
+]
+`;
+
+exports[`In operator 1`] = `
+"if (foo in bar) {
+ doThing()
+}
+"
+`;
+
+exports[`In operator 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 3) -> (1, 2)",
+ "(1, 4) -> (1, 3)",
+ "(1, 8) -> (1, 7)",
+ "(1, 11) -> (1, 10)",
+ "(1, 14) -> (1, 13)",
+ "(1, 16) -> (1, 14)",
+ "(2, 2) -> (1, 15)",
+ "(2, 9) -> (1, 22)",
+ "(2, 10) -> (1, 23)",
+ "(3, 0) -> (1, 24)",
+]
+`;
+
+exports[`Indented multiline comment 1`] = `
+"function foo() {
+ /**
+ * java doc style comment
+ * more comment
+ */
+ bar();
+}
+"
+`;
+
+exports[`Indented multiline comment 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 9) -> (1, 9)",
+ "(1, 12) -> (1, 12)",
+ "(1, 13) -> (1, 13)",
+ "(1, 15) -> (1, 15)",
+ "(6, 2) -> (6, 13)",
+ "(6, 5) -> (6, 16)",
+ "(6, 6) -> (6, 17)",
+ "(6, 7) -> (6, 18)",
+ "(7, 0) -> (7, 11)",
+]
+`;
+
+exports[`Instanceof 1`] = `
+"var a = x instanceof y;
+"
+`;
+
+exports[`Instanceof 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(1, 10) -> (1, 8)",
+ "(1, 21) -> (1, 19)",
+ "(1, 22) -> (1, 20)",
+]
+`;
+
+exports[`Let handling with value 1`] = `
+"let d = 'yes';
+"
+`;
+
+exports[`Let handling with value 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 6)",
+ "(1, 8) -> (1, 8)",
+ "(1, 13) -> (1, 13)",
+]
+`;
+
+exports[`Let handling without value 1`] = `
+"let d;
+"
+`;
+
+exports[`Let handling without value 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 5) -> (1, 5)",
+]
+`;
+
+exports[`Long parenthesis 1`] = `
+"if (
+ thisIsAVeryLongVariable &&
+ thisIsAnotherOne ||
+ yetAnotherVeryLongVariable
+) {
+ (
+ thisIsAnotherOne = thisMayReturnNull() ||
+ 'hi',
+ thisIsAVeryLongVariable = 42,
+ yetAnotherVeryLongVariable &&
+ doSomething(
+ true /* do it well */ ,
+ thisIsAVeryLongVariable,
+ thisIsAnotherOne,
+ yetAnotherVeryLongVariable
+ )
+ )
+}
+for (
+ let thisIsAnotherVeryLongVariable = 0;
+ i < thisIsAnotherVeryLongVariable.length;
+ thisIsAnotherVeryLongVariable++
+) {
+}
+const x = ({
+ thisIsAnotherVeryLongPropertyName: 'but should not cause the paren to be a line delimiter'
+})
+"
+`;
+
+exports[`Long parenthesis 2`] = `
+Array [
+ "(1, 0) -> (2, 6)",
+ "(1, 3) -> (2, 9)",
+ "(2, 2) -> (2, 10)",
+ "(2, 26) -> (2, 34)",
+ "(3, 2) -> (2, 37)",
+ "(3, 19) -> (2, 54)",
+ "(4, 2) -> (2, 57)",
+ "(5, 0) -> (2, 83)",
+ "(5, 2) -> (2, 85)",
+ "(6, 2) -> (3, 8)",
+ "(7, 4) -> (3, 9)",
+ "(7, 21) -> (3, 26)",
+ "(7, 23) -> (3, 28)",
+ "(7, 40) -> (3, 45)",
+ "(7, 41) -> (3, 46)",
+ "(7, 43) -> (3, 48)",
+ "(8, 4) -> (3, 51)",
+ "(8, 8) -> (3, 55)",
+ "(9, 4) -> (3, 57)",
+ "(9, 28) -> (3, 81)",
+ "(9, 30) -> (3, 83)",
+ "(9, 32) -> (3, 85)",
+ "(10, 4) -> (3, 87)",
+ "(10, 31) -> (3, 114)",
+ "(11, 4) -> (3, 117)",
+ "(11, 15) -> (3, 128)",
+ "(12, 6) -> (3, 129)",
+ "(12, 28) -> (3, 150)",
+ "(13, 6) -> (3, 151)",
+ "(13, 29) -> (3, 174)",
+ "(14, 6) -> (3, 176)",
+ "(14, 22) -> (3, 192)",
+ "(15, 6) -> (3, 194)",
+ "(16, 4) -> (3, 220)",
+ "(17, 2) -> (3, 221)",
+ "(18, 0) -> (4, 6)",
+ "(19, 0) -> (5, 6)",
+ "(19, 4) -> (5, 10)",
+ "(20, 2) -> (5, 11)",
+ "(20, 6) -> (5, 15)",
+ "(20, 36) -> (5, 45)",
+ "(20, 38) -> (5, 47)",
+ "(20, 39) -> (5, 48)",
+ "(21, 2) -> (5, 50)",
+ "(21, 4) -> (5, 52)",
+ "(21, 6) -> (5, 54)",
+ "(21, 35) -> (5, 83)",
+ "(21, 36) -> (5, 84)",
+ "(21, 42) -> (5, 90)",
+ "(22, 2) -> (5, 92)",
+ "(22, 31) -> (5, 121)",
+ "(23, 0) -> (5, 123)",
+ "(23, 2) -> (5, 125)",
+ "(24, 0) -> (5, 126)",
+ "(25, 0) -> (6, 6)",
+ "(25, 6) -> (6, 12)",
+ "(25, 8) -> (6, 14)",
+ "(25, 10) -> (6, 16)",
+ "(25, 11) -> (6, 17)",
+ "(26, 2) -> (6, 18)",
+ "(26, 35) -> (6, 51)",
+ "(26, 37) -> (6, 53)",
+ "(27, 0) -> (6, 108)",
+ "(27, 1) -> (6, 109)",
+]
+`;
+
+exports[`Multi line comment 1`] = `
+"/* Comment
+ more comment */
+function foo() {
+ bar();
+}
+"
+`;
+
+exports[`Multi line comment 2`] = `
+Array [
+ "(3, 0) -> (4, 4)",
+ "(3, 9) -> (4, 13)",
+ "(3, 12) -> (4, 16)",
+ "(3, 13) -> (4, 17)",
+ "(3, 15) -> (4, 19)",
+ "(4, 2) -> (4, 21)",
+ "(4, 5) -> (4, 24)",
+ "(4, 6) -> (4, 25)",
+ "(4, 7) -> (4, 26)",
+ "(5, 0) -> (4, 28)",
+]
+`;
+
+exports[`Multiple single line comments 1`] = `
+"function f() {
+ // a
+ // b
+ // c
+}
+"
+`;
+
+exports[`Multiple single line comments 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 9) -> (1, 9)",
+ "(1, 10) -> (1, 10)",
+ "(1, 11) -> (1, 11)",
+ "(1, 13) -> (1, 13)",
+ "(5, 0) -> (5, 11)",
+]
+`;
+
+exports[`Named class handling 1`] = `
+"let unnamed = class Class {
+ constructor() {
+ }
+}
+"
+`;
+
+exports[`Named class handling 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 12) -> (1, 11)",
+ "(1, 14) -> (1, 12)",
+ "(1, 20) -> (1, 18)",
+ "(1, 26) -> (1, 23)",
+ "(2, 2) -> (1, 24)",
+ "(2, 13) -> (1, 35)",
+ "(2, 14) -> (1, 36)",
+ "(2, 16) -> (1, 37)",
+ "(3, 2) -> (1, 38)",
+ "(4, 0) -> (1, 39)",
+]
+`;
+
+exports[`Nested function 1`] = `
+"function foo() {
+ function bar() {
+ debugger;
+ }
+ bar();
+}
+"
+`;
+
+exports[`Nested function 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 9) -> (1, 9)",
+ "(1, 12) -> (1, 12)",
+ "(1, 13) -> (1, 13)",
+ "(1, 15) -> (1, 15)",
+ "(2, 2) -> (1, 17)",
+ "(2, 11) -> (1, 26)",
+ "(2, 14) -> (1, 29)",
+ "(2, 15) -> (1, 30)",
+ "(2, 17) -> (1, 32)",
+ "(3, 4) -> (1, 34)",
+ "(3, 12) -> (1, 42)",
+ "(4, 2) -> (1, 44)",
+ "(5, 2) -> (1, 46)",
+ "(5, 5) -> (1, 49)",
+ "(5, 6) -> (1, 50)",
+ "(5, 7) -> (1, 51)",
+ "(6, 0) -> (1, 53)",
+]
+`;
+
+exports[`New expression 1`] = `
+"var foo = new Foo();
+"
+`;
+
+exports[`New expression 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 8) -> (1, 7)",
+ "(1, 10) -> (1, 8)",
+ "(1, 14) -> (1, 12)",
+ "(1, 17) -> (1, 15)",
+ "(1, 18) -> (1, 16)",
+ "(1, 19) -> (1, 17)",
+]
+`;
+
+exports[`Non-ASI function call 1`] = `
+"f()
+"
+`;
+
+exports[`Non-ASI function call 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 1) -> (2, 11)",
+ "(1, 2) -> (2, 12)",
+]
+`;
+
+exports[`Non-ASI in 1`] = `
+"'x' in foo
+"
+`;
+
+exports[`Non-ASI in 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (2, 11)",
+ "(1, 7) -> (2, 14)",
+]
+`;
+
+exports[`Non-ASI new 1`] = `
+"new F()
+"
+`;
+
+exports[`Non-ASI new 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (2, 11)",
+ "(1, 5) -> (2, 12)",
+ "(1, 6) -> (2, 13)",
+]
+`;
+
+exports[`Non-ASI property access 1`] = `
+"[
+ 1,
+ 2,
+ 3
+]
+[0]
+"
+`;
+
+exports[`Non-ASI property access 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(2, 2) -> (1, 1)",
+ "(2, 3) -> (1, 2)",
+ "(3, 2) -> (1, 3)",
+ "(3, 3) -> (1, 4)",
+ "(4, 2) -> (1, 5)",
+ "(5, 0) -> (1, 6)",
+ "(6, 0) -> (2, 11)",
+ "(6, 1) -> (2, 12)",
+ "(6, 2) -> (2, 13)",
+]
+`;
+
+exports[`Null assignment 1`] = `
+"var i = null;
+"
+`;
+
+exports[`Null assignment 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(1, 12) -> (1, 10)",
+]
+`;
+
+exports[`Objects 1`] = `
+"var o = {
+ a: 1,
+ b: 2
+};
+"
+`;
+
+exports[`Objects 2`] = `
+Array [
+ "(1, 0) -> (2, 6)",
+ "(1, 4) -> (2, 10)",
+ "(1, 6) -> (2, 11)",
+ "(1, 8) -> (2, 12)",
+ "(2, 2) -> (2, 13)",
+ "(2, 3) -> (2, 14)",
+ "(2, 5) -> (2, 15)",
+ "(2, 6) -> (2, 16)",
+ "(3, 2) -> (3, 6)",
+ "(3, 3) -> (3, 7)",
+ "(3, 5) -> (3, 8)",
+ "(4, 0) -> (3, 9)",
+ "(4, 1) -> (3, 10)",
+]
+`;
+
+exports[`Optional chaining parsing support 1`] = `
+"x?.y?.z?.['a']?.check();
+"
+`;
+
+exports[`Optional chaining parsing support 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 1) -> (1, 1)",
+ "(1, 3) -> (1, 3)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 6)",
+ "(1, 7) -> (1, 7)",
+ "(1, 9) -> (1, 9)",
+ "(1, 10) -> (1, 10)",
+ "(1, 13) -> (1, 13)",
+ "(1, 14) -> (1, 14)",
+ "(1, 16) -> (1, 16)",
+ "(1, 21) -> (1, 21)",
+ "(1, 22) -> (1, 22)",
+ "(1, 23) -> (1, 23)",
+]
+`;
+
+exports[`Private fields parsing support 1`] = `
+"class MyClass {
+ constructor(a) {
+ this.#a = a;
+ this.#b = Math.random();
+ this.ab = this.#getAB();
+ }
+ #a
+ #b = 'default value'
+ static #someStaticPrivate
+ #getA() {
+ return this.#a;
+ }
+ #getAB() {
+ return this.#getA() + this.#b
+ }
+}
+"
+`;
+
+exports[`Private fields parsing support 2`] = `
+Array [
+ "(1, 0) -> (2, 6)",
+ "(1, 6) -> (2, 12)",
+ "(1, 14) -> (2, 20)",
+ "(2, 2) -> (3, 8)",
+ "(2, 13) -> (3, 19)",
+ "(2, 14) -> (3, 20)",
+ "(2, 15) -> (3, 21)",
+ "(2, 17) -> (3, 23)",
+ "(3, 4) -> (4, 10)",
+ "(3, 8) -> (4, 14)",
+ "(3, 9) -> (4, 15)",
+ "(3, 12) -> (4, 18)",
+ "(3, 14) -> (4, 20)",
+ "(3, 15) -> (4, 21)",
+ "(4, 4) -> (4, 22)",
+ "(4, 8) -> (4, 26)",
+ "(4, 9) -> (4, 27)",
+ "(4, 12) -> (4, 30)",
+ "(4, 14) -> (4, 32)",
+ "(4, 18) -> (4, 36)",
+ "(4, 19) -> (4, 37)",
+ "(4, 25) -> (4, 43)",
+ "(4, 26) -> (4, 44)",
+ "(4, 27) -> (4, 45)",
+ "(5, 4) -> (4, 46)",
+ "(5, 8) -> (4, 50)",
+ "(5, 9) -> (4, 51)",
+ "(5, 12) -> (4, 54)",
+ "(5, 14) -> (4, 56)",
+ "(5, 18) -> (4, 60)",
+ "(5, 19) -> (4, 61)",
+ "(5, 25) -> (4, 67)",
+ "(5, 26) -> (4, 68)",
+ "(5, 27) -> (4, 69)",
+ "(6, 2) -> (5, 8)",
+ "(7, 2) -> (6, 8)",
+ "(8, 2) -> (7, 8)",
+ "(8, 5) -> (7, 11)",
+ "(8, 7) -> (7, 13)",
+ "(9, 2) -> (8, 8)",
+ "(9, 9) -> (8, 15)",
+ "(10, 2) -> (9, 8)",
+ "(10, 7) -> (9, 13)",
+ "(10, 8) -> (9, 14)",
+ "(10, 10) -> (9, 16)",
+ "(11, 4) -> (10, 10)",
+ "(11, 11) -> (10, 17)",
+ "(11, 15) -> (10, 21)",
+ "(11, 16) -> (10, 22)",
+ "(11, 18) -> (10, 24)",
+ "(12, 2) -> (11, 8)",
+ "(13, 2) -> (12, 8)",
+ "(13, 8) -> (12, 14)",
+ "(13, 9) -> (12, 15)",
+ "(13, 11) -> (12, 17)",
+ "(14, 4) -> (13, 10)",
+ "(14, 11) -> (13, 17)",
+ "(14, 15) -> (13, 21)",
+ "(14, 16) -> (13, 22)",
+ "(14, 21) -> (13, 27)",
+ "(14, 22) -> (13, 28)",
+ "(14, 24) -> (13, 29)",
+ "(14, 26) -> (13, 30)",
+ "(14, 30) -> (13, 34)",
+ "(14, 31) -> (14, 12)",
+ "(15, 2) -> (15, 8)",
+ "(16, 0) -> (16, 6)",
+]
+`;
+
+exports[`Regexp 1`] = `
+"var r = /foobar/g;
+"
+`;
+
+exports[`Regexp 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(1, 17) -> (1, 15)",
+]
+`;
+
+exports[`Simple function 1`] = `
+"function foo() {
+ bar();
+}
+"
+`;
+
+exports[`Simple function 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 9) -> (1, 9)",
+ "(1, 12) -> (1, 12)",
+ "(1, 13) -> (1, 13)",
+ "(1, 15) -> (1, 15)",
+ "(2, 2) -> (1, 17)",
+ "(2, 5) -> (1, 20)",
+ "(2, 6) -> (1, 21)",
+ "(2, 7) -> (1, 22)",
+ "(3, 0) -> (1, 24)",
+]
+`;
+
+exports[`Single line comment 1`] = `
+"// Comment
+function foo() {
+ bar();
+}
+"
+`;
+
+exports[`Single line comment 2`] = `
+Array [
+ "(2, 0) -> (3, 4)",
+ "(2, 9) -> (3, 13)",
+ "(2, 12) -> (3, 16)",
+ "(2, 13) -> (3, 17)",
+ "(2, 15) -> (3, 19)",
+ "(3, 2) -> (3, 21)",
+ "(3, 5) -> (3, 24)",
+ "(3, 6) -> (3, 25)",
+ "(3, 7) -> (3, 26)",
+ "(4, 0) -> (3, 28)",
+]
+`;
+
+exports[`Stack-keyword property access 1`] = `
+"foo.a = 1.1;
+foo.do.switch.case.default = 2.2;
+foo.b = 3.3;
+"
+`;
+
+exports[`Stack-keyword property access 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 3) -> (1, 3)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(1, 11) -> (1, 9)",
+ "(2, 0) -> (1, 10)",
+ "(2, 3) -> (1, 13)",
+ "(2, 4) -> (1, 14)",
+ "(2, 6) -> (1, 16)",
+ "(2, 7) -> (1, 17)",
+ "(2, 13) -> (1, 23)",
+ "(2, 14) -> (1, 24)",
+ "(2, 18) -> (1, 28)",
+ "(2, 19) -> (1, 29)",
+ "(2, 27) -> (1, 36)",
+ "(2, 29) -> (1, 37)",
+ "(2, 32) -> (1, 40)",
+ "(3, 0) -> (1, 41)",
+ "(3, 3) -> (1, 44)",
+ "(3, 4) -> (1, 45)",
+ "(3, 6) -> (1, 46)",
+ "(3, 8) -> (1, 47)",
+ "(3, 11) -> (1, 50)",
+]
+`;
+
+exports[`String with quote 1`] = `
+"var foo = '\\\\'';
+"
+`;
+
+exports[`String with quote 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 8) -> (1, 8)",
+ "(1, 10) -> (1, 10)",
+ "(1, 14) -> (1, 13)",
+]
+`;
+
+exports[`String with semicolon 1`] = `
+"var foo = ';';
+"
+`;
+
+exports[`String with semicolon 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 8) -> (1, 8)",
+ "(1, 10) -> (1, 10)",
+ "(1, 13) -> (1, 13)",
+]
+`;
+
+exports[`Subclass handling 1`] = `
+"class Class extends Base {
+ constructor() {
+ }
+}
+"
+`;
+
+exports[`Subclass handling 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 6) -> (1, 7)",
+ "(1, 12) -> (1, 14)",
+ "(1, 20) -> (1, 23)",
+ "(1, 25) -> (1, 27)",
+ "(2, 2) -> (1, 28)",
+ "(2, 13) -> (1, 39)",
+ "(2, 14) -> (1, 40)",
+ "(2, 16) -> (1, 41)",
+ "(3, 2) -> (1, 42)",
+ "(4, 0) -> (1, 43)",
+]
+`;
+
+exports[`Switch statements 1`] = `
+"switch (x) {
+ case a:
+ foo();
+ break;
+ default:
+ bar()
+}
+"
+`;
+
+exports[`Switch statements 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 7) -> (1, 6)",
+ "(1, 8) -> (1, 7)",
+ "(1, 9) -> (1, 8)",
+ "(1, 11) -> (1, 9)",
+ "(2, 2) -> (1, 10)",
+ "(2, 7) -> (1, 15)",
+ "(2, 8) -> (1, 16)",
+ "(3, 4) -> (1, 17)",
+ "(3, 7) -> (1, 20)",
+ "(3, 8) -> (1, 21)",
+ "(3, 9) -> (1, 22)",
+ "(4, 4) -> (1, 23)",
+ "(4, 9) -> (1, 28)",
+ "(5, 2) -> (1, 29)",
+ "(5, 9) -> (1, 36)",
+ "(6, 4) -> (1, 37)",
+ "(6, 7) -> (1, 40)",
+ "(6, 8) -> (1, 41)",
+ "(7, 0) -> (1, 42)",
+]
+`;
+
+exports[`Template literals 1`] = `
+"\`abc\${ JSON.stringify({
+ clas: 'testing'
+}) }def\`;
+{
+ a();
+}
+"
+`;
+
+exports[`Template literals 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 1) -> (1, 1)",
+ "(1, 4) -> (1, 4)",
+ "(1, 7) -> (1, 6)",
+ "(1, 11) -> (1, 10)",
+ "(1, 12) -> (1, 11)",
+ "(1, 21) -> (1, 20)",
+ "(1, 22) -> (1, 21)",
+ "(2, 2) -> (1, 22)",
+ "(2, 6) -> (1, 26)",
+ "(2, 8) -> (1, 28)",
+ "(3, 0) -> (1, 37)",
+ "(3, 1) -> (1, 38)",
+ "(3, 3) -> (1, 39)",
+ "(3, 4) -> (1, 40)",
+ "(3, 7) -> (1, 43)",
+ "(3, 8) -> (1, 44)",
+ "(4, 0) -> (1, 45)",
+ "(5, 2) -> (1, 46)",
+ "(5, 3) -> (1, 47)",
+ "(5, 4) -> (1, 48)",
+ "(5, 5) -> (1, 49)",
+ "(6, 0) -> (1, 50)",
+]
+`;
+
+exports[`Ternary operator 1`] = `
+"bar ? baz : bang;
+"
+`;
+
+exports[`Ternary operator 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 3)",
+ "(1, 6) -> (1, 4)",
+ "(1, 10) -> (1, 7)",
+ "(1, 12) -> (1, 8)",
+ "(1, 16) -> (1, 12)",
+]
+`;
+
+exports[`This property access 1`] = `
+"var foo = this.foo;
+"
+`;
+
+exports[`This property access 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 8) -> (1, 7)",
+ "(1, 10) -> (1, 8)",
+ "(1, 14) -> (1, 12)",
+ "(1, 15) -> (1, 13)",
+ "(1, 18) -> (1, 16)",
+]
+`;
+
+exports[`True assignment 1`] = `
+"var foo = true;
+"
+`;
+
+exports[`True assignment 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 8) -> (1, 7)",
+ "(1, 10) -> (1, 8)",
+ "(1, 14) -> (1, 12)",
+]
+`;
+
+exports[`Try/catch/finally statement 1`] = `
+"try {
+ dangerous()
+} catch (e) {
+ handle(e)
+} finally {
+ cleanup()
+}
+"
+`;
+
+exports[`Try/catch/finally statement 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 3)",
+ "(2, 2) -> (1, 4)",
+ "(2, 11) -> (1, 13)",
+ "(2, 12) -> (1, 14)",
+ "(3, 0) -> (1, 15)",
+ "(3, 2) -> (1, 16)",
+ "(3, 8) -> (1, 21)",
+ "(3, 9) -> (1, 22)",
+ "(3, 10) -> (1, 23)",
+ "(3, 12) -> (1, 24)",
+ "(4, 2) -> (1, 25)",
+ "(4, 8) -> (1, 31)",
+ "(4, 9) -> (1, 32)",
+ "(4, 10) -> (1, 33)",
+ "(5, 0) -> (1, 34)",
+ "(5, 2) -> (1, 35)",
+ "(5, 10) -> (1, 42)",
+ "(6, 2) -> (1, 43)",
+ "(6, 9) -> (1, 50)",
+ "(6, 10) -> (1, 51)",
+ "(7, 0) -> (1, 52)",
+]
+`;
+
+exports[`Undefined assignment 1`] = `
+"var i = undefined;
+"
+`;
+
+exports[`Undefined assignment 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(1, 17) -> (1, 15)",
+]
+`;
+
+exports[`Unnamed class handling 1`] = `
+"let unnamed = class {
+ constructor() {
+ }
+}
+"
+`;
+
+exports[`Unnamed class handling 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 12) -> (1, 11)",
+ "(1, 14) -> (1, 12)",
+ "(1, 20) -> (1, 17)",
+ "(2, 2) -> (1, 18)",
+ "(2, 13) -> (1, 29)",
+ "(2, 14) -> (1, 30)",
+ "(2, 16) -> (1, 31)",
+ "(3, 2) -> (1, 32)",
+ "(4, 0) -> (1, 33)",
+]
+`;
+
+exports[`Void 0 assignment 1`] = `
+"var i = void 0;
+"
+`;
+
+exports[`Void 0 assignment 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 8) -> (1, 6)",
+ "(1, 13) -> (1, 11)",
+ "(1, 14) -> (1, 12)",
+]
+`;
+
+exports[`With statement 1`] = `
+"with (obj) {
+ crock()
+}
+"
+`;
+
+exports[`With statement 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 5) -> (1, 4)",
+ "(1, 6) -> (1, 5)",
+ "(1, 9) -> (1, 8)",
+ "(1, 11) -> (1, 9)",
+ "(2, 2) -> (1, 10)",
+ "(2, 7) -> (1, 15)",
+ "(2, 8) -> (1, 16)",
+ "(3, 0) -> (1, 17)",
+]
+`;
+
+exports[`for..of loop 1`] = `
+"for (const x of [
+ 1,
+ 2,
+ 3
+]) {
+ console.log(x)
+}
+"
+`;
+
+exports[`for..of loop 2`] = `
+Array [
+ "(1, 0) -> (1, 0)",
+ "(1, 4) -> (1, 4)",
+ "(1, 5) -> (1, 5)",
+ "(1, 11) -> (1, 11)",
+ "(1, 13) -> (1, 13)",
+ "(1, 16) -> (1, 16)",
+ "(2, 2) -> (1, 17)",
+ "(2, 3) -> (1, 18)",
+ "(3, 2) -> (1, 19)",
+ "(3, 3) -> (1, 20)",
+ "(4, 2) -> (1, 21)",
+ "(5, 0) -> (1, 22)",
+ "(5, 1) -> (1, 23)",
+ "(5, 3) -> (1, 25)",
+ "(6, 2) -> (1, 27)",
+ "(6, 9) -> (1, 34)",
+ "(6, 10) -> (1, 35)",
+ "(6, 13) -> (1, 38)",
+ "(6, 14) -> (1, 39)",
+ "(6, 15) -> (1, 40)",
+ "(7, 0) -> (1, 42)",
+]
+`;
diff --git a/devtools/client/debugger/src/workers/pretty-print/tests/prettyFast.spec.js b/devtools/client/debugger/src/workers/pretty-print/tests/prettyFast.spec.js
new file mode 100644
index 0000000000..b9c19093ad
--- /dev/null
+++ b/devtools/client/debugger/src/workers/pretty-print/tests/prettyFast.spec.js
@@ -0,0 +1,435 @@
+/* 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/>. */
+
+/*
+ * Copyright 2013 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE.md or:
+ * http://opensource.org/licenses/BSD-2-Clause
+ */
+import { prettyFast } from "../pretty-fast";
+import { SourceMapConsumer } from "devtools/client/shared/vendor/source-map/source-map";
+
+const cases = [
+ {
+ name: "Simple function",
+ input: "function foo() { bar(); }",
+ },
+ {
+ name: "Nested function",
+ input: "function foo() { function bar() { debugger; } bar(); }",
+ },
+ {
+ name: "Immediately invoked function expression",
+ input: "(function(){thingy()}())",
+ },
+ {
+ name: "Single line comment",
+ input: `
+ // Comment
+ function foo() { bar(); }`,
+ },
+ {
+ name: "Multi line comment",
+ input: `
+ /* Comment
+ more comment */
+ function foo() { bar(); }
+ `,
+ },
+ { name: "Null assignment", input: "var i=null;" },
+ { name: "Undefined assignment", input: "var i=undefined;" },
+ { name: "Void 0 assignment", input: "var i=void 0;" },
+ {
+ name: "This property access",
+ input: "var foo=this.foo;\n",
+ },
+
+ {
+ name: "True assignment",
+ input: "var foo=true;\n",
+ },
+
+ {
+ name: "False assignment",
+ input: "var foo=false;\n",
+ },
+
+ {
+ name: "For loop",
+ input: "for (var i = 0; i < n; i++) { console.log(i); }",
+ },
+
+ {
+ name: "for..of loop",
+ input: "for (const x of [1,2,3]) { console.log(x) }",
+ },
+
+ {
+ name: "String with semicolon",
+ input: "var foo = ';';\n",
+ },
+
+ {
+ name: "String with quote",
+ input: 'var foo = "\'";\n',
+ },
+
+ {
+ name: "Function calls",
+ input: "var result=func(a,b,c,d);",
+ },
+
+ {
+ name: "Regexp",
+ input: "var r=/foobar/g;",
+ },
+
+ {
+ name: "In operator",
+ input: "if(foo in bar){doThing()}",
+ output: "if (foo in bar) {\n" + " doThing()\n" + "}\n",
+ },
+ {
+ name: "With statement",
+ input: "with(obj){crock()}",
+ },
+ {
+ name: "New expression",
+ input: "var foo=new Foo();",
+ },
+ {
+ name: "Continue/break statements",
+ input: "while(1){if(x){continue}if(y){break}if(z){break foo}}",
+ },
+ {
+ name: "Instanceof",
+ input: "var a=x instanceof y;",
+ },
+ {
+ name: "Binary operators",
+ input: "var a=5*30;var b=5>>3;",
+ },
+ {
+ name: "Delete",
+ input: "delete obj.prop;",
+ },
+
+ {
+ name: "Try/catch/finally statement",
+ input: "try{dangerous()}catch(e){handle(e)}finally{cleanup()}",
+ },
+ {
+ name: "If/else statement",
+ input: "if(c){then()}else{other()}",
+ },
+ {
+ name: "If/else without curlies",
+ input: "if(c) a else b",
+ },
+ {
+ name: "Objects",
+ input: `
+ var o={a:1,
+ b:2};`,
+ },
+ {
+ name: "Do/while loop",
+ input: "do{x}while(y)",
+ },
+ {
+ name: "Arrays",
+ input: "var a=[1,2,3];",
+ },
+ {
+ name: "Arrays and spread operator",
+ input: "var a=[1,...[2,3],...[], 4];",
+ },
+ {
+ name: "Empty object/array literals",
+ input: `let a=[];const b={};c={...{},d: 42};for(let x of []){for(let y in {}){}}`,
+ },
+ {
+ name: "Code that relies on ASI",
+ input: `
+ var foo = 10
+ var bar = 20
+ function g() {
+ a()
+ b()
+ }`,
+ },
+ {
+ name: "Ternary operator",
+ input: "bar?baz:bang;",
+ },
+ {
+ name: "Switch statements",
+ input: "switch(x){case a:foo();break;default:bar()}",
+ },
+
+ {
+ name: "Multiple single line comments",
+ input: `function f() {
+ // a
+ // b
+ // c
+ }`,
+ },
+ {
+ name: "Indented multiline comment",
+ input: `function foo() {
+ /**
+ * java doc style comment
+ * more comment
+ */
+ bar();
+ }`,
+ },
+ {
+ name: "ASI return",
+ input: `function f() {
+ return
+ {}
+ }`,
+ },
+ {
+ name: "Non-ASI property access",
+ input: `[1,2,3]
+ [0]`,
+ },
+ {
+ name: "Non-ASI in",
+ input: `'x'
+ in foo`,
+ },
+
+ {
+ name: "Non-ASI function call",
+ input: `f
+ ()`,
+ },
+ {
+ name: "Non-ASI new",
+ input: `new
+ F()`,
+ },
+ {
+ name: "Getter and setter literals",
+ input: "var obj={get foo(){return this._foo},set foo(v){this._foo=v}}",
+ },
+ {
+ name: "Escaping backslashes in strings",
+ input: "'\\\\'\n",
+ },
+ {
+ name: "Escaping carriage return in strings",
+ input: "'\\r'\n",
+ },
+ {
+ name: "Escaping tab in strings",
+ input: "'\\t'\n",
+ },
+ {
+ name: "Escaping vertical tab in strings",
+ input: "'\\v'\n",
+ },
+ {
+ name: "Escaping form feed in strings",
+ input: "'\\f'\n",
+ },
+ {
+ name: "Escaping null character in strings",
+ input: "'\\0'\n",
+ },
+ {
+ name: "Bug 977082 - space between grouping operator and dot notation",
+ input: `JSON.stringify(3).length;
+ ([1,2,3]).length;
+ (new Date()).toLocaleString();`,
+ },
+ {
+ name: "Bug 975477 don't move end of line comments to next line",
+ input: `switch (request.action) {
+ case 'show': //$NON-NLS-0$
+ if (localStorage.hideicon !== 'true') { //$NON-NLS-0$
+ chrome.pageAction.show(sender.tab.id);
+ }
+ break;
+ case 'hide': /*Multiline
+ Comment */
+ break;
+ default:
+ console.warn('unknown request'); //$NON-NLS-0$
+ // don't respond if you don't understand the message.
+ return;
+ }`,
+ },
+ {
+ name: "Const handling",
+ input: "const d = 'yes';\n",
+ },
+ {
+ name: "Let handling without value",
+ input: "let d;\n",
+ },
+ {
+ name: "Let handling with value",
+ input: "let d = 'yes';\n",
+ },
+ {
+ name: "Template literals",
+ // issue in acorn
+ input: "`abc${JSON.stringify({clas: 'testing'})}def`;{a();}",
+ },
+ {
+ name: "Class handling",
+ input: "class Class{constructor(){}}",
+ },
+ {
+ name: "Subclass handling",
+ input: "class Class extends Base{constructor(){}}",
+ },
+ {
+ name: "Unnamed class handling",
+ input: "let unnamed=class{constructor(){}}",
+ },
+ {
+ name: "Named class handling",
+ input: "let unnamed=class Class{constructor(){}}",
+ },
+ {
+ name: "Class extension within a function",
+ input: "(function() { class X extends Y { constructor() {} } })()",
+ },
+ {
+ name: "Bug 1261971 - indentation after switch statement",
+ input: "{switch(x){}if(y){}done();}",
+ },
+ {
+ name: "Bug 1206633 - spaces in for of",
+ input: "for (let tab of tabs) {}",
+ },
+ {
+ name: "Bug pretty-sure-3 - escaping line and paragraph separators",
+ input: "x = '\\u2029\\u2028';",
+ },
+ {
+ name: "Bug pretty-sure-4 - escaping null character before digit",
+ input: "x = '\\u00001';",
+ },
+ {
+ name: "Bug pretty-sure-5 - empty multiline comment shouldn't throw exception",
+ input: `{
+ /*
+ */
+ return;
+ }`,
+ },
+ {
+ name: "Bug pretty-sure-6 - inline comment shouldn't move parenthesis to next line",
+ input: `return /* inline comment */ (
+ 1+1);`,
+ },
+ {
+ name: "Bug pretty-sure-7 - accessing a literal number property requires a space",
+ input: "0..toString()+x.toString();",
+ },
+ {
+ name: "Bug pretty-sure-8 - return and yield only accept arguments when on the same line",
+ input: `{
+ return
+ (x)
+ yield
+ (x)
+ yield
+ *x
+ }`,
+ },
+ {
+ name: "Bug pretty-sure-9 - accept unary operator at start of file",
+ input: "+ 0",
+ },
+ {
+ name: "Stack-keyword property access",
+ input: "foo.a=1.1;foo.do.switch.case.default=2.2;foo.b=3.3;\n",
+ },
+ {
+ name: "Dot handling with let which is identifier name",
+ input: "y.let.let = 1.23;\n",
+ },
+ {
+ name: "Dot handling with keywords which are identifier name",
+ input: "y.await.break.const.delete.else.return.new.yield = 1.23;\n",
+ },
+ {
+ name: "Optional chaining parsing support",
+ input: "x?.y?.z?.['a']?.check();\n",
+ },
+ {
+ name: "Private fields parsing support",
+ input: `
+ class MyClass {
+ constructor(a) {
+ this.#a = a;this.#b = Math.random();this.ab = this.#getAB();
+ }
+ #a
+ #b = "default value"
+ static #someStaticPrivate
+ #getA() {
+ return this.#a;
+ }
+ #getAB() {
+ return this.#getA()+this.
+ #b
+ }
+ }
+ `,
+ },
+ {
+ name: "Long parenthesis",
+ input: `
+ if (thisIsAVeryLongVariable && thisIsAnotherOne || yetAnotherVeryLongVariable) {
+ (thisIsAnotherOne = thisMayReturnNull() || "hi", thisIsAVeryLongVariable = 42, yetAnotherVeryLongVariable && doSomething(true /* do it well */,thisIsAVeryLongVariable, thisIsAnotherOne, yetAnotherVeryLongVariable))
+ }
+ for (let thisIsAnotherVeryLongVariable = 0; i < thisIsAnotherVeryLongVariable.length; thisIsAnotherVeryLongVariable++) {}
+ const x = ({thisIsAnotherVeryLongPropertyName: "but should not cause the paren to be a line delimiter"})
+ `,
+ },
+ {
+ name: "Fat arrow function",
+ input: `
+ const a = () => 42
+ addEventListener("click", e => { return false });
+ const sum = (c,d) => c+d
+ `,
+ },
+];
+
+const includesOnly = cases.find(({ only }) => only);
+
+for (const { name, input, only, skip } of cases) {
+ if ((includesOnly && !only) || skip) {
+ continue;
+ }
+ // Wrapping name into a string to avoid jest/valid-title failures
+ test(`${name}`, async () => {
+ const actual = prettyFast(input, {
+ indent: " ",
+ url: "test.js",
+ });
+
+ expect(actual.code).toMatchSnapshot();
+
+ const smc = await new SourceMapConsumer(actual.map.toJSON());
+ const mappings = [];
+ smc.eachMapping(
+ ({ generatedColumn, generatedLine, originalColumn, originalLine }) => {
+ mappings.push(
+ `(${originalLine}, ${originalColumn}) -> (${generatedLine}, ${generatedColumn})`
+ );
+ }
+ );
+ expect(mappings).toMatchSnapshot();
+ });
+}
diff --git a/devtools/client/debugger/src/workers/pretty-print/worker.js b/devtools/client/debugger/src/workers/pretty-print/worker.js
new file mode 100644
index 0000000000..1c5587db9f
--- /dev/null
+++ b/devtools/client/debugger/src/workers/pretty-print/worker.js
@@ -0,0 +1,98 @@
+/* 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/>. */
+
+import { workerHandler } from "../../../../shared/worker-utils";
+import { prettyFast } from "./pretty-fast";
+
+var { SourceMapGenerator } = require("source-map");
+
+const sourceMapGeneratorByTaskId = new Map();
+
+function prettyPrint({ url, indent, sourceText }) {
+ const { code, map: sourceMapGenerator } = prettyFast(sourceText, {
+ url,
+ indent,
+ });
+
+ return {
+ code,
+ sourceMap: sourceMapGenerator.toJSON(),
+ };
+}
+
+function prettyPrintInlineScript({
+ taskId,
+ url,
+ indent,
+ sourceText,
+ originalStartLine,
+ originalStartColumn,
+ generatedStartLine,
+}) {
+ let taskSourceMapGenerator;
+ if (!sourceMapGeneratorByTaskId.has(taskId)) {
+ taskSourceMapGenerator = new SourceMapGenerator({ file: url });
+ sourceMapGeneratorByTaskId.set(taskId, taskSourceMapGenerator);
+ } else {
+ taskSourceMapGenerator = sourceMapGeneratorByTaskId.get(taskId);
+ }
+
+ const { code } = prettyFast(sourceText, {
+ url,
+ indent,
+ sourceMapGenerator: taskSourceMapGenerator,
+ /*
+ * By default prettyPrint will trim the text, and we'd have the pretty text displayed
+ * just after the script tag, e.g.:
+ *
+ * ```
+ * <script>if (true) {
+ * something()
+ * }
+ * </script>
+ * ```
+ *
+ * We want the text to start on a new line, so prepend a line break, so we get
+ * something like:
+ *
+ * ```
+ * <script>
+ * if (true) {
+ * something()
+ * }
+ * </script>
+ * ```
+ */
+ prefixWithNewLine: true,
+ originalStartLine,
+ originalStartColumn,
+ generatedStartLine,
+ });
+
+ // When a taskId was passed, we only return the pretty printed text.
+ // The source map should be retrieved with getSourceMapForTask.
+ return code;
+}
+
+/**
+ * Get the source map for a pretty-print task
+ *
+ * @param {Integer} taskId: The taskId that was used to call prettyPrint
+ * @returns {Object} A source map object
+ */
+function getSourceMapForTask(taskId) {
+ if (!sourceMapGeneratorByTaskId.has(taskId)) {
+ return null;
+ }
+
+ const taskSourceMapGenerator = sourceMapGeneratorByTaskId.get(taskId);
+ sourceMapGeneratorByTaskId.delete(taskId);
+ return taskSourceMapGenerator.toJSON();
+}
+
+self.onmessage = workerHandler({
+ prettyPrint,
+ prettyPrintInlineScript,
+ getSourceMapForTask,
+});
diff --git a/devtools/client/debugger/src/workers/search/get-matches.js b/devtools/client/debugger/src/workers/search/get-matches.js
new file mode 100644
index 0000000000..972dea6818
--- /dev/null
+++ b/devtools/client/debugger/src/workers/search/get-matches.js
@@ -0,0 +1,45 @@
+/* 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/>. */
+
+import assert from "../../utils/assert";
+import buildQuery from "../../utils/build-query";
+
+export default function getMatches(query, text, options) {
+ if (!query || !text || !options) {
+ return [];
+ }
+ const regexQuery = buildQuery(query, options, {
+ isGlobal: true,
+ });
+ const matchedLocations = [];
+ const lines = text.split("\n");
+ for (let i = 0; i < lines.length; i++) {
+ let singleMatch;
+ const line = lines[i];
+ while ((singleMatch = regexQuery.exec(line)) !== null) {
+ // Flow doesn't understand the test above.
+ if (!singleMatch) {
+ throw new Error("no singleMatch");
+ }
+
+ matchedLocations.push({
+ line: i,
+ ch: singleMatch.index,
+ match: singleMatch[0],
+ });
+
+ // When the match is an empty string the regexQuery.lastIndex will not
+ // change resulting in an infinite loop so we need to check for this and
+ // increment it manually in that case. See issue #7023
+ if (singleMatch[0] === "") {
+ assert(
+ !regexQuery.unicode,
+ "lastIndex++ can cause issues in unicode mode"
+ );
+ regexQuery.lastIndex++;
+ }
+ }
+ }
+ return matchedLocations;
+}
diff --git a/devtools/client/debugger/src/workers/search/index.js b/devtools/client/debugger/src/workers/search/index.js
new file mode 100644
index 0000000000..928bbf50e6
--- /dev/null
+++ b/devtools/client/debugger/src/workers/search/index.js
@@ -0,0 +1,17 @@
+/* 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/>. */
+
+import { WorkerDispatcher } from "devtools/client/shared/worker-utils";
+
+const WORKER_URL = "resource://devtools/client/debugger/dist/search-worker.js";
+
+export class SearchDispatcher extends WorkerDispatcher {
+ constructor(jestUrl) {
+ super(jestUrl || WORKER_URL);
+ }
+
+ getMatches = this.task("getMatches");
+
+ findSourceMatches = this.task("findSourceMatches");
+}
diff --git a/devtools/client/debugger/src/workers/search/moz.build b/devtools/client/debugger/src/workers/search/moz.build
new file mode 100644
index 0000000000..b7223ac81a
--- /dev/null
+++ b/devtools/client/debugger/src/workers/search/moz.build
@@ -0,0 +1,10 @@
+# vim: set filetype=python:
+# 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/.
+
+DIRS += []
+
+CompiledModules(
+ "index.js",
+)
diff --git a/devtools/client/debugger/src/workers/search/project-search.js b/devtools/client/debugger/src/workers/search/project-search.js
new file mode 100644
index 0000000000..f3751b57c4
--- /dev/null
+++ b/devtools/client/debugger/src/workers/search/project-search.js
@@ -0,0 +1,70 @@
+/* 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/>. */
+
+// Maybe reuse file search's functions?
+
+import getMatches from "./get-matches";
+
+export function findSourceMatches(content, queryText, options) {
+ if (queryText == "") {
+ return [];
+ }
+
+ const text = content.value;
+ const lines = text.split("\n");
+
+ return getMatches(queryText, text, options).map(({ line, ch, match }) => {
+ const { value, matchIndex } = truncateLine(lines[line], ch);
+ return {
+ line: line + 1,
+ column: ch,
+
+ matchIndex,
+ match,
+ value,
+ };
+ });
+}
+
+// This is used to find start of a word, so that cropped string look nice
+const startRegex = /([ !@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?])/g;
+// Similarly, find
+const endRegex = new RegExp(
+ [
+ "([ !@#$%^&*()_+-=[]{};':\"\\|,.<>/?])",
+ '[^ !@#$%^&*()_+-=[]{};\':"\\|,.<>/?]*$"/',
+ ].join("")
+);
+// For texts over 100 characters this truncates the text (for display)
+// around the context of the matched text.
+function truncateLine(text, column) {
+ if (text.length < 100) {
+ return {
+ matchIndex: column,
+ value: text,
+ };
+ }
+
+ // Initially take 40 chars left to the match
+ const offset = Math.max(column - 40, 0);
+ // 400 characters should be enough to figure out the context of the match
+ const truncStr = text.slice(offset, column + 400);
+ let start = truncStr.search(startRegex);
+ let end = truncStr.search(endRegex);
+
+ if (start > column) {
+ // No word separator found before the match, so we take all characters
+ // before the match
+ start = -1;
+ }
+ if (end < column) {
+ end = truncStr.length;
+ }
+ const value = truncStr.slice(start + 1, end);
+
+ return {
+ matchIndex: column - start - offset - 1,
+ value,
+ };
+}
diff --git a/devtools/client/debugger/src/workers/search/tests/get-matches.spec.js b/devtools/client/debugger/src/workers/search/tests/get-matches.spec.js
new file mode 100644
index 0000000000..30b0ce316d
--- /dev/null
+++ b/devtools/client/debugger/src/workers/search/tests/get-matches.spec.js
@@ -0,0 +1,99 @@
+/* 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/>. */
+
+import getMatches from "../get-matches";
+
+describe("search", () => {
+ describe("getMatches", () => {
+ it("gets basic string match", () => {
+ const text = "the test string with test in it multiple times test.";
+ const query = "test";
+ const matchLocations = getMatches(query, text, {
+ caseSensitive: true,
+ wholeWord: false,
+ regexMatch: false,
+ });
+ expect(matchLocations).toHaveLength(3);
+ });
+
+ it("gets basic string match case-sensitive", () => {
+ const text = "the Test string with test in it multiple times test.";
+ const query = "Test";
+ const matchLocations = getMatches(query, text, {
+ caseSensitive: true,
+ wholeWord: false,
+ regexMatch: false,
+ });
+ expect(matchLocations).toHaveLength(1);
+ });
+
+ it("gets whole word string match", () => {
+ const text = "the test string test in it multiple times whoatestthe.";
+ const query = "test";
+ const matchLocations = getMatches(query, text, {
+ caseSensitive: true,
+ wholeWord: true,
+ regexMatch: false,
+ });
+ expect(matchLocations).toHaveLength(2);
+ });
+
+ it("gets regex match", () => {
+ const text = "the test string test in it multiple times whoatestthe.";
+ const query = "(\\w+)\\s+(\\w+)";
+ const matchLocations = getMatches(query, text, {
+ caseSensitive: true,
+ wholeWord: false,
+ regexMatch: true,
+ });
+ expect(matchLocations).toHaveLength(4);
+ });
+
+ it("doesnt fail on empty data", () => {
+ const text = "";
+ const query = "";
+ const matchLocations = getMatches(query, text, {
+ caseSensitive: true,
+ wholeWord: false,
+ regexMatch: true,
+ });
+ expect(matchLocations).toHaveLength(0);
+ });
+
+ it("fails gracefully when the line is too long", () => {
+ const text = Array(100002).join("x");
+ const query = "query";
+ const matchLocations = getMatches(query, text, {
+ caseSensitive: true,
+ wholeWord: false,
+ regexMatch: true,
+ });
+ expect(matchLocations).toHaveLength(0);
+ });
+
+ // regression test for #6896
+ it("doesn't crash on the regex 'a*'", () => {
+ const text = "abc";
+ const query = "a*";
+ const matchLocations = getMatches(query, text, {
+ caseSensitive: true,
+ wholeWord: false,
+ regexMatch: true,
+ });
+ expect(matchLocations).toHaveLength(4);
+ });
+
+ // regression test for #6896
+ it("doesn't crash on the regex '^'", () => {
+ const text = "012";
+ const query = "^";
+ const matchLocations = getMatches(query, text, {
+ caseSensitive: true,
+ wholeWord: false,
+ regexMatch: true,
+ });
+ expect(matchLocations).toHaveLength(1);
+ });
+ });
+});
diff --git a/devtools/client/debugger/src/workers/search/worker.js b/devtools/client/debugger/src/workers/search/worker.js
new file mode 100644
index 0000000000..b452697516
--- /dev/null
+++ b/devtools/client/debugger/src/workers/search/worker.js
@@ -0,0 +1,9 @@
+/* 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/>. */
+
+import getMatches from "./get-matches";
+import { findSourceMatches } from "./project-search";
+import { workerHandler } from "../../../../shared/worker-utils";
+
+self.onmessage = workerHandler({ getMatches, findSourceMatches });