diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /devtools/client/debugger/src/workers | |
parent | Initial commit. (diff) | |
download | firefox-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')
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 }); |