master 8a387a10a3f7 cached
144 files
485.7 KB
120.7k tokens
824 symbols
1 requests
Download .txt
Showing preview only (524K chars total). Download the full file or copy to clipboard to get everything.
Repository: firefox-devtools/vscode-firefox-debug
Branch: master
Commit: 8a387a10a3f7
Files: 144
Total size: 485.7 KB

Directory structure:
gitextract_cmpgi7eh/

├── .gitignore
├── .mocharc.json
├── .vscode/
│   ├── extensions.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── .vscodeignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── dist/
│   ├── README.md
│   ├── package.json
│   └── terminator/
│       ├── main.js
│       └── manifest.json
├── package.json
├── src/
│   ├── README.md
│   ├── adapter/
│   │   ├── README.md
│   │   ├── adapter/
│   │   │   ├── README.md
│   │   │   ├── addonManager.ts
│   │   │   ├── breakpoint.ts
│   │   │   ├── breakpointsManager.ts
│   │   │   ├── consoleAPICall.ts
│   │   │   ├── dataBreakpointsManager.ts
│   │   │   ├── descriptor.ts
│   │   │   ├── environment.ts
│   │   │   ├── eventBreakpointsManager.ts
│   │   │   ├── frame.ts
│   │   │   ├── getterValue.ts
│   │   │   ├── objectGrip.ts
│   │   │   ├── preview.ts
│   │   │   ├── registry.ts
│   │   │   ├── scope.ts
│   │   │   ├── skipFilesManager.ts
│   │   │   ├── source.ts
│   │   │   ├── sourcesManager.ts
│   │   │   ├── thread.ts
│   │   │   ├── variable.ts
│   │   │   └── variablesProvider.ts
│   │   ├── configuration.ts
│   │   ├── debugAdapterBase.ts
│   │   ├── firefox/
│   │   │   ├── README.md
│   │   │   ├── actorProxy/
│   │   │   │   ├── README.md
│   │   │   │   ├── addons.ts
│   │   │   │   ├── base.ts
│   │   │   │   ├── breakpointList.ts
│   │   │   │   ├── console.ts
│   │   │   │   ├── descriptor.ts
│   │   │   │   ├── device.ts
│   │   │   │   ├── frame.ts
│   │   │   │   ├── interface.ts
│   │   │   │   ├── longString.ts
│   │   │   │   ├── objectGrip.ts
│   │   │   │   ├── preference.ts
│   │   │   │   ├── root.ts
│   │   │   │   ├── source.ts
│   │   │   │   ├── target.ts
│   │   │   │   ├── thread.ts
│   │   │   │   ├── threadConfiguration.ts
│   │   │   │   └── watcher.ts
│   │   │   ├── connection.ts
│   │   │   ├── launch.ts
│   │   │   ├── protocol.d.ts
│   │   │   ├── sourceMaps/
│   │   │   │   ├── README.md
│   │   │   │   ├── info.ts
│   │   │   │   ├── manager.ts
│   │   │   │   ├── source.ts
│   │   │   │   └── thread.ts
│   │   │   └── transport.ts
│   │   ├── firefoxDebugAdapter.ts
│   │   ├── firefoxDebugSession.ts
│   │   ├── location.ts
│   │   └── util/
│   │       ├── delayedTask.ts
│   │       ├── forkedLauncher.ts
│   │       ├── fs.ts
│   │       ├── log.ts
│   │       ├── misc.ts
│   │       ├── net.ts
│   │       ├── pathMapper.ts
│   │       └── pendingRequests.ts
│   ├── common/
│   │   ├── configuration.ts
│   │   ├── customEvents.ts
│   │   ├── deferredMap.ts
│   │   └── util.ts
│   ├── extension/
│   │   ├── addPathMapping.ts
│   │   ├── debugConfigurationProvider.ts
│   │   ├── eventBreakpointsProvider.ts
│   │   ├── loadedScripts/
│   │   │   ├── fileNode.ts
│   │   │   ├── nonLeafNode.ts
│   │   │   ├── provider.ts
│   │   │   ├── rootNode.ts
│   │   │   ├── sessionNode.ts
│   │   │   └── treeNode.ts
│   │   ├── main.ts
│   │   ├── pathMappingWizard.ts
│   │   └── popupAutohideManager.ts
│   ├── test/
│   │   ├── setup.ts
│   │   ├── sourceMapUtil.ts
│   │   ├── testAccessorProperties.ts
│   │   ├── testConfigurationParser.ts
│   │   ├── testConsole.ts
│   │   ├── testDataBreakpoints.ts
│   │   ├── testDebugAddons.ts
│   │   ├── testDebugWebWorkers.ts
│   │   ├── testEvaluate.ts
│   │   ├── testGulpSourceMaps.ts
│   │   ├── testHitBreakpoints.ts
│   │   ├── testInspectVariables.ts
│   │   ├── testSetBreakpoints.ts
│   │   ├── testSkipFiles.ts
│   │   ├── testSourceActorCollection.ts
│   │   ├── testStepThrough.ts
│   │   ├── testTerminateAndCleanup.ts
│   │   ├── testWebpackSourceMaps.ts
│   │   └── util.ts
│   └── typings/
│       ├── gulp-nop.d.ts
│       └── map-sources.d.ts
├── testdata/
│   ├── web/
│   │   ├── debuggerStatement.js
│   │   ├── dlscript.js
│   │   ├── exception-sourcemap.js
│   │   ├── exception-sourcemap.ts
│   │   ├── exception.js
│   │   ├── index.html
│   │   ├── main.js
│   │   ├── skip.js
│   │   ├── sourceMaps/
│   │   │   ├── modules/
│   │   │   │   ├── f.js
│   │   │   │   ├── g.js
│   │   │   │   └── index.html
│   │   │   └── scripts/
│   │   │       ├── f.js
│   │   │       ├── g.js
│   │   │       └── index.html
│   │   ├── tsconfig.json
│   │   └── worker.js
│   ├── webExtension/
│   │   ├── addOn/
│   │   │   ├── backgroundscript.js
│   │   │   ├── contentscript.js
│   │   │   └── manifest.json
│   │   └── index.html
│   └── webExtension2/
│       ├── addOn/
│       │   ├── backgroundscript.js
│       │   ├── contentscript.js
│       │   └── manifest.json
│       └── index.html
├── tsconfig.json
└── webpack.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
node_modules/
.nyc_output/
coverage/
dist/*.bundle.js
dist/*.bundle.js.map
dist/mappings.wasm
dist/*LICENSE*


================================================
FILE: .mocharc.json
================================================
{
	"require": ["ts-node/register/transpile-only", "src/test/setup.ts"],
	"timeout": 20000,
	"slow": 6000,
	"exit": true,
	"spec": "src/test/test*.ts"
}


================================================
FILE: .vscode/extensions.json
================================================
{
	// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
	// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp

	// List of extensions which should be recommended for users of this workspace.
	"recommendations": [
		"hbenl.vscode-mocha-test-adapter"
	],
	// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
	"unwantedRecommendations": [
	]
}

================================================
FILE: .vscode/launch.json
================================================
{
	"version": "0.2.0",
	"configurations": [
		{
			"type": "pwa-node",
			"request": "launch",
			"name": "debug server",
			"program": "${workspaceFolder}/dist/adapter.bundle.js",
			"args": [ "--server=4711" ],
			"cwd": "${workspaceFolder}",
			"sourceMaps": true
		},
		{
			"type": "pwa-extensionHost",
			"request": "launch",
			"name": "extension host",
			"args": [
				"--extensionDevelopmentPath=${workspaceFolder}"
			],
			"sourceMaps": true
		},
		{
			"type": "firefox",
			"request": "launch",
			"name": "web test",
			"debugServer": 4711,
			"file": "${workspaceFolder}/testdata/web/index.html"
		},
		{
			"type": "firefox",
			"request": "launch",
			"name": "webextension test",
			"debugServer": 4711,
			"addonPath": "${workspaceFolder}/testdata/webExtension/addOn",
			"file": "${workspaceFolder}/testdata/webExtension/index.html"
		}
	],
	"compounds": [
		{
			"name": "server & extension",
			"configurations": [
				"debug server",
				"extension host"
			]
		}
	]
}

================================================
FILE: .vscode/settings.json
================================================
{
	"editor.insertSpaces": false,
	"files.exclude": {
		".git": true,
		"node_modules": true,
		".nyc_output": true,
		"coverage": true
	},
	"editor.rulers": [100],
	"typescript.tsdk": "./node_modules/typescript/lib",
	"editor.tabSize": 4
}


================================================
FILE: .vscode/tasks.json
================================================
{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "npm",
			"script": "watch",
			"label": "watch",
			"isBackground": true,
			"runOptions": {
				"runOn": "folderOpen"
			}
		},
		{
			"type": "npm",
			"script": "typecheck-watch",
			"label": "typecheck-watch",
			"isBackground": true,
			"problemMatcher": "$tsc-watch",
			"runOptions": {
				"runOn": "folderOpen"
			}
		}
	]
}


================================================
FILE: .vscodeignore
================================================
src/**
node_modules/**
**/*.map
package-lock.json
tsconfig.json
webpack.config.js
.vscode/**
.gitignore
.nyc_output/**
coverage/**
testdata/**
dist/package.json
dist/README.md
dist/LICENSE


================================================
FILE: CHANGELOG.md
================================================
### Version 2.15.0
* fix various issues when debugging multiple tabs
* use the URL in thread names

### Version 2.14.1
* fix truncated console messages
* fix threads not showing up in the loaded scripts panel
* only show content scripts when debugging a WebExtension
* don't open a new tab in attach configurations
* resume detached threads when they pause

### Version 2.14.0
* improve how console messages are rendered

### Version 2.13.0
* fix `clearConsoleOnReload`
* fix output of styled console messages
* fix showing the locations of early console messages
* fix breakpoint issues with `reloadOnAttach`
* add pathMappingIndex configuration property

### Version 2.12.1
* fix debugging of web extension content scripts in Firefox 135

### Version 2.12.0
* add support for debugging without a launch configuration
* add support for event listener breakpoints
* fix handling of exited tabs and threads

### Version 2.11.0
* support restarting frames
* support skipping debugger statements
* fix breakpoints with hit counts on Windows

### Version 2.10.1
* fix path mapping on Windows

### Version 2.10.0
* migrate to new debug protocol methods
* fix breakpoints not working after navigating

### Version 2.9.11
* handle console.time/timeEnd
* fix the loaded scripts panel

### Version 2.9.10
* fix marketplace badge link in the README

### Version 2.9.9
* compatibility fix for Node 17 / VS Code 1.82

### Version 2.9.8
* debug protocol update for Firefox 104
* fix the build on MacOS

### Version 2.9.7
* debug protocol update for Firefox 102

### Version 2.9.6
* debug protocol update for Firefox 96

### Version 2.9.5
* compatibility fix for VS Code 1.62.1

### Version 2.9.4
* fix for breakpoints not being set in some situations
* add the URL to a thread's name

### Version 2.9.3
* fix breakpoints only working after reloading the page
* fix missing console messages
* fix debugging WebWorkers
* fix data breakpoints

### Version 2.9.2
* fix terminating Firefox at the end of the debug session
* fix function scopes being with the name `[unknown]`
* show an error message if the path mapping wizard couldn't update the launch configuration
* set the webRoot configuration property to its default if necessary
* support overriding the debugging port in the settings
* add workaround for the snap version of VS Code

### Version 2.9.1
* add `enableCRAWorkaround` configuration property
* fix the conditions for the `keepProfileChanges` configuration property on MacOS
* fix the sorting of Arrays in the Variables view

### Version 2.9.0
* add `tabFilter` configuration property
* open a new Firefox tab if no tab matches the `tabFilter`
* allow `stable`, `developer` and `nightly` as values for firefoxExecutable
* only suggest the Path Mapping Wizard if it can create a pathMapping
* debug protocol fix for Firefox 78

### Version 2.8.0
* debug protocol fix for Firefox 77
* add `tmpDir` configuration property
* fix for skipping external URLs containing a query string
* fixes for object previews

### Version 2.7.2
* debug protocol fixes for Firefox 76

### Version 2.7.1
* debug protocol fix for Firefox 75

### Version 2.7.0
* bugfix for breakpoints in Vue.js projects
* add default pathMappings for Next.js projects
* add support for wildcards in pathMappings
* add `suggestPathMappingWizard` configuration property
* various bugfixes

### Version 2.6.1
* fix for showing the launch configuration in a remote workspace
* fix for re-enabling a watchpoint

### Version 2.6.0
* add the Path Mapping Wizard
* extend the Loaded Scripts Explorer

### Version 2.5.5
* debug protocol fix for Firefox 72

### Version 2.5.4
* fix version detection for Firefox 72

### Version 2.5.3
* fix for create-react-app projects on Windows

### Version 2.5.2
* improve stepping performance
* fix for debugging a WebExtension in a workspace subfolder on Windows
* fix for debugging in a remote workspace on Windows

### Version 2.5.1
* fix removal of breakpoints from sourcemapped sources
* improved default `pathMappings` for Angular CLI projects
* sourcemapping accuracy improvements
* fix initialization of exception breakpoints

### Version 2.5.0
* performance improvement for setting breakpoints in bundled sources
* add support for the new column breakpoint UI introduced in VS Code 1.39
* remove support for Firefox <68

### Version 2.4.0
* add support for `console.clear()`
* add `clearConsoleOnReload` configuration property
* try to load sourcemaps from disk first
* fix WebExtension debugging in Firefox 71

### Version 2.3.4
* fix a performance issue when reloading the page in the browser

### Version 2.3.3
* fix for hot module replacement: when a module was replaced, breakpoints in that module stopped working
* fix for callstacks sometimes showing an error message "Couldn't find source adapter"

### Version 2.3.2
* fix support for data breakpoints with Firefox 70

### Version 2.3.1
* update README.md

### Version 2.3.0
* disable the prompt to configure telemetry in temporary debug profiles
* objects referenced in logpoints can now be inspected in the debug console
* add support for the BigInt primitive type

### Version 2.2.0
* add support for VS Code remote development
* add support for data breakpoints on object properties if Firefox supports watchpoints (an upcoming Firefox feature that will appear in Nightlies soon)

### Version 2.1.0
* add `timeout` launch configuration property

### Version 2.0.1
* build with babel and bundle with webpack - the resulting package is much smaller and loads faster
Version 2.0.1 was only released on npm

### Version 2.0.0
* branding updated - this extension is now an official Firefox DevTool!

### Version 1.8.3
* fix for launching Firefox on MacOS and some Linux distros
* increase the timeout for connecting to Firefox to 10 seconds and fix the handling of that timeout

### Version 1.8.2
* bugfix: globstars (`**`) in the skipFiles configuration didn't match path segments that contain `/./`
* bugfix: show the generated source location of a stack frame if it can't be mapped to an original source location
* bugfix: the debug adapter kept running after the end of the debug session until Firefox was closed

### Version 1.8.1
* bugfix: the temporary debug profile wasn't removed at the end of the debug session when using a recent Firefox version on Windows

### Version 1.8.0
* fix for Firefox 68
* remove support for legacy add-ons

### Version 1.7.11
* fix handling of case-insensitive paths on Windows when setting breakpoints
* add workaround for broken sourcemaps generated by create-react-app

### Version 1.7.10
* bugfix: sometimes the exception view wasn't shown
* further fixes for Firefox 67

### Version 1.7.9
* further fixes for Firefox 67

### Version 1.7.8
* fix for Firefox 66

### Version 1.7.7
* fix for debug protocol changes in Firefox 67

### Version 1.7.6
* fix for a debug protocol change in Firefox 66

### Version 1.7.5
* fix for sourcemaps in WebExtensions
* fix for `reAttach` on MacOS

### Version 1.7.4
* fix path mapping for configurations where `url` contains no path and no trailing slash (e.g. `"url": "http://localhost:8080"`)

### Version 1.7.3
* fix handling of relative sourceRoot in sourcemaps

### Version 1.7.2
* add log messages to monitor source-mapping performance

### Version 1.7.1
* WebExtension debugging: allow comments in manifest.json

### Version 1.7.0
* add the ability to override some launch configuration properties in the settings

### Version 1.6.0
* change the default for `sourceMaps` to `client`
* improve the performance of client-side source-map handling
* fix client-side source-map handling for source-maps with relative paths
* fix detection of Firefox Developer Edition on MacOS

### Version 1.5.0
* WebExtension debugging: add commands and status bar button for toggling popup auto-hide

### Version 1.4.3
* improve accuracy of client-side sourcemap support

### Version 1.4.2
* compute the original locations of console and error events when `sourceMaps` is set to `client`

### Version 1.4.1
* also look for `firefox-developer-edition` when searching the Firefox executable on Linux

### Version 1.4.0
* add `liftAccessorsFromPrototypes` configuration property

### Version 1.3.0
* allow WebExtensions without an ID if they're installed via RDP
* install WebExtensions via RDP by default

### Version 1.2.1
* fix `reloadOnChange` on Windows (thanks @Misiur)

### Version 1.2.0
* add support for breakpoints with hit counts
* add support for log points

### Version 1.1.4
* add support for evaluating getter functions
* fix path mapping of URLs that contain encoded characters

### Version 1.1.3
* path mapping bugfixes

### Version 1.1.2
* workaround for a timing issue with early beta versions of Firefox 60
* improve WebAssembly debugging support

### Version 1.1.1
* experimental support for WebAssembly debugging

### Version 1.1.0
* add support for creating `pathMappings` from the Loaded Scripts Explorer
* bugfix for breakpoints being shown unverified (gray) even when they were successfully set
* change default `pathMappings` for webpack to support Angular CLI projects

### Version 1.0.1
* fix debugging of WebExtensions that contain a `package.json` file
* set the default `addonType` to `webExtension` in configuration snippets and documentation

### Version 1.0.0
* add default `pathMappings` for webpack
* harmonize trailing slashes in user-specified `pathMappings`
* Linux: search the Firefox executable in all directories in the user's `PATH` (thanks @agathver)
* `addonType` now defaults to `webExtension`

### Version 0.17.0
* show object previews in the Variables and Watch sections of the Debug view
* fix the Loaded Scripts Explorer when navigating in Firefox

### Version 0.16.1
* fix opening remote scripts from the Loaded Scripts Explorer
* skip exceptions triggered from the debug console
* add the ability to configure URLs that should not be mapped to local paths
* remove deprecated VS Code APIs

### Version 0.16.0
* add Loaded Scripts Explorer
* add support for Symbol-keyed properties (Firefox 56+)

### Version 0.15.4
* bugfix: `pathMappings` were ignored in `attach` configurations

### Version 0.15.3
* performance improvements

### Version 0.15.2
* handle absolute urls in source-maps, including a workaround for webpack weirdness

### Version 0.15.1
* on Windows the debug adapter sometimes didn't attach to WebExtensions that were installed as temporary add-ons - fixed

### Version 0.15.0
* add support for toggling the skip flag for single files while debugging
* make `webRoot` optional if `pathMappings` are specified

### Version 0.14.1
* compatibility update for the upcoming VS Code 1.14 release
 
### Version 0.14.0
* fix WebExtension debugging in recent Firefox builds
* add experimental `sourceMaps` configuration property

### Version 0.13.1
* add support for setting variable values in the debug side bar
* add support for IntelliSense in the debug console

### Version 0.13.0
* add `reloadOnChange` configuration property

### Version 0.12.1
* fix temporary add-on installation on Windows

### Version 0.12.0
* add support for reloading add-ons
* add `installAddonInProfile` configuration property

### Version 0.11.1
* bugfix: some function names were not shown in the call stack
* bugfix: the tooltips of tabs for external source files didn't show the full url
* bugfix: some accessor properties (e.g. window.window) were shown as undefined
* bugfix for sporadical failures to attach to Firefox after launching it

### Version 0.11.0
* add `keepProfileChanges` configuration property
* bugfix: the temporary profiles are now deleted reliably

### Version 0.10.0
* add `preferences` configuration property
* add `showConsoleCallLocation` configuration property
* support sending objects to the console (e.g. `console.log(document)`)
* change the display of call stack, return values and exceptions to be more in line with other VS Code javascript debuggers

### Version 0.9.3
* fix slow initial startup of add-on debugging with the `reAttach` option

### Version 0.9.2
* support `reAttach` for add-on debugging

### Version 0.9.1
* fix `reAttach` on Windows

### Version 0.9.0
* Add `reAttach` and `reloadOnAttach` configuration properties

### Version 0.8.8
* bugfix: source files were not mapped to local files in VS Code 1.9

### Version 0.8.7
* workaround for Firefox sending inaccurate source information in certain situations, which can break the `skipFiles` feature

### Version 0.8.6
* bugfix: some URLs were not handled correctly when processing sourcemapped sources

### Version 0.8.5
* send log messages from add-ons to the debug console

### Version 0.8.4
* bugfix: exceptions were not shown

### Version 0.8.3
* strip query strings from urls when converting them to local file paths

### Version 0.8.2
* fix skipFiles on Windows

### Version 0.8.1
* bugfix: sources could not be skipped during their first execution

### Version 0.8.0
* Add `skipFiles` configuration property
* Add `pathMappings` configuration property
* Add configuration snippets
* Fix several bugs when evaluating watches and expressions entered in the debug console

### Version 0.7.7
* fix debugging of WebExtension content scripts in recent Firefox builds

### Version 0.7.6
* bugfix: breakpoints were sometimes not hit after a page reload

### Version 0.7.5
* bugfix: support javascript values of type Symbol
* bugfix: evaluating expressions in the VS Code debug console sometimes stopped working

### Version 0.7.2
* Terminate the debug session when Firefox is closed

### Version 0.7.1
* Show the full url of sources that do not correspond to local files
* bugfix for setting breakpoints in content scripts of `addonSdk` browser extensions

### Version 0.7.0
* Debugging Firefox add-ons
* Launch mode now always creates a temporary profile: if a profile is specified in the launch
  configuration, it will be copied and modified to allow remote debugging
* Launch mode now uses the developer edition of Firefox if it is found

### Version 0.6.5
* bugfix for sourcemaps with embedded source files

### Version 0.6.4
* Fix breakpoint handling when a Firefox tab is reloaded
* Only send javascript-related warnings and errors from Firefox to the debug console

### Version 0.6.3
* Add configuration option for diagnostic logging
* Make conversion between paths and urls more robust

### Version 0.6.2
* bugfix: stepping and resuming stopped working if a breakpoint was hit immediately after loading the page

### Version 0.6.1
* Fix debugging WebWorkers and multiple browser tabs in VSCode 1.2.0

### Version 0.6.0
* Add support for evaluating javascript expressions in the debug console even if Firefox isn't paused
* Add support for debugger statements

### Version 0.5.0
* Add support for call stack paging

### Version 0.4.0
* Add support for debugging WebWorkers
* Add support for debugging multiple browser tabs
* Fix exception breakpoints in VSCode 1.1.0
* Re-create the Firefox profile on every launch, unless a profile name or directory is configured

### Version 0.3.0
* Print messages from the Firefox console in the VS Code debug console
* bugfix: resume the VS Code debugger when Firefox resumes, e.g. if the user reloads the page in 
  Firefox while the debugger is paused

### Version 0.2.0
* Automatically create a Firefox profile for debugging

### Version 0.1.0
* Initial release


================================================
FILE: CODE_OF_CONDUCT.md
================================================
## Mozilla Community Participation Guidelines

This repository is governed by Mozilla's code of conduct and etiquette guidelines. 
For more details, please read the
[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 

## How to Report
For more information on how to report violations of the CPG, please read our '[How to Report](https://www.mozilla.org/en-US/about/governance/policies/participation/reporting/)' page.

## Project Specific Etiquette

### Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

Project maintainers who do not follow or enforce Mozilla's Participation Guidelines in good
faith may face temporary or permanent repercussions.


================================================
FILE: CONTRIBUTING.md
================================================
# Hacking the VS Code Debug Adapter for Firefox

## Prerequisites
First of all, you should familiarize yourself with the
[debugging architecture of VS Code](https://code.visualstudio.com/api/extension-guides/debugger-extension#debugging-architecture-of-vs-code)
and the [Firefox Remote Debugging Protocol](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md).

## Setup
* fork and clone this repository and open it in VS Code
* run `npm install`
* run `npm run watch` or start the `watch` task in VS Code
* optional but recommended: run `npm run typecheck-watch` or start the `typecheck-watch` task in VS Code

Most source folders contain a `README` file giving an overview of the contained code.
Start with the [top-level README](./src).

## Debugging
This repository contains several launch configurations for debugging different parts of the code:
* to debug the debug adapter itself (i.e. the code under `src/adapter/`), use the `debug server`
  configuration to start it as a stand-alone server in the node debugger. Then open a web application
  in a second VS Code window and add a launch configuration of type `firefox` to it. Add
  `"debugServer": 4711` to this launch configuration, so that VS Code will use the debug adapter
  that you just launched in the other VS Code window. Set a breakpoint in the `startSession()` of 
  [`FirefoxDebugAdapter`](./src/adapter/firefoxDebugAdapter.ts) and start debugging the web application.
* to debug the extension code (under `src/extension/`), use the `extension host` configuration.
  It will open a second VS Code window with the extension in it running in the node debugger.
* the compound configuration `server & extension` will launch both of the configurations above
* the `web test` and `webextension test` configurations can be used if you need to manually
  reproduce the mocha tests. You'll need to start the `debug server` configuration first.


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015-2017 Holger Benl <hbenl@evandor.de>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<h1 align="center">
  <br>
    <img src="https://github.com/firefox-devtools/vscode-firefox-debug/blob/master/icon.png?raw=true" alt="logo" width="200">
  <br>
  VS Code Debugger for Firefox
  <br>
  <br>
</h1>

<h4 align="center">Debug your JavaScript code running in Firefox from VS Code.</h4>

<p align="center">
  <a href="https://marketplace.visualstudio.com/items?itemName=firefox-devtools.vscode-firefox-debug"><img src="https://vsmarketplacebadges.dev/version/firefox-devtools.vscode-firefox-debug.png?label=Debugger%20for%20Firefox" alt="Marketplace badge"></a>
</p>

A VS Code extension to debug web applications and extensions running in the [Mozilla Firefox browser](https://www.mozilla.org/en-US/firefox/developer/?utm_medium=vscode_extension&utm_source=devtools). [📦 Install from VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=firefox-devtools.vscode-firefox-debug).

### Supported features

* Pause [breakpoints](https://code.visualstudio.com/docs/editor/debugging#_breakpoints), including advanced [conditional](https://code.visualstudio.com/docs/editor/debugging#_conditional-breakpoints) and [inline](https://code.visualstudio.com/docs/editor/debugging#_inline-breakpoints) modes
* Pause on object property changes with [Data breakpoints](https://code.visualstudio.com/docs/editor/debugging#_data-breakpoints)
* Inject logging during debugging using [logpoints](https://code.visualstudio.com/docs/editor/debugging#_logpoints)
* Debugging eval scripts, script tags, and scripts that are added dynamically and/or source mapped
* *Variables* pane for inspecting and setting values
* *Watch* pane for evaluating and watching expressions
* *Console* for logging and REPL
* Debugging Firefox extensions
* Debugging Web Workers
* Compatible with [remote development](https://code.visualstudio.com/docs/remote/remote-overview)

## Getting Started

You can use this extension in **launch** or **attach** mode.

In **launch** mode it will start an instance of Firefox navigated to the start page of your application
and terminate it when you stop debugging. You can also set the `reAttach` option in your launch configuration to `true`, in this case Firefox won't be terminated at the end of your debugging session and the debugger will re-attach to it when
you start the next debugging session - this is a lot faster than restarting Firefox every time. `reAttach` also works for WebExtension debugging: in this case, the WebExtension is (re-)installed as a [temporary add-on](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox).

In **attach** mode the extension connects to a running instance of Firefox (which must be manually
configured to allow remote debugging - see [below](#attach)).

To configure these modes you must create a file `.vscode/launch.json` in the root directory of your
project. You can do so manually or let VS Code create an example configuration for you by clicking 
the gear icon at the top of the Debug pane.

Finally, if `.vscode/launch.json` already exists in your project, you can open it and add a 
configuration snippet to it using the *"Add Configuration"* button in the lower right corner of the
editor.

### Launch
Here's an example configuration for launching Firefox navigated to the local file `index.html` 
in the root directory of your project:
```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch index.html",
            "type": "firefox",
            "request": "launch",
            "reAttach": true,
            "file": "${workspaceFolder}/index.html"
        }
    ]
}
```

You may want (or need) to debug your application running on a Webserver (especially if it interacts
with server-side components like Webservices). In this case replace the `file` property in your
`launch` configuration with a `url` and a `webRoot` property. These properties are used to map
urls to local files:
```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch localhost",
            "type": "firefox",
            "request": "launch",
            "reAttach": true,
            "url": "http://localhost/index.html",
            "webRoot": "${workspaceFolder}"
        }
    ]
}
```
The `url` property may point to a file or a directory, if it points to a directory it must end with
a trailing `/` (e.g. `http://localhost/my-app/`).
You may omit the `webRoot` property if you specify the `pathMappings` manually. For example, the
above configuration would be equivalent to
```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch localhost",
            "type": "firefox",
            "request": "launch",
            "reAttach": true,
            "url": "http://localhost/index.html",
            "pathMappings": [{
                "url": "http://localhost",
                "path": "${workspaceFolder}"
            }]
        }
    ]
}
```
Setting the `pathMappings` manually becomes necessary if the `url` points to a file or resource in a
subdirectory of your project, e.g. `http://localhost/login/index.html`.

### Attach
To use attach mode, you have to launch Firefox manually from a terminal with remote debugging enabled.
Note that if you don't use Firefox Developer Edition, you must first configure Firefox to allow
remote debugging. To do this, open the Developer Tools Settings and check the checkboxes labeled
"Enable browser chrome and add-on debugging toolboxes" and "Enable remote debugging"
(as described [here](https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Debugging_Firefox_Desktop#Enable_remote_debugging)).
Alternatively you can set the following values in `about:config`:

Preference Name                       | Value   | Comment
--------------------------------------|---------|---------
`devtools.debugger.remote-enabled`    | `true`  | Required
`devtools.chrome.enabled`             | `true`  | Required
`devtools.debugger.prompt-connection` | `false` | Recommended
`devtools.debugger.force-local`       | `false` | Set this only if you want to attach VS Code to Firefox running on a different machine (using the `host` property in the `attach` configuration)

Then close Firefox and start it from a terminal like this:

__Windows__

`"C:\Program Files\Mozilla Firefox\firefox.exe" -start-debugger-server`

(This syntax is for a regular command prompt (cmd.exe), not PowerShell!)

__OS X__

`/Applications/Firefox.app/Contents/MacOS/firefox -start-debugger-server`

__Linux__

`firefox -start-debugger-server`

Navigate to your web application and use this `launch.json` configuration to attach to Firefox:
```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch index.html",
            "type": "firefox",
            "request": "attach"
        }
    ]
}
```

If your application is running on a Webserver, you need to add the `url` and `webRoot` properties
to the configuration (as in the second `launch` configuration example above).

### Skipping ("blackboxing") files
You can tell the debugger to ignore certain files while debugging: When a file is ignored, the
debugger won't break in that file and will skip it when you're stepping through your code. This is
the same as "black boxing" scripts in the Firefox Developer Tools.

There are two ways to enable this feature:
* You can enable/disable this for single files while debugging by choosing "Toggle skipping this file"
  from the context menu of a frame in the call stack.
* You can use the `skipFiles` configuration property, which takes an array of glob patterns
  specifying the files to be ignored.
  If the URL of a file can't be mapped to a local file path, the URL will be matched against these
  glob patterns, otherwise the local file path will be matched.
  Examples for glob patterns:
  * `"${workspaceFolder}/skipThis.js"` - will skip the file `skipThis.js` in the root folder of your project
  * `"**/skipThis.js"` - will skip files called `skipThis.js` in any folder
  * `"**/node_modules/**"` - will skip all files in `node_modules` folders anywhere in the project
  * `"http?(s):/**"` - will skip files that could not be mapped to local files
  * `"**/google.com/**"` - will skip files containing `/google.com/` in their url, in particular
    all files from the domain `google.com` (that could not be mapped to local files)

### Path mapping
The debug adapter needs to map the URLs of javascript files (as seen by Firefox) to local file paths
(as seen by VS Code). It creates a set of default path mappings from the configuration that work
for most projects. However, depending on the setup of your project, they may not work for you,
resulting in breakpoints being shown in gray (and Firefox not breaking on them) even after Firefox
has loaded the corresponding file. In this case, you will have to define them manually using the
`pathMappings` configuration property.

The easiest way to do this is through the Path Mapping Wizard: when you try to set a breakpoint 
during a debug session in a file that couldn't be mapped to a URL, the debug adapter will offer to
automatically create a path mapping for you. If you click "Yes" it will analyze the URLs loaded by
Firefox and try to find a path mapping that maps this file and as many other workspace files as
possible to URLs loaded by Firefox and it will add this mapping to your debug configuration.
Note that this path mapping is just a guess, so you should check if it looks plausible to you.
You can also call the Path Mapping Wizard from the command palette during a debug session.

You can look at the Firefox URLs and how they are mapped to paths in the Loaded Scripts Explorer,
which appears at the bottom of the debug side bar of VS Code during a debug session.
By choosing "Map to local file" or "Map to local directory" from the context menu of a file or
a directory, you can pick the corresponding local file or directory and a path mapping will
automatically be added to your configuration.

If you specify more than one mapping, the first mappings in the list will take precedence over
subsequent ones and all of them will take precedence over the default mappings.

The most common source of path mapping problems is webpack because the URLs that it generates
depend on its configuration and different URL styles are in use. If your configuration contains a
`webroot` property, the following mappings will be added by default in order to support most webpack
setups:
```
{ "url": "webpack:///~/", "path": "${webRoot}/node_modules/" }
{ "url": "webpack:///./~/", "path": "${webRoot}/node_modules/" }
{ "url": "webpack:///./", "path": "${webRoot}/" }
{ "url": "webpack:///src/", "path": "${webRoot}/src/" }
{ "url": "webpack:///node_modules/", "path": "${webRoot}/node_modules/" }
{ "url": "webpack:///webpack", "path": null }
{ "url": "webpack:///(webpack)", "path": null }
{ "url": "webpack:///pages/", "path": "${webRoot}/pages/" }
{ "url": "webpack://[name]_[chunkhash]/node_modules/", "path": "${webRoot}/node_modules/" }
{ "url": "webpack://[name]_[chunkhash]/", "path": null }
{ "url": "webpack:///", "path": "" }
```

When the `path` argument of a mapping is set to `null`, the corresponding URLs are prevented from
being mapped to local files. In the webpack mappings shown above this is used to specify that
URLs starting with `webpack:///webpack` or `webpack:///(webpack)` do not correspond to files in
your workspace (because they are dynamically generated by webpack). It could also be used for URLs
that dynamically generate their content on the server (e.g. PHP scripts) or if the content on the
server is different from the local file content. For these URLs the debugger will show the content
fetched from the server instead of the local file content.

You can also use `*` as a wildcard in the `url` of a pathMapping. It will match any number of
arbitrary characters except `/`.

### Debugging WebExtensions
Here's an example configuration for WebExtension debugging:
```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch WebExtension",
            "type": "firefox",
            "request": "launch",
            "reAttach": true,
            "addonPath": "${workspaceFolder}"
        }
    ]
}
```
The `addonPath` property must be the absolute path to the directory containing `manifest.json`.

You can reload your WebExtension using the command "Firefox: Reload add-on" (`extension.firefox.reloadAddon`)
from the VS Code command palette.
The WebExtension will also be reloaded when you restart the debugging session, unless you have set
`reloadOnAttach` to `false`.
You can also use the `reloadOnChange` property to let VS Code reload your WebExtension automatically
whenever you change a file.

You can enable/disable/toggle popup auto-hide using the commands "Firefox: Enable/Disable/Toggle
popup auto-hide" (`extension.firefox.enablePopupAutohide` / `disablePopupAutohide` / `togglePopupAutohide`).

### Further optional configuration properties
* `reAttach`: If you set this option to `true` in a `launch` configuration, Firefox won't be 
  terminated at the end of your debugging session and the debugger will re-attach to it at the
  start of your next debugging session.
* `reloadOnAttach`: This flag controls whether the web page(s) should be automatically reloaded
  after attaching to Firefox. The default is to reload in a `launch` configuration with the
  `reAttach` flag set to `true` and to not reload in an `attach` configuration.
* `reloadOnChange`: Automatically reload the Firefox tabs or your WebExtension whenever files change.
  You can specify single files, directories or glob patterns to watch for file changes and
  additionally specify files to be ignored. Since watching files consumes system resources,
  make sure that you are not watching more files than necessary.
  The following example will watch all javascript files in your workspace except those under
  `node_modules`:
  ```json
    "reloadOnChange": {
        "watch": [ "${workspaceFolder}/**/*.js" ],
        "ignore": [ "${workspaceFolder}/node_modules/**" ]
    }
  ```
  By default, the reloading will be "debounced": the debug adapter will wait until the last file
  change was 100 milliseconds ago before reloading. This is useful if your project uses a build
  system that generates multiple files - without debouncing, each file would trigger a separate
  reload. You can use `reloadOnChange.debounce` to change the debounce time span or to disable
  debouncing (by setting it to `0` or `false`).

  Instead of string arrays, you can also use a single string for `watch` and `ignore` and if you
  don't need to specify `ignore` or `debounce`, you can specify the `watch` value directly, e.g.
  ```json
  "reloadOnChange": "${workspaceFolder}/lib/*.js"
  ```
* `tabFilter`: Only attach to Firefox tabs with matching URLs. You can specify one or more URLs to
  include and/or URLs to exclude and the URLs can contain `*` wildcards.
  By default, a `tabFilter` is constructed from the `url` in your `launch` or `attach` configuration
  by replacing the last path segment with `*`. For example, if your configuration contains
  `"url": "http://localhost:3000/app/index.html"`, the default `tabFilter` will be
  `"http://localhost:3000/app/*"`.
* `clearConsoleOnReload`: Clear the debug console in VS Code when the page is reloaded in Firefox.
* `tmpDir`: The path of the directory to use for temporary files
* `profileDir`, `profile`: You can specify a Firefox profile directory or the name of a profile
  created with the Firefox profile manager. The extension will create a copy of this profile in the
  system's temporary directory and modify the settings in this copy to allow remote debugging.
  You can also override these properties in your settings (see below). The default profile names
  used by Firefox are `default`, `dev-edition-default` and `default-nightly` for the stable,
  developer and nightly editions, respectively.
* `keepProfileChanges`: Use the specified profile directly instead of creating a temporary copy.
  Since this profile will be permanently modified for debugging, you should only use this option
  with a dedicated debugging profile. You can also override this property in your settings (see below).
* `port`: Firefox uses port 6000 for the debugger protocol by default. If you want to use a different
  port, you can set it with this property. You can also override this property in your settings
  (see below).
* `timeout`: The timeout in seconds for the adapter to connect to Firefox after launching it.
* `firefoxExecutable`: The absolute path to the Firefox executable or the name of a Firefox edition
  (`stable`, `developer` or `nightly`) to look for in its default installation path. If not specified,
  this extension will look for both stable and developer editions of Firefox; if both are available,
  it will use the developer edition. You can also override this property in your settings (see below).
* `firefoxArgs`: An array of additional arguments used when launching Firefox (`launch` configuration only).
  You can also override this property in your settings (see below).
* `host`: If you want to debug with Firefox running on a different machine, you can specify the 
  device's address using this property (`attach` configuration only).
* `log`: Configures diagnostic logging for this extension. This may be useful for troubleshooting
  (see below for examples).
* `showConsoleCallLocation`: Set this option to `true` to append the source location of `console`
  calls to their output
* `preferences`: Set additional Firefox preferences in the debugging profile
* `popupAutohideButton`: Show a button in the status bar for toggling popup auto-hide
  (enabled by default when debugging a WebExtension)
* `liftAccessorsFromPrototypes`: If there are accessor properties (getters and setters) defined
  on an object's prototype chain, you can "lift" them so they are displayed on the object itself.
  This is usually necessary in order to execute the getters, because otherwise they would be
  executed with `this` set to the object's prototype instead of the object itself. This property
  lets you set the number of prototype levels that should be scanned for accessor properties to lift.
  Note that this will slow the debugger down, so it's set to `0` by default.
* `pathMappingIndex`: The name of the directory index file configured in the webserver, defaults
  to `index.html`. This will be appended to all URLs pointing to a directory (i.e. URLs ending
  with `/`) before trying to map them to file paths.
* `suggestPathMappingWizard`: Suggest using the Path Mapping Wizard when you try to set a
  breakpoint in an unmapped source during a debug session. You may want to turn this off if some
  of the sources in your project are loaded on-demand (e.g. if you create multiple bundles with
  webpack and some of these bundles are only loaded as needed).
* `enableCRAWorkaround`: Enable a workaround for facebook/create-react-app#6074: Adding/removing
  breakpoints doesn't work for sources that were changed after the dev-server was started

### Overriding configuration properties in your settings
You can override some of the `launch.json` configuration properties in your user, workspace or
folder settings. This can be useful to make machine-specific changes to your launch configuration
without sharing them with other users.

This setting                 | overrides this `launch.json` property
-----------------------------|-------------------------------------
`firefox.executable`         | `firefoxExecutable`
`firefox.args`               | `firefoxArgs`
`firefox.profileDir`         | `profileDir`
`firefox.profile`            | `profile`
`firefox.keepProfileChanges` | `keepProfileChanges`
`firefox.port`               | `port`

### Diagnostic logging
The following example for the `log` property will write all log messages to the file `log.txt` in
your workspace:
```json
...
    "log": {
        "fileName": "${workspaceFolder}/log.txt",
        "fileLevel": {
            "default": "Debug"
        }
    }
...
```

This example will write all messages about conversions from URLs to paths and all error messages
to the VS Code console:
```json
...
    "log": {
        "consoleLevel": {
            "PathConversion": "Debug",
            "default": "Error"
        }
    }
...
```
 
## Troubleshooting
* Breakpoints that should get hit immediately after the javascript file is loaded may not work the
  first time: You will have to click "Reload" in Firefox for the debugger to stop at such a
  breakpoint. This is a weakness of the Firefox debug protocol: VS Code can't tell Firefox about
  breakpoints in a file before the execution of that file starts.
* If your breakpoints remain unverified after launching the debugger (i.e. they appear gray instead
  of red), the conversion between file paths and urls may not work. The messages from the 
  `PathConversion` logger may contain clues how to fix your configuration. Have a look at the 
  "Diagnostic Logging" section for an example how to enable this logger.
* If you think you've found a bug in this adapter please [file a bug report](https://github.com/firefox-devtools/vscode-firefox-debug/issues).
  It may be helpful if you create a log file (as described in the "Diagnostic Logging" section) and
  attach it to the bug report.


================================================
FILE: dist/README.md
================================================
# Debug Adapter for Firefox

This package implements the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/) for Firefox.
It is part of the [VS Code Debugger for Firefox](https://marketplace.visualstudio.com/items?itemName=firefox-devtools.vscode-firefox-debug) but can be used by other IDEs as well to integrate with Firefox's debugger.

## Custom requests and events

In addition to the standard Debug Adapter Protocol, the debug adapter implements some custom requests and events:

### Requests

The following custom requests can be sent to the debug adapter:

* `toggleSkippingFile` : toggle whether a particular file (identified by its URL) is skipped (aka blackboxed) during debugging
* `reloadAddon` : reload the WebExtension that is being debugged
* `setPopupAutohide` : set the popup auto-hide flag (config key `ui.popup.disable_autohide`, WebExtension debugging only)
* `togglePopupAutohide` : toggle the popup auto-hide flag
* `setActiveEventBreakpoints` : set event listener breakpoints

### Events

The debug adapter sends these custom events:

* `popupAutohide` : contains the initial state of the popup auto-hide flag (WebExtension debugging only)
* `threadStarted` : sent when a thread-like actor (for a Tab, Worker or WebExtension) is started
* `threadExited` : sent when a thread-like actor exited
* `newSource` : sent when Firefox loaded a new source file
* `removeSources` : sent when a thread-like actor discards its previously loaded sources, i.e. when a Tab is navigated to a new URL
* `unknownSource` : sent when the user tries to set a breakpoint in a file that could not be mapped to a URL loaded by Firefox
* `availableEvents` : contains the events for which event listener breakpoints can be set

The event body types are defined [here](../src/common/customEvents.ts).
The source events may be replaced by the [LoadedSourceEvent](https://microsoft.github.io/debug-adapter-protocol/specification#Events_LoadedSource) in the future.


================================================
FILE: dist/package.json
================================================
{
  "name": "firefox-debugadapter",
  "version": "2.15.0",
  "author": "Holger Benl <hbenl@evandor.de>",
  "description": "Debug adapter for Firefox",
  "files": [
    "adapter.bundle.js",
    "launcher.bundle.js",
    "mappings.wasm",
    "terminator/*",
    "README.md",
    "LICENSE"
  ],
  "main": "adapter.bundle.js",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/firefox-devtools/vscode-firefox-debug.git"
  },
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/firefox-devtools/vscode-firefox-debug/issues"
  },
  "homepage": "https://github.com/firefox-devtools/vscode-firefox-debug"
}


================================================
FILE: dist/terminator/main.js
================================================
browser.windows.getAll().then((windows) => {
	for (const window of windows) {
		browser.windows.remove(window.id);
	}
});


================================================
FILE: dist/terminator/manifest.json
================================================
{
	"description": "A WebExtension that terminates Firefox by closing all its windows",
	"manifest_version": 2,
	"name": "Terminator",
	"version": "1.0",
	"homepage_url": "https://github.com/firefox-devtools/vscode-firefox-debug",
	"applications": {
		"gecko": {
			"id": "{5b498dbd-f841-423d-9e46-a735486a0eb7}"
		}
	},
	"background": {
		"scripts": [
			"main.js"
		]
	}
}


================================================
FILE: package.json
================================================
{
  "name": "vscode-firefox-debug",
  "displayName": "Debugger for Firefox",
  "version": "2.15.0",
  "author": "Holger Benl <hbenl@evandor.de>",
  "publisher": "firefox-devtools",
  "description": "Debug your web application or browser extension in Firefox",
  "icon": "icon.png",
  "engines": {
    "vscode": "^1.80.0"
  },
  "categories": [
    "Debuggers"
  ],
  "scripts": {
    "reinstall": "rimraf node_modules package-lock.json && npm install",
    "clean": "rimraf dist/*.bundle.js dist/*.bundle.js.map dist/mappings.wasm coverage .nyc_output vscode-firefox-debug-*.vsix",
    "build": "webpack --mode=production",
    "watch": "webpack --watch --mode=development",
    "rebuild": "npm run clean && npm run build",
    "typecheck": "tsc",
    "typecheck-watch": "tsc -w",
    "test": "mocha",
    "cover": "nyc npm test && nyc report --reporter=lcov && nyc report --reporter=html",
    "package": "vsce package",
    "publish": "npm run rebuild && vsce publish",
    "package-npm": "cd dist && npm pack",
    "publish-npm": "npm run rebuild && cd dist && npm publish"
  },
  "dependencies": {
    "@babel/polyfill": "^7.12.1",
    "@vscode/debugadapter": "^1.68.0",
    "chokidar": "^3.6.0",
    "core-js": "^3.39.0",
    "data-uri-to-buffer": "3.0.1",
    "debounce": "^2.2.0",
    "escape-string-regexp": "4.0.0",
    "file-uri-to-path": "^2.0.0",
    "file-url": "^4.0.0",
    "firefox-profile": "^4.7.0",
    "fs-extra": "^11.2.0",
    "is-absolute-url": "3.0.3",
    "minimatch": "^9.0.5",
    "source-map": "^0.7.4",
    "strip-json-comments": "3.1.1",
    "uuid": "^11.0.3",
    "vscode-uri": "^3.0.8"
  },
  "devDependencies": {
    "@babel/cli": "^7.26.4",
    "@babel/core": "^7.26.0",
    "@babel/plugin-proposal-class-properties": "^7.18.6",
    "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
    "@babel/preset-env": "^7.26.0",
    "@babel/preset-typescript": "^7.26.0",
    "@gulp-sourcemaps/map-sources": "^1.0.0",
    "@types/debounce": "^1.2.4",
    "@types/fs-extra": "^11.0.4",
    "@types/gulp": "^4.0.17",
    "@types/gulp-concat": "^0.0.37",
    "@types/gulp-rename": "^2.0.6",
    "@types/gulp-sourcemaps": "^0.0.38",
    "@types/gulp-uglify": "^3.0.11",
    "@types/mocha": "^10.0.10",
    "@types/node": "^16.18.122",
    "@types/vscode": "~1.80.0",
    "@vscode/debugadapter-testsupport": "^1.68.0",
    "babel-loader": "^9.2.1",
    "copy-webpack-plugin": "^12.0.2",
    "dotenv": "^16.4.7",
    "gulp": "^5.0.0",
    "gulp-concat": "^2.6.1",
    "gulp-nop": "0.0.3",
    "gulp-rename": "^2.0.0",
    "gulp-sourcemaps": "^3.0.0",
    "gulp-uglify": "^3.0.2",
    "mocha": "^11.0.1",
    "nyc": "^17.1.0",
    "original-fs": "^1.2.0",
    "rimraf": "^6.0.1",
    "terser-webpack-plugin": "^5.3.11",
    "ts-node": "^10.9.2",
    "typescript": "^5.7.2",
    "vsce": "^2.15.0",
    "webpack": "^5.97.1",
    "webpack-cli": "^5.1.4"
  },
  "babel": {
    "presets": [
      "@babel/typescript",
      [
        "@babel/env",
        {
          "modules": false,
          "useBuiltIns": "usage",
          "corejs": 3
        }
      ]
    ],
    "plugins": [
      "@babel/proposal-class-properties",
      "@babel/proposal-object-rest-spread"
    ]
  },
  "browserslist": [
    "node 8"
  ],
  "nyc": {
    "include": [
      "out/**/*.js"
    ],
    "exclude": [
      "out/test/**/*.js"
    ]
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/firefox-devtools/vscode-firefox-debug.git"
  },
  "keywords": [
    "vscode",
    "firefox",
    "debug"
  ],
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/firefox-devtools/vscode-firefox-debug/issues"
  },
  "homepage": "https://github.com/firefox-devtools/vscode-firefox-debug",
  "extensionKind": [
    "ui"
  ],
  "main": "./dist/extension.bundle.js",
  "activationEvents": [
    "onDebug"
  ],
  "contributes": {
    "commands": [
      {
        "command": "extension.firefox.reloadAddon",
        "title": "Firefox: Reload add-on"
      },
      {
        "command": "extension.firefox.toggleSkippingFile",
        "title": "Toggle skipping this file"
      },
      {
        "command": "extension.firefox.openScript",
        "title": "Open script"
      },
      {
        "command": "extension.firefox.addPathMapping",
        "title": "Map to local directory"
      },
      {
        "command": "extension.firefox.addFilePathMapping",
        "title": "Map to local file"
      },
      {
        "command": "extension.firefox.addNullPathMapping",
        "title": "Don't map this directory"
      },
      {
        "command": "extension.firefox.addNullFilePathMapping",
        "title": "Don't map this file"
      },
      {
        "command": "extension.firefox.enablePopupAutohide",
        "title": "Firefox: Enable popup auto-hide"
      },
      {
        "command": "extension.firefox.disablePopupAutohide",
        "title": "Firefox: Disable popup auto-hide"
      },
      {
        "command": "extension.firefox.togglePopupAutohide",
        "title": "Firefox: Toggle popup auto-hide"
      },
      {
        "command": "extension.firefox.pathMappingWizard",
        "title": "Firefox: Run the path mapping wizard"
      }
    ],
    "menus": {
      "debug/callstack/context": [
        {
          "command": "extension.firefox.toggleSkippingFile",
          "when": "inDebugMode && debugType == 'firefox' && callStackItemType == 'stackFrame'"
        }
      ],
      "view/item/context": [
        {
          "command": "extension.firefox.addPathMapping",
          "group": "addPathMapping@1",
          "when": "view == extension.firefox.loadedScripts && viewItem == directory"
        },
        {
          "command": "extension.firefox.addFilePathMapping",
          "group": "addPathMapping@1",
          "when": "view == extension.firefox.loadedScripts && viewItem == file"
        },
        {
          "command": "extension.firefox.addNullPathMapping",
          "group": "addPathMapping@2",
          "when": "view == extension.firefox.loadedScripts && viewItem == directory"
        },
        {
          "command": "extension.firefox.addNullFilePathMapping",
          "group": "addPathMapping@2",
          "when": "view == extension.firefox.loadedScripts && viewItem == file"
        }
      ],
      "commandPalette": [
        {
          "command": "extension.firefox.pathMappingWizard",
          "when": "editorIsOpen && inDebugMode && debugType == 'firefox'"
        },
        {
          "command": "extension.firefox.toggleSkippingFile",
          "when": "false"
        },
        {
          "command": "extension.firefox.openScript",
          "when": "false"
        },
        {
          "command": "extension.firefox.addPathMapping",
          "when": "false"
        },
        {
          "command": "extension.firefox.addFilePathMapping",
          "when": "false"
        },
        {
          "command": "extension.firefox.addNullPathMapping",
          "when": "false"
        },
        {
          "command": "extension.firefox.addNullFilePathMapping",
          "when": "false"
        }
      ]
    },
    "configuration": {
      "title": "Firefox debug",
      "properties": {
        "firefox.executable": {
          "description": "Absolute path to the Firefox executable",
          "type": "string",
          "scope": "resource"
        },
        "firefox.args": {
          "description": "Additional arguments passed to Firefox",
          "type": "array",
          "items": {
            "type": "string"
          },
          "scope": "resource"
        },
        "firefox.profileDir": {
          "description": "The path of the Firefox profile directory to use",
          "type": "string",
          "scope": "resource"
        },
        "firefox.profile": {
          "description": "The name of the Firefox profile to use",
          "type": "string",
          "scope": "resource"
        },
        "firefox.keepProfileChanges": {
          "description": "Use the specified profile directly instead of a temporary copy",
          "type": "boolean",
          "scope": "resource"
        },
        "firefox.port": {
          "description": "The remote debugging port to use",
          "type": "number",
          "scope": "resource"
        }
      }
    },
    "views": {
      "debug": [
        {
          "id": "extension.firefox.loadedScripts",
          "name": "Loaded Scripts",
          "when": "inDebugMode && debugType == 'firefox'"
        },
        {
          "id": "extension.firefox.eventBreakpoints",
          "name": "Event Listener Breakpoints",
          "when": "inDebugMode && debugType == 'firefox'"
        }
      ]
    },
    "debuggers": [
      {
        "type": "firefox",
        "label": "Firefox",
        "program": "./dist/adapter.bundle.js",
        "runtime": "node",
        "languages": [
          "html"
        ],
        "initialConfigurations": [
          {
            "name": "Launch index.html",
            "type": "firefox",
            "request": "launch",
            "reAttach": true,
            "file": "${workspaceFolder}/index.html"
          },
          {
            "name": "Launch localhost",
            "type": "firefox",
            "request": "launch",
            "reAttach": true,
            "url": "http://localhost/index.html",
            "webRoot": "${workspaceFolder}"
          },
          {
            "name": "Attach",
            "type": "firefox",
            "request": "attach"
          },
          {
            "name": "Launch WebExtension",
            "type": "firefox",
            "request": "launch",
            "reAttach": true,
            "addonPath": "${workspaceFolder}"
          }
        ],
        "configurationSnippets": [
          {
            "label": "Firefox: Launch (file)",
            "description": "Launch Firefox navigated to a local file in your project",
            "body": {
              "type": "firefox",
              "request": "launch",
              "reAttach": true,
              "name": "${1:Launch index.html}",
              "file": "^\"\\${workspaceFolder}/${2:index.html}\""
            }
          },
          {
            "label": "Firefox: Launch (server)",
            "description": "Launch Firefox navigated to your project running on a server",
            "body": {
              "type": "firefox",
              "request": "launch",
              "reAttach": true,
              "name": "${1:Launch localhost}",
              "url": "${2:http://localhost/index.html}",
              "webRoot": "^\"\\${workspaceFolder}${3:}\""
            }
          },
          {
            "label": "Firefox: Attach",
            "description": "Attach to a running Firefox process",
            "body": {
              "type": "firefox",
              "request": "attach",
              "name": "${1:Attach}"
            }
          },
          {
            "label": "Firefox: WebExtension",
            "description": "Launch Firefox with your WebExtension project installed",
            "body": {
              "type": "firefox",
              "request": "launch",
              "reAttach": true,
              "name": "${1:Launch add-on}",
              "addonPath": "^\"\\${workspaceFolder}${2:}\""
            }
          }
        ],
        "configurationAttributes": {
          "launch": {
            "required": [],
            "properties": {
              "file": {
                "type": "string",
                "description": "The file to open in the browser",
                "default": "${workspaceFolder}/index.html"
              },
              "url": {
                "type": "string",
                "description": "The url to open in the browser"
              },
              "webRoot": {
                "type": "string",
                "description": "If the 'url' property is specified, this property specifies the workspace absolute path corresponding to the path of the url",
                "default": "${workspaceFolder}"
              },
              "firefoxExecutable": {
                "type": "string",
                "description": "Absolute path to the Firefox executable"
              },
              "tmpDir": {
                "type": "string",
                "description": "The path of the directory to use for temporary files"
              },
              "profileDir": {
                "type": "string",
                "description": "The path of the Firefox profile directory to use"
              },
              "profile": {
                "type": "string",
                "description": "The name of the Firefox profile to use"
              },
              "keepProfileChanges": {
                "type": "boolean",
                "description": "Use the specified profile directly instead of a temporary copy",
                "default": true
              },
              "port": {
                "type": "number",
                "description": "The remote debugging port to use",
                "default": 6000
              },
              "timeout": {
                "type": "number",
                "description": "The timeout in seconds for the adapter to connect to Firefox after launching it",
                "default": 5
              },
              "firefoxArgs": {
                "type": "array",
                "description": "Additional arguments passed to Firefox",
                "items": {
                  "type": "string"
                },
                "default": []
              },
              "reAttach": {
                "type": "boolean",
                "description": "Don't terminate Firefox at the end of the debugging session and re-attach to it when starting the next session",
                "default": true
              },
              "reloadOnAttach": {
                "type": "boolean",
                "description": "Reload all tabs after re-attaching to Firefox",
                "default": true
              },
              "reloadOnChange": {
                "description": "Watch the specified files, directories or glob patterns and reload the tabs or add-on when they change",
                "type": [
                  "string",
                  "array",
                  "object"
                ],
                "items": {
                  "type": "string"
                },
                "properties": {
                  "watch": {
                    "description": "Files, directories or glob patterns to be watched for file changes",
                    "type": [
                      "string",
                      "array"
                    ],
                    "items": {
                      "type": "string"
                    },
                    "default": "${workspaceFolder}/**/*.js"
                  },
                  "ignore": {
                    "description": "Files, directories or glob patterns to be ignored",
                    "type": [
                      "string",
                      "array"
                    ],
                    "items": {
                      "type": "string"
                    },
                    "default": "**/node_modules/**"
                  },
                  "debounce": {
                    "description": "The time in milliseconds to wait after a file change before reloading, or false to start reloading immediately",
                    "type": [
                      "number",
                      "boolean"
                    ]
                  }
                },
                "default": {
                  "watch": "${workspaceFolder}/**/*.js",
                  "ignore": "**/node_modules/**"
                }
              },
              "clearConsoleOnReload": {
                "type": "boolean",
                "description": "Clear the debug console in VS Code when the page is reloaded in Firefox",
                "default": false
              },
              "pathMappings": {
                "type": "array",
                "description": "Additional mappings from URLs (as seen by Firefox) to filesystem paths (as seen by VS Code)",
                "items": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "description": "The URL as seen by Firefox"
                    },
                    "path": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The corresponding filesystem path as seen by VS Code"
                    }
                  }
                }
              },
              "pathMappingIndex": {
                "type": "string",
                "description": "The name of the directory index file configured in the webserver",
                "default": "index.html"
              },
              "skipFiles": {
                "type": "array",
                "description": "An array of glob patterns to skip when debugging",
                "items": {
                  "type": "string"
                }
              },
              "preferences": {
                "type": "object",
                "description": "Set additional Firefox preferences",
                "additionalProperties": {
                  "type": [
                    "boolean",
                    "integer",
                    "string",
                    "null"
                  ]
                }
              },
              "tabFilter": {
                "description": "Only attach to tabs whose URL matches this",
                "type": [
                  "string",
                  "array",
                  "object"
                ],
                "items": {
                  "type": "string"
                },
                "properties": {
                  "include": {
                    "description": "URLs to attach to",
                    "type": [
                      "string",
                      "array"
                    ],
                    "items": {
                      "type": "string"
                    },
                    "default": "*"
                  },
                  "exclude": {
                    "description": "URLs not to attach to",
                    "type": [
                      "string",
                      "array"
                    ],
                    "items": {
                      "type": "string"
                    },
                    "default": []
                  }
                },
                "default": "*"
              },
              "showConsoleCallLocation": {
                "type": "boolean",
                "description": "Show the location of console API calls",
                "default": true
              },
              "addonPath": {
                "type": "string",
                "description": "The path of the directory containing the WebExtension",
                "default": "${workspaceFolder}"
              },
              "popupAutohideButton": {
                "type": "boolean",
                "description": "Show a button in the status bar for toggling popup auto-hide (WebExtension debugging)",
                "default": false
              },
              "liftAccessorsFromPrototypes": {
                "type": "number",
                "description": "The number of prototype levels that should be scanned for accessor properties",
                "default": 0
              },
              "suggestPathMappingWizard": {
                "type": "boolean",
                "description": "Suggest using the Path Mapping Wizard when the user tries to set a breakpoint in an unmapped source during a debug session",
                "default": true
              },
              "enableCRAWorkaround": {
                "type": "boolean",
                "description": "Enable a workaround for breakpoints not working in projects created using create-react-app",
                "default": true
              },
              "log": {
                "type": "object",
                "description": "Configuration for diagnostic logging of the debug adapter",
                "properties": {
                  "fileName": {
                    "type": "string",
                    "description": "The name of the logfile",
                    "default": "${workspaceFolder}/vscode-firefox-debug.log"
                  },
                  "fileLevel": {
                    "type": "object",
                    "description": "The minimum loglevel(s) for messages written to the logfile",
                    "properties": {
                      "default": {
                        "type": "string",
                        "enum": [
                          "Debug",
                          "Info",
                          "Warn",
                          "Error"
                        ],
                        "description": "The default loglevel"
                      }
                    },
                    "additionalProperties": {
                      "type": "string",
                      "enum": [
                        "Debug",
                        "Info",
                        "Warn",
                        "Error"
                      ]
                    },
                    "default": {
                      "default": "Debug"
                    }
                  },
                  "consoleLevel": {
                    "type": "object",
                    "description": "The minimum loglevel(s) for messages written to the console",
                    "properties": {
                      "default": {
                        "type": "string",
                        "enum": [
                          "Debug",
                          "Info",
                          "Warn",
                          "Error"
                        ],
                        "description": "The default loglevel"
                      }
                    },
                    "additionalProperties": {
                      "type": "string",
                      "enum": [
                        "Debug",
                        "Info",
                        "Warn",
                        "Error"
                      ]
                    },
                    "default": {
                      "default": "Debug"
                    }
                  }
                },
                "default": {
                  "fileName": "${workspaceFolder}/vscode-firefox-debug.log",
                  "fileLevel": {
                    "default": "Debug"
                  },
                  "consoleLevel": {
                    "default": "Warn"
                  }
                }
              }
            }
          },
          "attach": {
            "required": [],
            "properties": {
              "url": {
                "type": "string",
                "description": "The url to open in the browser"
              },
              "webRoot": {
                "type": "string",
                "description": "If the 'url' property is specified, this property specifies the workspace absolute path corresponding to the path of the url",
                "default": "${workspaceFolder}"
              },
              "firefoxExecutable": {
                "type": "string",
                "description": "Absolute path to the Firefox executable"
              },
              "profileDir": {
                "type": "string",
                "description": "The path of the Firefox profile directory to use"
              },
              "port": {
                "type": "number",
                "description": "The remote debugging port to use",
                "default": 6000
              },
              "host": {
                "type": "string",
                "description": "The remote debugging host to use",
                "default": "localhost"
              },
              "reloadOnAttach": {
                "type": "boolean",
                "description": "Reload all tabs after attaching to Firefox",
                "default": false
              },
              "reloadOnChange": {
                "description": "Watch the specified files, directories or glob patterns and reload the tabs or add-on when they change",
                "type": [
                  "string",
                  "array",
                  "object"
                ],
                "items": {
                  "type": "string"
                },
                "properties": {
                  "watch": {
                    "description": "Files, directories or glob patterns to be watched for file changes",
                    "type": [
                      "string",
                      "array"
                    ],
                    "items": {
                      "type": "string"
                    },
                    "default": "${workspaceFolder}/**/*.js"
                  },
                  "ignore": {
                    "description": "Files, directories or glob patterns to be ignored",
                    "type": [
                      "string",
                      "array"
                    ],
                    "items": {
                      "type": "string"
                    },
                    "default": "**/node_modules/**"
                  },
                  "debounce": {
                    "description": "The time in milliseconds to wait after a file change before reloading, or false to start reloading immediately",
                    "type": [
                      "number",
                      "boolean"
                    ]
                  }
                },
                "default": {
                  "watch": "${workspaceFolder}/**/*.js",
                  "ignore": "**/node_modules/**"
                }
              },
              "clearConsoleOnReload": {
                "type": "boolean",
                "description": "Clear the debug console in VS Code when the page is reloaded in Firefox",
                "default": false
              },
              "pathMappings": {
                "type": "array",
                "description": "Additional mappings from URLs (as seen by Firefox) to filesystem paths (as seen by VS Code)",
                "items": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "description": "The URL as seen by Firefox"
                    },
                    "path": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The corresponding filesystem path as seen by VS Code"
                    }
                  }
                }
              },
              "pathMappingIndex": {
                "type": "string",
                "description": "The name of the directory index file configured in the webserver",
                "default": "index.html"
              },
              "skipFiles": {
                "type": "array",
                "description": "An array of glob patterns to skip when debugging",
                "items": {
                  "type": "string"
                },
                "default": [
                  "${workspaceFolder}/node_modules/**/*"
                ]
              },
              "tabFilter": {
                "description": "Only attach to tabs whose URL matches this",
                "type": [
                  "string",
                  "array",
                  "object"
                ],
                "items": {
                  "type": "string"
                },
                "properties": {
                  "include": {
                    "description": "URLs to attach to",
                    "type": [
                      "string",
                      "array"
                    ],
                    "items": {
                      "type": "string"
                    },
                    "default": "*"
                  },
                  "exclude": {
                    "description": "URLs not to attach to",
                    "type": [
                      "string",
                      "array"
                    ],
                    "items": {
                      "type": "string"
                    },
                    "default": []
                  }
                },
                "default": "*"
              },
              "showConsoleCallLocation": {
                "type": "boolean",
                "description": "Show the location of console API calls",
                "default": true
              },
              "addonPath": {
                "type": "string",
                "description": "The path of the directory containing the WebExtension",
                "default": "${workspaceFolder}"
              },
              "popupAutohideButton": {
                "type": "boolean",
                "description": "Show a button in the status bar for toggling popup auto-hide (WebExtension debugging)",
                "default": false
              },
              "liftAccessorsFromPrototypes": {
                "type": "number",
                "description": "The number of prototype levels that should be scanned for accessor properties",
                "default": 0
              },
              "suggestPathMappingWizard": {
                "type": "boolean",
                "description": "Suggest using the Path Mapping Wizard when the user tries to set a breakpoint in an unmapped source during a debug session",
                "default": true
              },
              "enableCRAWorkaround": {
                "type": "boolean",
                "description": "Enable a workaround for breakpoints not working in projects created using create-react-app",
                "default": true
              },
              "log": {
                "type": "object",
                "description": "Configuration for diagnostic logging of the debug adapter",
                "properties": {
                  "fileName": {
                    "type": "string",
                    "description": "The name of the logfile",
                    "default": "${workspaceFolder}/vscode-firefox-debug.log"
                  },
                  "fileLevel": {
                    "type": "object",
                    "description": "The minimum loglevel(s) for messages written to the logfile",
                    "properties": {
                      "default": {
                        "type": "string",
                        "enum": [
                          "Debug",
                          "Info",
                          "Warn",
                          "Error"
                        ],
                        "description": "The default loglevel"
                      }
                    },
                    "additionalProperties": {
                      "type": "string",
                      "enum": [
                        "Debug",
                        "Info",
                        "Warn",
                        "Error"
                      ]
                    },
                    "default": {
                      "default": "Debug"
                    }
                  },
                  "consoleLevel": {
                    "type": "object",
                    "description": "The minimum loglevel(s) for messages written to the console",
                    "properties": {
                      "default": {
                        "type": "string",
                        "enum": [
                          "Debug",
                          "Info",
                          "Warn",
                          "Error"
                        ],
                        "description": "The default loglevel"
                      }
                    },
                    "additionalProperties": {
                      "type": "string",
                      "enum": [
                        "Debug",
                        "Info",
                        "Warn",
                        "Error"
                      ]
                    },
                    "default": {
                      "default": "Debug"
                    }
                  }
                },
                "default": {
                  "fileName": "${workspaceFolder}/vscode-firefox-debug.log",
                  "fileLevel": {
                    "default": "Debug"
                  },
                  "consoleLevel": {
                    "default": "Warn"
                  }
                }
              }
            }
          }
        }
      }
    ]
  }
}


================================================
FILE: src/README.md
================================================
This folder contains the sources for the Debug Adapter for Firefox extension.
They are grouped into the following subfolders:

* [`adapter`](./adapter) -
  the [debug adapter](https://code.visualstudio.com/api/extension-guides/debugger-extension#debugging-architecture-of-vs-code)
  itself, which is run in a separate process and talks to VS Code using the
  [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)

* [`extension`](./extension) - contains additional integration with VS Code (this code will be run in the VS Code extension host):
  * the Loaded Scripts Explorer, which is shown at the bottom of the debug view
  * a [DebugConfigurationProvider](https://code.visualstudio.com/api/extension-guides/debugger-extension#using-a-debugconfigurationprovider)
    that adds [machine-specific configuration](https://github.com/firefox-devtools/vscode-firefox-debug#overriding-configuration-properties-in-your-settings)
    (like the location of the Firefox executable, the name of the profile to use for debugging, etc.)
    from the user's VS Code settings to debug configurations
  * a button to toggle the “Disable Popup Auto-Hide” flag (for WebExtension debugging) from VS Code

* [`test`](./test) - mocha tests for this extension

* [`common`](./common) - a few interfaces and functions used throughout this extension

* [`typings`](./typings) - type definition files for npm modules for which no type definitions exist on npm


================================================
FILE: src/adapter/README.md
================================================
This folder contains the sources for the Firefox
[debug adapter](https://code.visualstudio.com/api/extension-guides/debugger-extension#debugging-architecture-of-vs-code).

The entry point is the [`FirefoxDebugAdapter`](./firefoxDebugAdapter.ts) class, which receives the
requests from VS Code and delegates most of the work to the [`FirefoxDebugSession`](./firefoxDebugSession.ts) class.

The [`firefox`](./firefox) folder contains the code for launching and talking to Firefox.

The [`coordinator`](./coordinator) folder contains classes that manage the states of
["threads"](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md#interacting-with-thread-like-actors)
in Firefox.

The [`adapter`](./adapter) folder contains classes that translate between the debugging protocols of Firefox and VS Code.


================================================
FILE: src/adapter/adapter/README.md
================================================
This folder contains classes that translate between the
[Firefox Remote Debugging Protocol](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md)
and VS Code's [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/).
Furthermore, there are classes for managing [breakpoints](./breakpointsManager.ts),
[skipping](./skipFilesManager.ts) (or blackboxing) files in the debugger and
[addon debugging](./addonManager.ts).


================================================
FILE: src/adapter/adapter/addonManager.ts
================================================
import { Log } from '../util/log';
import * as path from 'path';
import { ParsedAddonConfiguration } from '../configuration';
import { RootActorProxy } from '../firefox/actorProxy/root';
import { AddonsActorProxy } from '../firefox/actorProxy/addons';
import { PreferenceActorProxy } from '../firefox/actorProxy/preference';
import { FirefoxDebugSession } from '../firefoxDebugSession';
import { PopupAutohideEventBody } from '../../common/customEvents';
import { isWindowsPlatform } from '../../common/util';
import { DescriptorActorProxy } from '../firefox/actorProxy/descriptor';

const log = Log.create('AddonManager');

export const popupAutohidePreferenceKey = 'ui.popup.disable_autohide';

/**
 * When debugging a WebExtension, this class installs the WebExtension, attaches to it, reloads it
 * when desired and tells the [`PopupAutohideManager`](../../extension/popupAutohideManager.ts) the
 * initial state of the popup auto-hide flag by sending a custom event.
 */
export class AddonManager {

	private resolveAddonId!: (addonId: string) => void;
	public readonly addonId = new Promise<string>(resolve => this.resolveAddonId = resolve);

	private readonly config: ParsedAddonConfiguration;

	private descriptorActor: DescriptorActorProxy | undefined = undefined;

	constructor(
		private readonly debugSession: FirefoxDebugSession
	) {
		this.config = debugSession.config.addon!;
	}

	public async sessionStarted(
		rootActor: RootActorProxy,
		addonsActor: AddonsActorProxy,
		preferenceActor: PreferenceActorProxy
	): Promise<void> {

		const addonPath = isWindowsPlatform() ? path.normalize(this.config.path) : this.config.path;
		let result = await addonsActor.installAddon(addonPath);
		this.resolveAddonId(result.addon.id);

		await this.fetchDescriptor(rootActor);

		if (this.config.popupAutohideButton) {
			const popupAutohide = !(await preferenceActor.getBoolPref(popupAutohidePreferenceKey));
			this.debugSession.sendCustomEvent('popupAutohide', <PopupAutohideEventBody>{ popupAutohide });
		}
	}

	public async reloadAddon(): Promise<void> {
		if (!this.descriptorActor) {
			throw 'Addon isn\'t attached';
		}

		await this.descriptorActor.reload();
	}

	private async fetchDescriptor(rootActor: RootActorProxy): Promise<void> {

		const addons = await rootActor.fetchAddons();

		addons.forEach(async addon => {
			if (addon.id === await this.addonId) {
				this.descriptorActor = new DescriptorActorProxy(
					addon.actor,
					'webExtension',
					this.debugSession.firefoxDebugConnection
				);

				if (!this.debugSession.processDescriptorMode) {
					const adapter = await this.debugSession.attachDescriptor(this.descriptorActor);
					await adapter.watcherActor.watchResources(['console-message', 'error-message', 'source', 'thread-state']);
				}
			}
		});
	}
}


================================================
FILE: src/adapter/adapter/breakpoint.ts
================================================
import { DebugProtocol } from '@vscode/debugprotocol';
import { MappedLocation } from '../location';

export class BreakpointInfo {

	/**
	 * the actual location where the breakpoint was set (which may be different from the requested location)
	 */
	public actualLocation: MappedLocation | undefined;

	/** true if the breakpoint was successfully set */
	public verified: boolean;

	/** how many times the breakpoint should be skipped initially */
	public readonly hitLimit: number;
	public hitCount = 0;

	public constructor(
		public readonly id: number,
		public readonly requestedBreakpoint: DebugProtocol.SourceBreakpoint
	) {
		this.verified = false;
		this.hitLimit = +(requestedBreakpoint.hitCondition || '');
	}

	public isEquivalent(other: BreakpointInfo | DebugProtocol.SourceBreakpoint): boolean {

		const bp1 = this.requestedBreakpoint;
		const bp2 = (other instanceof BreakpointInfo) ? other.requestedBreakpoint : other;

		return (bp1.line === bp2.line) && (bp1.column === bp2.column) &&
			(bp1.condition === bp2.condition) && (bp1.logMessage === bp2.logMessage);
	}
}


================================================
FILE: src/adapter/adapter/breakpointsManager.ts
================================================
import { Log } from '../util/log';
import { BreakpointInfo } from './breakpoint';
import { DebugProtocol } from '@vscode/debugprotocol';
import { Event, Breakpoint, BreakpointEvent } from '@vscode/debugadapter';
import { FirefoxDebugSession } from '../firefoxDebugSession';
import { SourceMappingSourceActorProxy } from '../firefox/sourceMaps/source';
import { normalizePath } from '../util/fs';

let log = Log.create('BreakpointsManager');

/**
 * This class holds all breakpoints that have been set in VS Code and synchronizes them with all
 * sources in all threads in Firefox using [`SourceAdapter#updateBreakpoints()`](./source.ts).
 */
export class BreakpointsManager {

	private nextBreakpointId = 1;
	private readonly breakpointsBySourcePathOrUrl = new Map<string, BreakpointInfo[]>();

	constructor(
		private readonly session: FirefoxDebugSession
	) {
		session.breakpointLists.onRegistered(breakpointListActor => {
			[...this.breakpointsBySourcePathOrUrl.entries()].forEach(async ([sourcePath, breakpoints]) => {
				const sourceAdapter = await session.sources.getAdapterForPath(sourcePath);
				if (sourceAdapter.url) {
					breakpoints.forEach(async breakpointInfo => {
						const actualLocation = await sourceAdapter.findNextBreakableLocation(
							breakpointInfo.requestedBreakpoint.line,
							(breakpointInfo.requestedBreakpoint.column || 1) - 1
						);
						if (actualLocation) {
							breakpointInfo.actualLocation = actualLocation;

							let logValue: string | undefined;
							if (breakpointInfo.requestedBreakpoint.logMessage) {
								logValue = '...' + convertLogpointMessage(breakpointInfo.requestedBreakpoint.logMessage);
							}
				
							const location = actualLocation.generated ?? actualLocation;
							const url = actualLocation.generated ? sourceAdapter.generatedUrl : sourceAdapter.url;
							if (url) {
								breakpointListActor.setBreakpoint(
									url,
									location.line,
									location.column,
									breakpointInfo.requestedBreakpoint.condition,
									logValue
								);
							}
							if (!breakpointInfo.verified) {
								this.verifyBreakpoint(breakpointInfo);
							}	
						}
					});
				}
			});
		});
	}

	/**
	 * called by [`FirefoxDebugAdapter#setBreakpoints()`](../firefoxDebugAdapter.ts) whenever the
	 * breakpoints have been changed by the user in VS Code
	 */
	public setBreakpoints(
		breakpoints: DebugProtocol.SourceBreakpoint[],
		sourcePathOrUrl: string
	): BreakpointInfo[] {

		log.debug(`Setting ${breakpoints.length} breakpoints for ${sourcePathOrUrl}`);

		const normalizedPathOrUrl = normalizePath(sourcePathOrUrl);
		const oldBreakpointInfos = this.breakpointsBySourcePathOrUrl.get(normalizedPathOrUrl);
		const breakpointInfos = breakpoints.map(
			breakpoint => this.getOrCreateBreakpointInfo(breakpoint, oldBreakpointInfos)
		);

		this.breakpointsBySourcePathOrUrl.set(normalizedPathOrUrl, breakpointInfos);

		breakpointInfos.forEach(async breakpointInfo => {
			if (!oldBreakpointInfos?.some(oldBreakpointInfo => oldBreakpointInfo === breakpointInfo)) {
				let sourceAdapter = this.session.sources.getExistingAdapterForPath(normalizedPathOrUrl);
				if (!sourceAdapter) {
					this.session.sendEvent(new Event('unknownSource', sourcePathOrUrl));
					sourceAdapter = await this.session.sources.getAdapterForPath(normalizedPathOrUrl);
				}
				if (sourceAdapter.url) {
					const actualLocation = await sourceAdapter.findNextBreakableLocation(
						breakpointInfo.requestedBreakpoint.line,
						(breakpointInfo.requestedBreakpoint.column || 1) - 1
					);
					if (actualLocation) {
						breakpointInfo.actualLocation = actualLocation;

						let logValue: string | undefined;
						if (breakpointInfo.requestedBreakpoint.logMessage) {
							logValue = '...' + convertLogpointMessage(breakpointInfo.requestedBreakpoint.logMessage);
						}
			
						const location = actualLocation.generated ?? actualLocation;
						const url = actualLocation.generated ? sourceAdapter.generatedUrl : sourceAdapter.url;
						if (url) {
							for (const [, breakpointListActor] of this.session.breakpointLists) {
								breakpointListActor.setBreakpoint(
									url,
									location.line,
									location.column,
									breakpointInfo.requestedBreakpoint.condition,
									logValue
								);
							}
						}
						if (!breakpointInfo.verified) {
							this.verifyBreakpoint(breakpointInfo);
						}
					}
				}
			}
		});

		if (oldBreakpointInfos) {
			oldBreakpointInfos.forEach(async oldBreakpointInfo => {
				if (!breakpointInfos.some(breakpointInfo => 
					breakpointInfo.requestedBreakpoint.line === oldBreakpointInfo.requestedBreakpoint.line &&
					breakpointInfo.requestedBreakpoint.column === oldBreakpointInfo.requestedBreakpoint.column
				)) {
					const sourceAdapter = await this.session.sources.getAdapterForPath(normalizedPathOrUrl);
					if (sourceAdapter.url) {
						const actualLocation = await sourceAdapter.findNextBreakableLocation(
							oldBreakpointInfo.requestedBreakpoint.line,
							(oldBreakpointInfo.requestedBreakpoint.column || 1) - 1
						);
						if (actualLocation) {
							const location = actualLocation.generated ?? actualLocation;
							const url = actualLocation.generated ? sourceAdapter.generatedUrl : sourceAdapter.url;
							if (url) {
								for (const [, breakpointListActor] of this.session.breakpointLists) {
									breakpointListActor.removeBreakpoint(
										url,
										location.line,
										location.column
									);
								}
							}
						}
					}
					}
			});
		}

		return breakpointInfos;
	}

	public getBreakpoints(sourcePathOrUrl: string) {
		return this.breakpointsBySourcePathOrUrl.get(normalizePath(sourcePathOrUrl));
	}

	private verifyBreakpoint(breakpointInfo: BreakpointInfo): void {

		if (!breakpointInfo.actualLocation) return;

		let breakpoint: DebugProtocol.Breakpoint = new Breakpoint(
			true, breakpointInfo.actualLocation.line, breakpointInfo.actualLocation.column + 1);
		breakpoint.id = breakpointInfo.id;
		this.session.sendEvent(new BreakpointEvent('changed', breakpoint));

		breakpointInfo.verified = true;
	}

	private getOrCreateBreakpointInfo(
		requestedBreakpoint: DebugProtocol.SourceBreakpoint,
		oldBreakpointInfos: BreakpointInfo[] | undefined
	): BreakpointInfo {

		if (oldBreakpointInfos) {

			const oldBreakpointInfo = oldBreakpointInfos.find(
				breakpointInfo => breakpointInfo.isEquivalent(requestedBreakpoint)
			);

			if (oldBreakpointInfo) {
				return oldBreakpointInfo;
			}
		}

		return new BreakpointInfo(this.nextBreakpointId++, requestedBreakpoint);
	}
}

/**
 * convert the message of a logpoint (which can contain javascript expressions in curly braces)
 * to a javascript expression that evaluates to an array of values to be displayed in the debug console
 * (doesn't support escaping or nested curly braces)
 */
export function convertLogpointMessage(msg: string): string {

	// split `msg` into string literals and javascript expressions
	const items: string[] = [];
	let currentPos = 0;
	while (true) {

		const leftBrace = msg.indexOf('{', currentPos);

		if (leftBrace < 0) {

			items.push(JSON.stringify(msg.substring(currentPos)));
			break;

		} else {

			let rightBrace = msg.indexOf('}', leftBrace + 1);
			if (rightBrace < 0) rightBrace = msg.length;

			items.push(JSON.stringify(msg.substring(currentPos, leftBrace)));
			items.push(msg.substring(leftBrace + 1, rightBrace));
			currentPos = rightBrace + 1;
		}
	}

	// the appended `reduce()` call will convert all non-object values to strings and concatenate consecutive strings
	return `[${items.join(',')}].reduce((a,c)=>{if(typeof c==='object'&&c){a.push(c,'')}else{a.push(a.pop()+c)}return a},[''])`;
}


================================================
FILE: src/adapter/adapter/consoleAPICall.ts
================================================
import { VariablesProvider } from './variablesProvider';
import { VariableAdapter } from './variable';
import { ThreadAdapter } from './thread';

/**
 * Adapter class for representing a `consoleAPICall` event from Firefox.
 */
export class ConsoleAPICallAdapter implements VariablesProvider {

	public readonly variablesProviderId: number;
	public readonly referenceExpression = undefined;
	public readonly referenceFrame = undefined;
	private readonly argsAdapter: VariableAdapter;

	public constructor(
		args: VariableAdapter[],
		preview: string,
		public readonly threadAdapter: ThreadAdapter
	) {
		this.variablesProviderId = threadAdapter.debugSession.variablesProviders.register(this);
		this.argsAdapter = VariableAdapter.fromArgumentList(args, preview, threadAdapter);
	}

	public getVariables(): Promise<VariableAdapter[]> {
		return Promise.resolve(this.argsAdapter ? [this.argsAdapter] : []);
	}
}

export class ArgumentListAdapter implements VariablesProvider {

	public readonly variablesProviderId: number;
	public readonly referenceExpression = undefined;
	public readonly referenceFrame = undefined;

	public constructor(
		private readonly args: VariableAdapter[],
		public readonly threadAdapter: ThreadAdapter
	) {
		this.variablesProviderId = threadAdapter.debugSession.variablesProviders.register(this);
	}

	public getVariables(): Promise<VariableAdapter[]> {
		return Promise.resolve(this.args);
	}
}


================================================
FILE: src/adapter/adapter/dataBreakpointsManager.ts
================================================
import { Log } from '../util/log';
import { VariablesProvider } from './variablesProvider';
import { Registry } from './registry';
import { DebugProtocol } from '@vscode/debugprotocol';
import { ObjectGripAdapter } from './objectGrip';

const log = Log.create('DataBreakpointsManager');

export class DataBreakpointsManager {

	private dataBreakpoints = new Set<string>();

	constructor(
		private readonly variablesProviders: Registry<VariablesProvider>
	) {}

	public static encodeDataId(variablesProviderId: number, property: string): string {
		return `${variablesProviderId}.${property}`;
	}

	public static decodeDataId(dataId: string): { variablesProviderId: number, property: string } {

		const separatorIndex = dataId.indexOf('.');

		return {
			variablesProviderId: +dataId.substring(0, separatorIndex),
			property: dataId.substring(separatorIndex + 1)
		};
	}

	public async setDataBreakpoints(newDataBreakpoints: DebugProtocol.DataBreakpoint[]): Promise<void> {

		log.debug(`Setting ${newDataBreakpoints.length} data breakpoints`);

		const oldDataBreakpoints = new Set<string>(this.dataBreakpoints);

		for (const dataBreakpoint of newDataBreakpoints) {
			if (!oldDataBreakpoints.has(dataBreakpoint.dataId)) {

				const type = (dataBreakpoint.accessType === 'read') ? 'get' : 'set';
				await this.addDataBreakpoint(dataBreakpoint.dataId, type);

			} else {
				oldDataBreakpoints.delete(dataBreakpoint.dataId);
			}
		}

		for (const dataBreakpoint of oldDataBreakpoints) {
			await this.removeDataBreakpoint(dataBreakpoint);
		}

		this.dataBreakpoints = new Set<string>(newDataBreakpoints.map(dataBreakpoint => dataBreakpoint.dataId));
	}

	private async addDataBreakpoint(dataId: string, type: 'get' | 'set'): Promise<void> {

		const { variablesProviderId, property } = DataBreakpointsManager.decodeDataId(dataId);
		const variablesProvider = this.variablesProviders.find(variablesProviderId);

		if (variablesProvider instanceof ObjectGripAdapter) {

			log.debug(`Adding data breakpoint for property ${property} of object #${variablesProviderId}`);

			await variablesProvider.actor.addWatchpoint(property, dataId, type);

		} else {
			log.warn(`Couldn't find object #${variablesProviderId}`);
		}
	}

	private async removeDataBreakpoint(dataId: string): Promise<void> {

		const { variablesProviderId, property } = DataBreakpointsManager.decodeDataId(dataId);
		const variablesProvider = this.variablesProviders.find(variablesProviderId);

		if (variablesProvider instanceof ObjectGripAdapter) {

			log.debug(`Removing data breakpoint for property ${property} of object #${variablesProviderId}`);

			await variablesProvider.actor.removeWatchpoint(property);

		} else {
			log.warn(`Couldn't find object #${variablesProviderId}`);
		}
	}
}


================================================
FILE: src/adapter/adapter/descriptor.ts
================================================
import { Registry } from './registry';
import { DescriptorActorProxy } from '../firefox/actorProxy/descriptor';
import { BreakpointListActorProxy } from '../firefox/actorProxy/breakpointList';
import { WatcherActorProxy } from '../firefox/actorProxy/watcher';
import { ThreadConfigurationActorProxy } from '../firefox/actorProxy/threadConfiguration';
import { ThreadAdapter } from './thread';

export class DescriptorAdapter {

	public readonly id: number;
	private readonly configuratorId: number;
	private readonly breakpointListId: number;
	public readonly threads = new Set<ThreadAdapter>();

	public constructor(
		private readonly descriptorRegistry: Registry<DescriptorAdapter>,
		private readonly configurators: Registry<ThreadConfigurationActorProxy>,
		private readonly breakpointLists: Registry<BreakpointListActorProxy>,
		public readonly descriptorActor: DescriptorActorProxy,
		public readonly watcherActor: WatcherActorProxy,
		private readonly configurator: ThreadConfigurationActorProxy,
		private readonly breakpointList: BreakpointListActorProxy
	) {
		this.id = descriptorRegistry.register(this);
		this.configuratorId = configurators.register(configurator);
		this.breakpointListId = breakpointLists.register(breakpointList);
	}

	public dispose() {
		for (const thread of this.threads) {
			thread.dispose();
		}
		this.descriptorRegistry.unregister(this.id);
		this.configurators.unregister(this.configuratorId);
		this.breakpointLists.unregister(this.breakpointListId);
		this.descriptorActor.dispose();
		this.configurator.dispose();
		this.breakpointList.dispose();
		this.watcherActor.dispose();
	}
}


================================================
FILE: src/adapter/adapter/environment.ts
================================================
import { Log } from '../util/log';
import { ScopeAdapter, ObjectScopeAdapter, LocalVariablesScopeAdapter, FunctionScopeAdapter } from './scope';
import { FrameAdapter } from './frame';

let log = Log.create('EnvironmentAdapter');

/**
 * Abstract adapter base class for a lexical environment.
 * Used to create [`ScopeAdapter`](./scope.ts)s which then create `Scope` objects for VS Code.
 */
export abstract class EnvironmentAdapter<T extends FirefoxDebugProtocol.Environment> {

	protected environment: T;
	protected parent?: EnvironmentAdapter<FirefoxDebugProtocol.Environment>;

	public constructor(environment: T) {
		this.environment = environment;
		if (environment.parent !== undefined) {
			this.parent = EnvironmentAdapter.from(environment.parent);
		}
	}

	/** factory function for creating an EnvironmentAdapter of the appropriate type */
	public static from(environment: FirefoxDebugProtocol.Environment): EnvironmentAdapter<FirefoxDebugProtocol.Environment> {
		switch (environment.type) {
			case 'object':
				return new ObjectEnvironmentAdapter(<FirefoxDebugProtocol.ObjectEnvironment>environment);
			case 'function':
				return new FunctionEnvironmentAdapter(<FirefoxDebugProtocol.FunctionEnvironment>environment);
			case 'with':
				return new WithEnvironmentAdapter(<FirefoxDebugProtocol.WithEnvironment>environment);
			case 'block':
				return new BlockEnvironmentAdapter(<FirefoxDebugProtocol.BlockEnvironment>environment);
			default:
				throw new Error(`Unknown environment type ${environment.type}`);
		}
	}

	public getScopeAdapters(frameAdapter: FrameAdapter): ScopeAdapter[] {

		let scopes = this.getAllScopeAdapters(frameAdapter);

		return scopes;
	}

	protected getAllScopeAdapters(frameAdapter: FrameAdapter): ScopeAdapter[] {

		let scopes: ScopeAdapter[];

		if (this.parent !== undefined) {
			scopes = this.parent.getAllScopeAdapters(frameAdapter);
		} else {
			scopes = [];
		}

		let ownScope = this.getOwnScopeAdapter(frameAdapter);
		scopes.unshift(ownScope);

		return scopes;
	}

	protected abstract getOwnScopeAdapter(frameAdapter: FrameAdapter): ScopeAdapter;
}

export class ObjectEnvironmentAdapter extends EnvironmentAdapter<FirefoxDebugProtocol.ObjectEnvironment> {

	public constructor(environment: FirefoxDebugProtocol.ObjectEnvironment) {
		super(environment);
	}

	protected getOwnScopeAdapter(frameAdapter: FrameAdapter): ScopeAdapter {

		let grip = this.environment.object;

		if ((typeof grip === 'boolean') || (typeof grip === 'number') || (typeof grip === 'string')) {

			throw new Error(`Object environment with unexpected grip of type ${typeof grip}`);

		} else if (grip.type !== 'object') {

			throw new Error(`Object environment with unexpected grip of type ${grip.type}`);

		} else {

			let objectGrip = <FirefoxDebugProtocol.ObjectGrip>grip;
			let name = `Object: ${objectGrip.class}`;
			return new ObjectScopeAdapter(name, objectGrip, frameAdapter);

		}
	}
}

export class FunctionEnvironmentAdapter extends EnvironmentAdapter<FirefoxDebugProtocol.FunctionEnvironment> {

	public constructor(environment: FirefoxDebugProtocol.FunctionEnvironment) {
		super(environment);
	}

	protected getOwnScopeAdapter(frameAdapter: FrameAdapter): ScopeAdapter {

		let funcName = this.environment.function.displayName;
		let scopeName: string;
		if (funcName) {
			scopeName = `Local: ${funcName}`;
		} else {
			log.error(`Unexpected function in function environment: ${JSON.stringify(this.environment.function)}`);
			scopeName = '[unknown]';
		}

		return new FunctionScopeAdapter(scopeName, this.environment.bindings, frameAdapter);
	}
}

export class WithEnvironmentAdapter extends EnvironmentAdapter<FirefoxDebugProtocol.WithEnvironment> {

	public constructor(environment: FirefoxDebugProtocol.WithEnvironment) {
		super(environment);
	}

	protected getOwnScopeAdapter(frameAdapter: FrameAdapter): ScopeAdapter {

		let grip = this.environment.object;

		if ((typeof grip === 'boolean') || (typeof grip === 'number') || (typeof grip === 'string')) {

			throw new Error(`"with" environment with unexpected grip of type ${typeof grip}`);

		} else if (grip.type !== 'object') {

			throw new Error(`"with" environment with unexpected grip of type ${grip.type}`);

		} else {

			let objectGrip = <FirefoxDebugProtocol.ObjectGrip>grip;
			let name = `With: ${objectGrip.class}`;
			return new ObjectScopeAdapter(name, objectGrip, frameAdapter);

		}
	}
}

export class BlockEnvironmentAdapter extends EnvironmentAdapter<FirefoxDebugProtocol.BlockEnvironment> {

	public constructor(environment: FirefoxDebugProtocol.BlockEnvironment) {
		super(environment);
	}

	protected getOwnScopeAdapter(frameAdapter: FrameAdapter): ScopeAdapter {

		return new LocalVariablesScopeAdapter('Block', this.environment.bindings.variables, frameAdapter);

	}
}


================================================
FILE: src/adapter/adapter/eventBreakpointsManager.ts
================================================
import { AvailableEventCategory } from '../../common/customEvents';
import { FirefoxDebugSession } from '../firefoxDebugSession';
import { compareStrings } from '../util/misc';

export class EventBreakpointsManager {

	public readonly availableEvents: AvailableEventCategory[] = [];

	constructor(
		private readonly session: FirefoxDebugSession
	) {
		session.threads.onRegistered(async threadAdapter => {
			const newAvailableEvents = await threadAdapter.actor.getAvailableEventBreakpoints();
			let categoryWasAdded = false;
			for (const newCategory of newAvailableEvents) {
				const category = this.availableEvents.find(category => category.name === newCategory.name);

				if (!category) {
					this.availableEvents.push({
						name: newCategory.name,
						events: newCategory.events.map(newEvent => ({
							name: newEvent.name,
							id: newEvent.id,
						})),
					});
					categoryWasAdded = true;
					continue;
				}

				let eventWasAdded = false;
				for (const newEvent of newCategory.events) {
					if (!category.events.find(event => event.id === newEvent.id)) {
						category.events.push({
							name: newEvent.name,
							id: newEvent.id,
						});
						eventWasAdded = true;
					}
				}

				if (eventWasAdded) {
					category.events.sort((e1, e2) => compareStrings(e1.name, e2.name))
				}
			}

			if (categoryWasAdded) {
				this.availableEvents.sort((c1, c2) => compareStrings(c1.name, c2.name));
			}

			this.session.sendCustomEvent('availableEvents', this.availableEvents);
		});
	}

	public async setActiveEventBreakpoints(ids: string[]) {
		await Promise.all(this.session.breakpointLists.map(breakpointList => 
			breakpointList.setActiveEventBreakpoints(ids)
		));
	}
}


================================================
FILE: src/adapter/adapter/frame.ts
================================================
import { Log } from '../util/log';
import { ThreadAdapter } from './thread';
import { EnvironmentAdapter } from './environment';
import { ScopeAdapter } from './scope';
import { StackFrame } from '@vscode/debugadapter';
import { Registry } from './registry';
import { FrameActorProxy } from '../firefox/actorProxy/frame';

let log = Log.create('FrameAdapter');

/**
 * Adapter class for a stackframe.
 */
export class FrameAdapter {

	public readonly id: number;
	private _scopeAdapters?: ScopeAdapter[];

	public constructor(
		private readonly frameRegistry: Registry<FrameAdapter>,
		public readonly frame: FirefoxDebugProtocol.Frame,
		public readonly threadAdapter: ThreadAdapter
	) {
		this.id = frameRegistry.register(this);
	}

	public async getStackframe(): Promise<StackFrame> {

		let sourceActorName = this.frame.where.actor;
		let sourceAdapter = await this.threadAdapter.debugSession.sources.getAdapterForActor(sourceActorName);

		let name: string;
		switch (this.frame.type) {

			case 'call':
				const callFrame = this.frame as FirefoxDebugProtocol.CallFrame;
				name = callFrame.displayName || '[anonymous function]';
				break;

			case 'global':
				name = '[Global]';
				break;

			case 'eval':
			case 'clientEvaluate':
				name = '[eval]';
				break;

			case 'wasmcall':
				name = '[wasm]';
				break;

			default:
				name = `[${this.frame.type}]`;
				log.error(`Unexpected frame type ${this.frame.type}`);
				break;
		}

		return new StackFrame(this.id, name, sourceAdapter.source,
			this.frame.where.line, (this.frame.where.column || 0) + 1);
	}

	public async getScopeAdapters(): Promise<ScopeAdapter[]> {

		if (!this._scopeAdapters) {

			const frameActor = new FrameActorProxy(this.frame.actor, this.threadAdapter.debugSession.firefoxDebugConnection);
			const environment = await frameActor.getEnvironment();
			frameActor.dispose();

			if (environment.type) {
				const environmentAdapter = EnvironmentAdapter.from(environment);
				this._scopeAdapters = environmentAdapter.getScopeAdapters(this);
				if (this.frame.this !== undefined) {
					this._scopeAdapters[0].addThis(this.frame.this);
				}
			} else {
				this._scopeAdapters = [];
			}
		}

		return this._scopeAdapters;
	}

	public dispose(): void {
		this.frameRegistry.unregister(this.id);
	}
}


================================================
FILE: src/adapter/adapter/getterValue.ts
================================================
import { VariablesProvider } from './variablesProvider';
import { ThreadAdapter } from './thread';
import { FrameAdapter } from './frame';
import { VariableAdapter } from './variable';

/**
 * Adapter class for an accessor property with a getter (i.e. a property defined using
 * [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
 * with an accessor descriptor containing a `get` function or using the new ES6 syntax for defining
 * accessors).
 * The value of such a property can only be determined by executing the getter function, but that may
 * have side-effects. Therefore it is not executed and the corresponding [`VariableAdapter`](./variable.ts)
 * will show a text like "Getter & Setter - expand to execute Getter" to the user. When the user
 * clicks on this text, the getter will be executed by the `getVariables()` method and the value
 * will be displayed.
 * 
 * Note that if the accessor property is not defined on the object itself but on one of its
 * prototypes, the user would have to navigate to the prototype to find it and if he then executed
 * the getter, it would be executed with `this` set to the prototype, which is usually not the
 * desired behavior. Therefore it is possible to "lift" accessor properties to an object from its
 * prototype chain using the `liftAccessorsFromPrototypes` configuration property.
 */
export class GetterValueAdapter implements VariablesProvider {

	public readonly variablesProviderId: number;
	public get threadAdapter(): ThreadAdapter {
		return this.variableAdapter.threadAdapter;
	}
	/** a javascript expression that will execute the getter */
	public get referenceExpression(): string | undefined {
		return this.variableAdapter.referenceExpression;
	}
	/** the stackframe to use when executing the `referenceExpression` */
	public get referenceFrame(): FrameAdapter | undefined {
		return this.variableAdapter.referenceFrame;
	}

	public constructor(private readonly variableAdapter: VariableAdapter) {
		this.variablesProviderId = this.threadAdapter.debugSession.variablesProviders.register(this);
	}

	/** execute the getter and return a VariableAdapter for the value returned by the getter */
	public async getVariables(): Promise<VariableAdapter[]> {
		if (this.referenceExpression && this.referenceFrame) {

			const grip = await this.threadAdapter.evaluateRaw(
				this.referenceExpression, true, this.referenceFrame.frame.actor
			);

			const variableAdapter = VariableAdapter.fromGrip(
				'Value from Getter', this.referenceExpression, this.referenceFrame,
				grip, false, this.threadAdapter, true
			);

			return [ variableAdapter ];

		} else {
			return [];
		}
	}
}


================================================
FILE: src/adapter/adapter/objectGrip.ts
================================================
import { VariablesProvider } from './variablesProvider';
import { VariableAdapter } from './variable';
import { FrameAdapter } from './frame';
import { ThreadAdapter } from './thread';
import { ObjectGripActorProxy } from '../firefox/actorProxy/objectGrip';

/**
 * Adapter class for a javascript object.
 */
export class ObjectGripAdapter implements VariablesProvider {

	public readonly variablesProviderId: number;
	public readonly actor: ObjectGripActorProxy;
	public get threadAdapter(): ThreadAdapter {
		return this.variableAdapter.threadAdapter;
	}
	/** a javascript expression for accessing the object represented by this adapter */
	public get referenceExpression(): string | undefined {
		return this.variableAdapter.referenceExpression;
	}
	/** the stackframe to use when executing the `referenceExpression` */
	public get referenceFrame(): FrameAdapter | undefined {
		return this.variableAdapter.referenceFrame;
	}

	public constructor(
		private readonly variableAdapter: VariableAdapter,
		objectGrip: FirefoxDebugProtocol.ObjectGrip,
		public threadLifetime: boolean,
		private readonly isPrototype: boolean
	) {
		this.actor = this.threadAdapter.debugSession.getOrCreateObjectGripActorProxy(objectGrip);
		this.actor.increaseRefCount();
		this.variablesProviderId = this.threadAdapter.debugSession.variablesProviders.register(this);
		this.threadAdapter.registerObjectGripAdapter(this);
	}

	/**
	 * get the referenced object's properties and its prototype as an array of Variables.
	 * This method can only be called when the thread is paused.
	 */
	public async getVariables(): Promise<VariableAdapter[]> {

		let prototypeAndProperties = await this.actor.fetchPrototypeAndProperties();

		let variables: VariableAdapter[] = [];
		let symbolVariables: VariableAdapter[] = [];
		let safeGetterValues = prototypeAndProperties.safeGetterValues || {};
		let symbolProperties = prototypeAndProperties.ownSymbols || [];

		for (let varname in prototypeAndProperties.ownProperties) {
			if (!safeGetterValues[varname]) {
				variables.push(VariableAdapter.fromPropertyDescriptor(
					varname, this.referenceExpression, this.referenceFrame,
					prototypeAndProperties.ownProperties[varname],
					this.threadLifetime, this.threadAdapter));
			}
		}

		for (let varname in safeGetterValues) {
			variables.push(VariableAdapter.fromSafeGetterValueDescriptor(
				varname, this.referenceExpression, this.referenceFrame,
				safeGetterValues[varname],
				this.threadLifetime, this.threadAdapter));
		}

		for (let symbolProperty of symbolProperties) {
			symbolVariables.push(VariableAdapter.fromPropertyDescriptor(
				symbolProperty.name, undefined, undefined,
				symbolProperty.descriptor, this.threadLifetime, this.threadAdapter));
		}

		let prototypeVariable: VariableAdapter | undefined = undefined;
		let accessorsFromPrototypes: VariableAdapter[] = [];
		if (prototypeAndProperties.prototype.type !== 'null') {
			prototypeVariable = VariableAdapter.fromGrip(
				'__proto__', this.referenceExpression, this.referenceFrame,
				prototypeAndProperties.prototype,
				this.threadLifetime, this.threadAdapter
			);

			if (!this.isPrototype) {
				const prototypeLevels = this.threadAdapter.debugSession.config.liftAccessorsFromPrototypes;
				if (prototypeLevels > 0) {
					accessorsFromPrototypes = await this.fetchAccessorsFromPrototypes(prototypeVariable, prototypeLevels);
				}
			}
		}

		/** Array-Objects are already sorted, sorting them again as strings messes up the order */
		let isArray = (prototypeAndProperties.prototype.type == 'object' && prototypeAndProperties.prototype.class == 'Array');
		if (!isArray) {
			VariableAdapter.sortVariables(variables);
		}
		VariableAdapter.sortVariables(symbolVariables);
		VariableAdapter.sortVariables(accessorsFromPrototypes);
		variables.push(...symbolVariables);
		variables.push(...accessorsFromPrototypes);

		if (prototypeVariable) {
			variables.push(prototypeVariable);
		}

		return variables;
	}

	/**
	 * used to "lift" accessor properties from the prototype chain to an object if the
	 * `liftAccessorsFromPrototypes` configuration property is set.
	 * Have a look at the [`GetterValueAdapter`](./getterValue.ts) for more info.
	 */
	private async fetchAccessorsFromPrototypes(
		prototypeVariable: VariableAdapter,
		levels: number
	): Promise<VariableAdapter[]> {

		let objectGripAdapter: ObjectGripAdapter | undefined = <any>prototypeVariable.variablesProvider;
		let variables: VariableAdapter[] = [];
		let level = 0;
		while ((level < levels) && objectGripAdapter) {

			let prototypeAndProperties = await objectGripAdapter.actor.fetchPrototypeAndProperties();

			for (const varname in prototypeAndProperties.ownProperties) {

				const propertyDescriptor = prototypeAndProperties.ownProperties[varname];
				if ((varname !== '__proto__') && 
					(<FirefoxDebugProtocol.AccessorPropertyDescriptor>propertyDescriptor).get) {

					variables.push(VariableAdapter.fromPropertyDescriptor(
						varname, this.referenceExpression, this.referenceFrame,
						propertyDescriptor, this.threadLifetime, this.threadAdapter
					));
				}
			}

			prototypeVariable = VariableAdapter.fromGrip(
				'__proto__', this.referenceExpression, this.referenceFrame,
				prototypeAndProperties.prototype,
				this.threadLifetime, this.threadAdapter
			);
			objectGripAdapter = <any>prototypeVariable.variablesProvider;

			level++;
		}

		return variables;
	}

	public dispose(): void {
		this.actor.decreaseRefCount();
		this.threadAdapter.debugSession.variablesProviders.unregister(this.variablesProviderId);
	}
}


================================================
FILE: src/adapter/adapter/preview.ts
================================================
import { Log } from '../util/log';

const log = Log.create('Preview');

const maxProperties = 5;
const maxArrayItems = 5;
const maxStringChars = 20;
const maxAttributes = 5;
const maxParameters = 5;

/** generates the preview string for an object shown in the debugger's Variables view */
export function renderPreview(objectGrip: FirefoxDebugProtocol.ObjectGrip): string {
	try {

		if ((objectGrip.class === 'Function') || 
			(objectGrip as FirefoxDebugProtocol.FunctionGrip).parameterNames) {

			if (objectGrip.class !== 'Function') {
				log.warn(`Looks like a FunctionGrip but has a different class: ${JSON.stringify(objectGrip)}`);
			}
			return renderFunctionGrip(<FirefoxDebugProtocol.FunctionGrip>objectGrip);
		}

		const preview = objectGrip.preview;
		if (!preview) {
			return objectGrip.class;
		}

		if (preview.kind === 'Object') {

			return renderObjectPreview(preview, objectGrip.class);

		} else if (preview.kind === 'ArrayLike') {

			return renderArrayLikePreview(preview, objectGrip.class);

		} else if ((objectGrip.class === 'Date') && (preview.kind === undefined)) {

			const date = new Date(preview.timestamp);
			return date.toString();

		} else if (preview.kind === 'ObjectWithURL') {

			return `${objectGrip.class} ${preview.url}`;

		} else if ((preview.kind === 'DOMNode') && (preview.nodeType === 1)) {

			return renderDOMElementPreview(preview);

		} else if (preview.kind === 'Error') {

			return `${objectGrip.class}: ${preview.message}`;

		} else {

			return objectGrip.class;

		}

	} catch (e) {
		log.error(`renderPreview failed for ${JSON.stringify(objectGrip)}: ${e}`);
		return '';
	}
}

function renderObjectPreview(preview: FirefoxDebugProtocol.ObjectPreview, className: string): string {

	const renderedProperties: string[] = [];
	let i = 0;
	for (const property in preview.ownProperties) {

		var valueGrip = preview.ownProperties[property].value;
		if (!valueGrip) {
			continue;
		}

		const renderedValue = renderGrip(valueGrip);
		renderedProperties.push(`${property}: ${renderedValue}`);

		if (++i >= maxProperties) {
			renderedProperties.push('\u2026');
			break;
		}
	}

	if (i < maxProperties && preview.ownSymbols) {
		for (const symbolProperty of preview.ownSymbols) {

			const renderedValue = renderGrip(symbolProperty.descriptor.value);
			renderedProperties.push(`Symbol(${symbolProperty.name}): ${renderedValue}`);

			if (++i >= maxProperties) {
				renderedProperties.push('\u2026');
				break;
			}
		}
	}

	const renderedObject = `{${renderedProperties.join(', ')}}`;

	if (className === 'Object') {
		return renderedObject;
	} else {
		return `${className} ${renderedObject}`;
	}
}

function renderDOMElementPreview(preview: FirefoxDebugProtocol.DOMNodePreview): string {

	if (!preview.attributes) {
		return `<${preview.nodeName}>`;
	}

	const renderedAttributes: string[] = [];
	let i = 0;
	for (const attribute in preview.attributes) {

		const renderedValue = renderGrip(preview.attributes[attribute]);
		renderedAttributes.push(`${attribute}=${renderedValue}`);

		if (++i >= maxAttributes) {
			renderedAttributes.push('\u2026');
			break;
		}
	}

	if (renderedAttributes.length === 0) {
		return `<${preview.nodeName}>`;
	} else {
		return `<${preview.nodeName} ${renderedAttributes.join(' ')}>`;
	}
}

function renderArrayLikePreview(preview: FirefoxDebugProtocol.ArrayLikePreview, className: string): string {

	let result = `${className}(${preview.length})`;

	if (preview.items && preview.items.length > 0) {

		const renderCount = Math.min(preview.items.length, maxArrayItems);
		const itemsToRender = preview.items.slice(0, renderCount);
		const renderedItems = itemsToRender.map(item => renderGripOrNull(item));

		if (renderCount < preview.items.length) {
			renderedItems.push('\u2026');
		}

		result += ` [${renderedItems.join(', ')}]`;

	}

	return result;
}

function renderFunctionGrip(functionGrip: FirefoxDebugProtocol.FunctionGrip): string {

	let parameters = '';

	if (functionGrip.parameterNames &&
		functionGrip.parameterNames.every(parameterName => typeof parameterName === 'string')) {

		let parameterNames = functionGrip.parameterNames;
		if (parameterNames.length > maxParameters) {
			parameterNames = parameterNames.slice(0, maxParameters);
			parameterNames.push('\u2026');
		}

		parameters = parameterNames.join(', ');
	}

	const functionName = functionGrip.displayName || functionGrip.name || 'function';
	return `${functionName}(${parameters}) {\u2026}`;
}

function renderGripOrNull(gripOrNull: FirefoxDebugProtocol.Grip | null): string {
	if (gripOrNull === null) {
		return "_";
	} else {
		return renderGrip(gripOrNull);
	}
}

export function renderGrip(grip: FirefoxDebugProtocol.Grip): string {

	if ((typeof grip === 'boolean') || (typeof grip === 'number')) {

		return grip.toString();

	} else if (typeof grip === 'string') {

		if (grip.length > maxStringChars) {
			return `"${grip.substr(0, maxStringChars)}\u2026"`;
		} else {
			return `"${grip}"`;
		}

	} else {

		switch (grip.type) {

			case 'null':
			case 'undefined':
			case 'Infinity':
			case '-Infinity':
			case 'NaN':
			case '-0':

				return grip.type;

			case 'BigInt':

				return `${(<FirefoxDebugProtocol.BigIntGrip>grip).text}n`;

			case 'longString':

				const initial = (<FirefoxDebugProtocol.LongStringGrip>grip).initial;
				if (initial.length > maxStringChars) {
					return `${initial.substr(0, maxStringChars)}\u2026`;
				} else {
					return initial;
				}
		
			case 'symbol':

				let symbolName = (<FirefoxDebugProtocol.SymbolGrip>grip).name;
				return `Symbol(${symbolName})`;

			case 'object':

				let objectGrip = <FirefoxDebugProtocol.ObjectGrip>grip;
				return renderPreview(objectGrip);

			default:

				log.warn(`Unexpected object grip of type ${grip.type}: ${JSON.stringify(grip)}`);
				return '';

		}
	}
}


================================================
FILE: src/adapter/adapter/registry.ts
================================================
import { EventEmitter } from 'events';

/**
 * A generic collection of objects identified by a numerical ID.
 * The ID is generated and returned when an object is added to the collection using `register()`.
 */
export class Registry<T> extends EventEmitter implements Iterable<[number, T]> {

	private objectsById = new Map<number, T>();
	private nextId = 1;

	/**
	 * add an object to the registry and return the ID generated for it
	 */
	public register(obj: T): number {
		let id = this.nextId++;
		this.objectsById.set(id, obj);
		this.emit('registered', obj);
		return id;
	}

	public unregister(id: number): boolean {
		return this.objectsById.delete(id);
	}

	public has(id: number): boolean {
		return this.objectsById.has(id);
	}

	public find(id: number): T | undefined {
		return this.objectsById.get(id);
	}

	public get count() {
		return this.objectsById.size;
	}

	public [Symbol.iterator](): Iterator<[number, T]> {
		return this.objectsById[Symbol.iterator]();
	}

	public map<S>(f: (obj: T) => S): S[] {
		let result: S[] = [];
		for (let [, obj] of this.objectsById) {
			result.push(f(obj));
		}
		return result;
	}

	public filter(f: (obj: T) => boolean): T[] {
		let result: T[] = [];
		for (let [, obj] of this.objectsById) {
			if (f(obj)) {
				result.push(obj);
			}
		}
		return result;
	}

	public onRegistered(cb: (obj: T) => void) {
		this.on('registered', cb);
	}
}

================================================
FILE: src/adapter/adapter/scope.ts
================================================
import { ThreadAdapter } from './thread';
import { FrameAdapter } from './frame';
import { VariableAdapter } from './variable';
import { Scope } from '@vscode/debugadapter';
import { VariablesProvider } from './variablesProvider';

/**
 * Abstract adapter base class for a javascript scope.
 */
export abstract class ScopeAdapter implements VariablesProvider {

	public readonly variablesProviderId: number;
	public readonly referenceExpression = '';
	public get threadAdapter(): ThreadAdapter {
		return this.referenceFrame.threadAdapter;
	}

	public thisVariable?: VariableAdapter;
	public returnVariable?: VariableAdapter;

	protected constructor(
		public readonly name: string,
		public readonly referenceFrame: FrameAdapter
	) {
		this.threadAdapter.registerScopeAdapter(this);
		this.variablesProviderId = this.threadAdapter.debugSession.variablesProviders.register(this);
	}

	public static fromGrip(name: string, grip: FirefoxDebugProtocol.Grip, referenceFrame: FrameAdapter): ScopeAdapter {
		if ((typeof grip === 'object') && (grip.type === 'object')) {
			return new ObjectScopeAdapter(name, <FirefoxDebugProtocol.ObjectGrip>grip, referenceFrame);
		} else {
			return new SingleValueScopeAdapter(name, grip, referenceFrame);
		}
	}

	public addThis(thisValue: FirefoxDebugProtocol.Grip) {
		this.thisVariable = VariableAdapter.fromGrip(
			'this', this.referenceExpression, this.referenceFrame, thisValue, false, this.threadAdapter);
	}

	public addReturnValue(returnValue: FirefoxDebugProtocol.Grip) {
		this.returnVariable = VariableAdapter.fromGrip(
			'Return value', undefined, this.referenceFrame, returnValue, false, this.threadAdapter);
	}

	public getScope(): Scope {
		return new Scope(this.name, this.variablesProviderId);
	}

	public async getVariables(): Promise<VariableAdapter[]> {

		// we make a (shallow) copy of the variables array because we're going to modify it
		let variables = [ ...await this.getVariablesInt() ];

		if (this.thisVariable) {
			variables.unshift(this.thisVariable);
		}

		if (this.returnVariable) {
			variables.unshift(this.returnVariable);
		}

		return variables;
	}

	protected abstract getVariablesInt(): Promise<VariableAdapter[]>;

	public dispose(): void {
		this.threadAdapter.debugSession.variablesProviders.unregister(this.variablesProviderId);
	}
}

export class SingleValueScopeAdapter extends ScopeAdapter {

	private variableAdapter: VariableAdapter;

	public constructor(name: string, grip: FirefoxDebugProtocol.Grip, referenceFrame: FrameAdapter) {
		super(name, referenceFrame);
		this.variableAdapter = VariableAdapter.fromGrip(
			'', this.referenceExpression, this.referenceFrame, grip, false, this.threadAdapter);
	}

	protected getVariablesInt(): Promise<VariableAdapter[]> {
		return Promise.resolve([this.variableAdapter]);
	}
}

export class ObjectScopeAdapter extends ScopeAdapter {

	private variableAdapter: VariableAdapter;

	public constructor(name: string, object: FirefoxDebugProtocol.ObjectGrip, referenceFrame: FrameAdapter) {
		super(name, referenceFrame);
		this.variableAdapter = VariableAdapter.fromGrip(
			'', this.referenceExpression, this.referenceFrame, object, false, this.threadAdapter);
	}

	protected getVariablesInt(): Promise<VariableAdapter[]> {
		return this.variableAdapter.variablesProvider!.getVariables();
	}
}

export class LocalVariablesScopeAdapter extends ScopeAdapter {

	public variables: VariableAdapter[] = [];

	public constructor(name: string, variableDescriptors: FirefoxDebugProtocol.PropertyDescriptors, referenceFrame: FrameAdapter) {
		super(name, referenceFrame);

		for (let varname in variableDescriptors) {
			this.variables.push(VariableAdapter.fromPropertyDescriptor(
				varname, this.referenceExpression, this.referenceFrame,
				variableDescriptors[varname], false, this.threadAdapter));
		}

		VariableAdapter.sortVariables(this.variables);
	}

	protected getVariablesInt(): Promise<VariableAdapter[]> {
		return Promise.resolve(this.variables);
	}
}

export class FunctionScopeAdapter extends ScopeAdapter {

	public variables: VariableAdapter[] = [];

	public constructor(name: string, bindings: FirefoxDebugProtocol.FunctionBindings, referenceFrame: FrameAdapter) {
		super(name, referenceFrame);

		bindings.arguments.forEach((arg) => {
			for (let varname in arg) {
				this.variables.push(VariableAdapter.fromPropertyDescriptor(
					varname, this.referenceExpression, this.referenceFrame,
					arg[varname], false, this.threadAdapter));
			}
		});

		for (let varname in bindings.variables) {
			this.variables.push(VariableAdapter.fromPropertyDescriptor(
				varname, this.referenceExpression, this.referenceFrame,
				bindings.variables[varname], false, this.threadAdapter));
		}

		VariableAdapter.sortVariables(this.variables);
	}

	protected getVariablesInt(): Promise<VariableAdapter[]> {
		return Promise.resolve(this.variables);
	}
}


================================================
FILE: src/adapter/adapter/skipFilesManager.ts
================================================
import isAbsoluteUrl from 'is-absolute-url';
import { Log } from '../util/log';
import { isWindowsPlatform as detectWindowsPlatform } from '../../common/util';
import { SourcesManager } from './sourcesManager';
import { Registry } from './registry';
import { ThreadAdapter } from './thread';

let log = Log.create('SkipFilesManager');

/**
 * This class determines which files should be skipped (aka blackboxed). Files to be skipped are
 * configured using the `skipFiles` configuration property or by using the context menu on a
 * stackframe in VS Code.
 */
export class SkipFilesManager {

	private readonly isWindowsPlatform = detectWindowsPlatform();

	/**
	 * Files that were configured to (not) be skipped by using the context menu on a
	 * stackframe in VS Code. This overrides the `skipFiles` configuration property.
	 */
	private readonly dynamicFiles = new Map<string, boolean>();

	public constructor(
		private readonly configuredFilesToSkip: RegExp[],
		private readonly sources: SourcesManager,
		private readonly threads: Registry<ThreadAdapter>
	) {}

	public shouldSkip(pathOrUrl: string): boolean {

		if (this.dynamicFiles.has(pathOrUrl)) {

			let result = this.dynamicFiles.get(pathOrUrl)!;

			if (log.isDebugEnabled()) {
				log.debug(`skipFile is set dynamically to ${result} for ${pathOrUrl}`);
			}

			return result;
		}

		let testee = pathOrUrl.replace('/./', '/');
		if (this.isWindowsPlatform && !isAbsoluteUrl(pathOrUrl)) {
			testee = testee.replace(/\\/g, '/');
		}
		for (let regExp of this.configuredFilesToSkip) {

			if (regExp.test(testee)) {

				if (log.isDebugEnabled()) {
					log.debug(`skipFile is set per configuration to true for ${pathOrUrl}`);
				}

				return true;
			}
		}

		if (log.isDebugEnabled()) {
			log.debug(`skipFile is not set for ${pathOrUrl}`);
		}

		return false;
	}

	public async toggleSkipping(pathOrUrl: string): Promise<void> {
		
		const skipFile = !this.shouldSkip(pathOrUrl);
		this.dynamicFiles.set(pathOrUrl, skipFile);

		log.info(`Setting skipFile to ${skipFile} for ${pathOrUrl}`);

		let promises: Promise<void>[] = [];

		const sourceAdapters = this.sources.findSourceAdaptersForPathOrUrl(pathOrUrl);

		for (const sourceAdapter of sourceAdapters) {
			promises.push(sourceAdapter.setBlackBoxed(skipFile));
		}

		for (const [, thread] of this.threads) {
			thread.triggerStackframeRefresh();
		}

		await Promise.all(promises);
	}
}


================================================
FILE: src/adapter/adapter/source.ts
================================================
import { Log } from '../util/log';
import { MappedLocation } from '../location';
import { DebugProtocol } from '@vscode/debugprotocol';
import { Source } from '@vscode/debugadapter';
import { ISourceActorProxy } from '../firefox/actorProxy/source';
import { SourceMappingSourceActorProxy } from '../firefox/sourceMaps/source';
import { Registry } from './registry';

const log = Log.create('SourceAdapter');

/**
 * Adapter class for a javascript source.
 */
export class SourceAdapter {

	public readonly url: string | undefined;
	public readonly generatedUrl: string | undefined;
	public readonly introductionType: 'scriptElement' | 'eval' | 'Function' | 'debugger eval' | 'wasm' | undefined;
	public readonly id: number;
	public readonly source: Source;
	public readonly actors: SourceActorCollection;
	private blackboxed = false;

	public get isBlackBoxed() { return this.blackboxed; }

	public constructor(
		actor: ISourceActorProxy,
		/** the path or url as seen by VS Code */
		public readonly path: string | undefined,
		sourceRegistry: Registry<SourceAdapter>
	) {
		this.url = actor.url ?? undefined;
		if (actor instanceof SourceMappingSourceActorProxy) {
			this.generatedUrl = actor.underlyingActor.url ?? undefined;
		}
		this.introductionType = actor.source.introductionType ?? undefined;
		this.id = sourceRegistry.register(this);

		let sourceName = '';
		if (actor.url) {
			sourceName = actor.url.split('/').pop()!.split('#')[0];
		} else {
			sourceName = `${actor.source.introductionType || 'Script'} ${this.id}`;
		}

		if (path !== undefined) {
			this.source = new Source(sourceName, path);
		} else {
			this.source = new Source(sourceName, actor.url || undefined, this.id);
		}

		this.actors = new SourceActorCollection(actor);
	}

	public async setBlackBoxed(blackboxed: boolean) {
		if (this.blackboxed === blackboxed) {
			return;
		}
		this.blackboxed = blackboxed;
		(<DebugProtocol.Source>this.source).presentationHint = blackboxed ? 'deemphasize' : 'normal';
		await this.actors.runWithAllActors(actor => actor.setBlackbox(blackboxed));
	}

	public getBreakableLines(): Promise<number[]> {
		return this.actors.runWithSomeActor(actor => actor.getBreakableLines());
	}

	public getBreakableLocations(line: number): Promise<MappedLocation[]> {
		return this.actors.runWithSomeActor(actor => actor.getBreakableLocations(line));
	}

	public fetchSource(): Promise<FirefoxDebugProtocol.Grip> {
		return this.actors.runWithSomeActor(actor => actor.fetchSource());
	}

	public async findNextBreakableLocation(
		requestedLine: number,
		requestedColumn: number
	): Promise<MappedLocation | undefined> {

		let breakableLocations = await this.getBreakableLocations(requestedLine);
		for (const location of breakableLocations) {
			if (location.column >= requestedColumn) {
				return location;
			}
		}

		const breakableLines = await this.getBreakableLines();
		for (const line of breakableLines) {
			if (line > requestedLine) {
				breakableLocations = await this.getBreakableLocations(line);
				if (breakableLocations.length > 0) {
					return breakableLocations[0];
				}
			}
		}

		return undefined;
	}
}

export class SourceActorCollection {

	private readonly actors: ISourceActorProxy[];
	private someActor: Promise<ISourceActorProxy>;
	private resolveSomeActor: ((actor: ISourceActorProxy) => void) | undefined;

	public constructor(actor: ISourceActorProxy) {
		this.actors = [actor];
		this.someActor = Promise.resolve(actor);
	}

	public add(actor: ISourceActorProxy) {
		this.actors.push(actor);
		if (this.resolveSomeActor) {
			this.resolveSomeActor(actor);
			this.resolveSomeActor = undefined;
		}
	}

	public remove(actor: ISourceActorProxy) {
		const index = this.actors.indexOf(actor);
		if (index >= 0) {
			this.actors.splice(index, 1);
			if (this.actors.length > 0) {
				this.someActor = Promise.resolve(this.actors[0]);
			} else {
				this.someActor = new Promise(resolve => this.resolveSomeActor = resolve);
			}
		}
	}

	public async runWithSomeActor<T>(fn: (actor: ISourceActorProxy) => Promise<T>): Promise<T> {
		while (true) {
			const actor = await this.someActor;
			try {
				return await fn(actor);
			} catch (err: any) {
				if (err.error === 'noSuchActor') {
					this.remove(actor);
					continue;
				}
				throw err;
			}
		}
	}

	public async runWithAllActors<T>(fn: (actor: ISourceActorProxy) => Promise<T>): Promise<void> {
		await Promise.all(this.actors.map(actor => fn(actor)));
	}
}


================================================
FILE: src/adapter/adapter/sourcesManager.ts
================================================
import { Log } from '../util/log';
import { ISourceActorProxy } from "../firefox/actorProxy/source";
import { DeferredMap } from "../../common/deferredMap";
import { pathsAreEqual } from "../util/misc";
import { PathMapper } from "../util/pathMapper";
import { Registry } from "./registry";
import { SourceAdapter } from './source';
import { normalizePath } from '../util/fs';

const log = Log.create('SourcesManager');

export class SourcesManager {

	private readonly adapters = new Registry<SourceAdapter>();
	private readonly adaptersByPath = new DeferredMap<string, SourceAdapter>();
	private readonly adaptersByActor = new DeferredMap<string, SourceAdapter>();
	private readonly adaptersByUrl = new DeferredMap<string, SourceAdapter>();

	constructor(private readonly pathMapper: PathMapper) {}

	public addActor(actor: ISourceActorProxy) {
		log.debug(`Adding source ${actor.name}`);

		let adapter: SourceAdapter | undefined = actor.url ? this.adaptersByUrl.getExisting(actor.url) : undefined;
		const path = this.pathMapper.convertFirefoxSourceToPath(actor.source);
		const normalizedPath = path ? normalizePath(path) : undefined;

		if (adapter) {
			adapter.actors.add(actor);
		} else {
			if (normalizedPath) {
				adapter = this.adaptersByPath.getExisting(normalizedPath);
			}
			if (adapter) {
				adapter.actors.add(actor);
			} else {
				adapter = new SourceAdapter(actor, path, this.adapters);
			}
		}

		if (normalizedPath) {
			this.adaptersByPath.set(normalizedPath, adapter);
		}
		this.adaptersByActor.set(actor.name, adapter);
		if (actor.url) {
			this.adaptersByUrl.set(actor.url, adapter);
		}

		return adapter;
	}

	public removeActor(actor: ISourceActorProxy) {
		log.info(`Removing source ${actor.name}`);

		const adapter = this.adaptersByActor.getExisting(actor.name);
		if (!adapter) return;

		this.adaptersByActor.delete(actor.name);
		adapter.actors.remove(actor);
	}

	public getAdapterForID(id: number) {
		return this.adapters.find(id);
	}

	public getAdapterForPath(path: string) {
		return this.adaptersByPath.get(path);
	}

	public getExistingAdapterForPath(path: string) {
		return this.adaptersByPath.getExisting(path);
	}

	public getAdapterForActor(actor: string) {
		return this.adaptersByActor.get(actor);
	}

	public getAdapterForUrl(url: string) {
		return this.adaptersByUrl.get(url);
	}

	public findSourceAdaptersForPathOrUrl(pathOrUrl: string): SourceAdapter[] {
		if (!pathOrUrl) return [];

		return this.adapters.filter((sourceAdapter) =>
			pathsAreEqual(pathOrUrl, sourceAdapter.path) || (sourceAdapter.url === pathOrUrl)
		);
	}

	public findSourceAdaptersForUrlWithoutQuery(url: string): SourceAdapter[] {

		return this.adapters.filter((sourceAdapter) => {

			let sourceUrl = sourceAdapter.url;
			if (!sourceUrl) return false;

			let queryStringIndex = sourceUrl.indexOf('?');
			if (queryStringIndex >= 0) {
				sourceUrl = sourceUrl.substr(0, queryStringIndex);
			}

			return url === sourceUrl;
		});
	}
}


================================================
FILE: src/adapter/adapter/thread.ts
================================================
import { EventEmitter } from 'events';
import { IThreadActorProxy } from '../firefox/actorProxy/thread';
import { ConsoleActorProxy } from '../firefox/actorProxy/console';
import { FrameAdapter } from './frame';
import { ScopeAdapter } from './scope';
import { ObjectGripAdapter } from './objectGrip';
import { VariablesProvider } from './variablesProvider';
import { VariableAdapter } from './variable';
import { Variable } from '@vscode/debugadapter';
import { Log } from '../util/log';
import { FirefoxDebugSession } from '../firefoxDebugSession';
import { TargetActorProxy } from '../firefox/actorProxy/target';
import { ISourceActorProxy } from '../firefox/actorProxy/source';

let log = Log.create('ThreadAdapter');

export type TargetType = 'tab' | 'iframe' | 'worker' | 'backgroundScript' | 'contentScript';

/**
 * Adapter class for a thread
 */
export class ThreadAdapter extends EventEmitter {

	public id: number;
	public get actorName() {
		return this.actor.name;
	}
	public get url(): string | undefined {
		return this.targetActor.target.url;
	}

	/**
	 * All `SourceAdapter`s for this thread. They will be disposed when this `ThreadAdapter` is disposed.
	 */
	public readonly sourceActors = new Set<ISourceActorProxy>();

	/**
	 * When the thread is paused, this is set to a Promise that resolves to the `FrameAdapter`s for
	 * the stacktrace for the current thread pause. At the end of the thread pause, these are disposed.
	 */
	private framesPromise: Promise<FrameAdapter[]> | undefined = undefined;

	/**
	 * All `ScopeAdapter`s that have been created for the current thread pause. They will be disposed
	 * at the end of the thread pause.
	 */
	private scopes: ScopeAdapter[] = [];

	/**
	 * All `ObjectGripAdapter`s that should be disposed at the end of the current thread pause
	 */
	private pauseLifetimeObjects: ObjectGripAdapter[] = [];

	/**
	 * All `ObjectGripAdapter`s that should be disposed when this `ThreadAdapter` is disposed
	 */
	private threadLifetimeObjects: ObjectGripAdapter[] = [];

	public threadPausedReason?: FirefoxDebugProtocol.ThreadPausedReason;

	public constructor(
		public readonly type: TargetType,
		public readonly name: string,
		public readonly actor: IThreadActorProxy,
		public readonly targetActor: TargetActorProxy,
		private readonly consoleActor: ConsoleActorProxy,
		public readonly debugSession: FirefoxDebugSession
	) {
		super();
		this.id = debugSession.threads.register(this);
	}

	public registerScopeAdapter(scopeAdapter: ScopeAdapter) {
		this.scopes.push(scopeAdapter);
	}

	public registerObjectGripAdapter(objectGripAdapter: ObjectGripAdapter) {
		if (objectGripAdapter.threadLifetime) {
			this.threadLifetimeObjects.push(objectGripAdapter);
		} else {
			this.pauseLifetimeObjects.push(objectGripAdapter);
		}
	}

	/**
	 * extend the given adapter's lifetime to threadLifetime (if it isn't already)
	 */
	public threadLifetime(objectGripAdapter: ObjectGripAdapter): void {

		if (!objectGripAdapter.threadLifetime) {

			const index = this.pauseLifetimeObjects.indexOf(objectGripAdapter);
			if (index >= 0) {
				this.pauseLifetimeObjects.splice(index, 1);
			}

			this.threadLifetimeObjects.push(objectGripAdapter);
			objectGripAdapter.threadLifetime = true;
		}
	}

	public interrupt(): Promise<void> {
		return this.actor.interrupt();
	}

	public resume(): Promise<void> {
		return this.actor.resume();
	}

	public stepOver(): Promise<void> {
		return this.actor.resume('next');
	}

	public stepIn(): Promise<void> {
		return this.actor.resume('step');
	}

	public stepOut(): Promise<void> {
		return this.actor.resume('finish');
	}

	public restartFrame(frameActor: string): Promise<void> {
		return this.actor.resume('restart', frameActor);
	}

	public fetchAllStackFrames(): Promise<FrameAdapter[]> {

		if (!this.framesPromise) {
			this.framesPromise = (async () => {

				let frames = await this.actor.fetchStackFrames();

				let frameAdapters = frames.map((frame) =>
					new FrameAdapter(this.debugSession.frames, frame, this));

				let threadPausedReason = this.threadPausedReason;
				if ((threadPausedReason !== undefined) && (frameAdapters.length > 0)) {

					const scopeAdapters = await frameAdapters[0].getScopeAdapters();

					if (threadPausedReason.frameFinished !== undefined) {

						if (threadPausedReason.frameFinished.return !== undefined) {

							scopeAdapters[0].addReturnValue(
								threadPausedReason.frameFinished.return);

						} else if (threadPausedReason.frameFinished.throw !== undefined) {

							scopeAdapters.unshift(ScopeAdapter.fromGrip(
								'Exception', threadPausedReason.frameFinished.throw, frameAdapters[0]));
						}

					} else if (threadPausedReason.exception !== undefined) {

						scopeAdapters.unshift(ScopeAdapter.fromGrip(
							'Exception', threadPausedReason.exception, frameAdapters[0]));
					}
				}

				return frameAdapters;
			})();
		}

		return this.framesPromise;
	}

	public async fetchStackFrames(start: number, count: number): Promise<[FrameAdapter[], number]> {

		let frameAdapters = await this.fetchAllStackFrames();

		let requestedFrames = (count > 0) ? frameAdapters.slice(start, start + count) : frameAdapters.slice(start);

		return [requestedFrames, frameAdapters.length];
	}

	/** this will cause VS Code to reload the current stackframes from this adapter */
	public triggerStackframeRefresh(): void {
		this.debugSession.sendStoppedEvent(this, this.threadPausedReason);
	}

	public async fetchVariables(variablesProvider: VariablesProvider): Promise<Variable[]> {

		let variableAdapters = await variablesProvider.getVariables();

		return variableAdapters.map((variableAdapter) => variableAdapter.getVariable());
	}

	public evaluateRaw(expr: string, skipBreakpoints: boolean, frameActorName?: string): Promise<FirefoxDebugProtocol.Grip> {
		return this.consoleActor.evaluate(expr, skipBreakpoints, frameActorName);
	}

	public async evaluate(expr: string, skipBreakpoints: boolean, frameActorName?: string): Promise<Variable> {
		let grip = await this.consoleActor.evaluate(expr, skipBreakpoints, frameActorName);
		let variableAdapter = this.variableFromGrip(grip, true);
		return variableAdapter.getVariable();
	}

	public async autoComplete(text: string, column: number, frameActorName?: string): Promise<string[]> {
		return await this.consoleActor.autoComplete(text, column, frameActorName);
	}

	private variableFromGrip(grip: FirefoxDebugProtocol.Grip | undefined, threadLifetime: boolean): VariableAdapter {
		if (grip !== undefined) {
			return VariableAdapter.fromGrip('', undefined, undefined, grip, threadLifetime, this);
		} else {
			return new VariableAdapter('', undefined, undefined, 'undefined', this);
		}
	}

	/**
	 * Called by the `ThreadCoordinator` before resuming the thread
	 */
	public async disposePauseLifetimeAdapters(): Promise<void> {

		if (this.framesPromise) {
			let frames = await this.framesPromise;
			frames.forEach((frameAdapter) => {
				frameAdapter.dispose();
			});
			this.framesPromise = undefined;
		}

		this.scopes.forEach((scopeAdapter) => {
			scopeAdapter.dispose();
		});
		this.scopes = [];

		this.pauseLifetimeObjects.forEach((objectGripAdapter) => {
			objectGripAdapter.dispose();
		});

		this.pauseLifetimeObjects = [];
	}

	public async dispose(): Promise<void> {

		await this.disposePauseLifetimeAdapters();

		this.threadLifetimeObjects.forEach((objectGripAdapter) => {
			objectGripAdapter.dispose();
		});

		for (const sourceActor of this.sourceActors) {
			this.debugSession.sources.removeActor(sourceActor);
			sourceActor.dispose();
		}

		this.actor.dispose();
		this.targetActor.dispose();
		this.consoleActor.dispose();

		this.debugSession.threads.unregister(this.id);
	}
}


================================================
FILE: src/adapter/adapter/variable.ts
================================================
import { Log } from '../util/log';
import { ThreadAdapter } from './thread';
import { ObjectGripAdapter } from './objectGrip';
import { FrameAdapter } from './frame';
import { Variable } from '@vscode/debugadapter';
import { DebugProtocol } from '@vscode/debugprotocol';
import { accessorExpression, compareStrings } from '../util/misc';
import { renderPreview } from './preview';
import { VariablesProvider } from './variablesProvider';
import { GetterValueAdapter } from './getterValue';
import { ArgumentListAdapter } from './consoleAPICall';

let log = Log.create('VariableAdapter');

/**
 * Adapter class for anything that will be sent to VS Code as a Variable.
 * At the very least a Variable needs a name and a string representation of its value.
 * If the VariableAdapter represents anything that can have child variables, it also needs a
 * [`VariablesProvider`](./variablesProvider.ts) that will be used to fetch the child variables when
 * requested by VS Code.
 */
export class VariableAdapter {

	private _variablesProvider: VariablesProvider | undefined;

	public get variablesProvider(): VariablesProvider | undefined {
		return this._variablesProvider;
	}

	public constructor(
		public readonly varname: string,
		public readonly referenceExpression: string | undefined,
		public readonly referenceFrame: FrameAdapter | undefined,
		public readonly displayValue: string,
		public readonly threadAdapter: ThreadAdapter
	) {}

	public getVariable(): Variable {

		let variable = new Variable(this.varname, this.displayValue,
			this.variablesProvider ? this.variablesProvider.variablesProviderId : undefined);

		(<DebugProtocol.Variable>variable).evaluateName = this.referenceExpression;

		return variable;
	}

	/**
	 * factory function for creating a VariableAdapter from an
	 * [object grip](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md#objects)
	 */
	public static fromGrip(
		varname: string,
		parentReferenceExpression: string | undefined,
		referenceFrame: FrameAdapter | undefined,
		grip: FirefoxDebugProtocol.Grip,
		threadLifetime: boolean,
		threadAdapter: ThreadAdapter,
		useParentReferenceExpression?: boolean
	): VariableAdapter {

		let referenceExpression =
			useParentReferenceExpression ?
			parentReferenceExpression :
			accessorExpression(parentReferenceExpression, varname);

		if ((typeof grip === 'boolean') || (typeof grip === 'number')) {

			return new VariableAdapter(varname, referenceExpression, referenceFrame, grip.toString(), threadAdapter);

		} else if (typeof grip === 'string') {

			return new VariableAdapter(varname, referenceExpression, referenceFrame, `"${grip}"`, threadAdapter);

		} else {

			switch (grip.type) {

				case 'null':
				case 'undefined':
				case 'Infinity':
				case '-Infinity':
				case 'NaN':
				case '-0':

					return new VariableAdapter(
						varname, referenceExpression, referenceFrame, grip.type, threadAdapter);

				case 'BigInt':

					return new VariableAdapter(
						varname, referenceExpression, referenceFrame,
						`${(<FirefoxDebugProtocol.BigIntGrip>grip).text}n`, threadAdapter);

				case 'longString':

					return new VariableAdapter(
						varname, referenceExpression, referenceFrame,
						(<FirefoxDebugProtocol.LongStringGrip>grip).initial, threadAdapter);

				case 'symbol':

					let symbolName = (<FirefoxDebugProtocol.SymbolGrip>grip).name;
					return new VariableAdapter(
						varname, referenceExpression, referenceFrame,
						`Symbol(${symbolName})`, threadAdapter);

				case 'object':

					let objectGrip = <FirefoxDebugProtocol.ObjectGrip>grip;
					let displayValue = renderPreview(objectGrip);
					let variableAdapter = new VariableAdapter(
						varname, referenceExpression, referenceFrame, displayValue, threadAdapter);
					variableAdapter._variablesProvider = new ObjectGripAdapter(
						variableAdapter, objectGrip, threadLifetime, (varname === '__proto__'));
					return variableAdapter;

				default:

					log.warn(`Unexpected object grip of type ${grip.type}: ${JSON.stringify(grip)}`);
					return new VariableAdapter(
						varname, referenceExpression, referenceFrame, grip.type, threadAdapter);

			}
		}
	}

	/**
	 * factory function for creating a VariableAdapter from a
	 * [property descriptor](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md#property-descriptors)
	 */
	public static fromPropertyDescriptor(
		varname: string,
		parentReferenceExpression: string | undefined,
		referenceFrame: FrameAdapter | undefined,
		propertyDescriptor: FirefoxDebugProtocol.PropertyDescriptor,
		threadLifetime: boolean,
		threadAdapter: ThreadAdapter
	): VariableAdapter {

		if ((<FirefoxDebugProtocol.DataPropertyDescriptor>propertyDescriptor).value !== undefined) {

			return VariableAdapter.fromGrip(
				varname, parentReferenceExpression, referenceFrame,
				(<FirefoxDebugProtocol.DataPropertyDescriptor>propertyDescriptor).value,
				threadLifetime, threadAdapter);

		} else {

			let referenceExpression = accessorExpression(parentReferenceExpression, varname);

			let accessorPropertyDescriptor = <FirefoxDebugProtocol.AccessorPropertyDescriptor>propertyDescriptor;
			let hasGetter = VariableAdapter.isFunctionGrip(accessorPropertyDescriptor.get);
			let hasSetter = VariableAdapter.isFunctionGrip(accessorPropertyDescriptor.set);
			let displayValue: string;
			if (hasGetter) {
				displayValue = 'Getter';
				if (hasSetter) {
					displayValue += ' & Setter';
				}
				displayValue += ' - expand to execute Getter';
			} else if (hasSetter) {
				displayValue = 'Setter';
			} else {
				log.error(`${referenceExpression} is neither a data property nor does it have a getter or setter`);
				displayValue = 'Error';
			}

			let variableAdapter = new VariableAdapter(
				varname, referenceExpression, referenceFrame, displayValue, threadAdapter);

			if (hasGetter) {
				variableAdapter._variablesProvider = new GetterValueAdapter(variableAdapter);
			}

			return variableAdapter;

		}
	}

	/**
	 * factory function for creating a VariableAdapter from a
	 * [safe getter value descriptor](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md#property-descriptors)
	 */
	public static fromSafeGetterValueDescriptor(
		varname: string,
		parentReferenceExpression: string | undefined,
		referenceFrame: FrameAdapter | undefined,
		safeGetterValueDescriptor: FirefoxDebugProtocol.SafeGetterValueDescriptor,
		threadLifetime: boolean,
		threadAdapter: ThreadAdapter
	): VariableAdapter {

		return VariableAdapter.fromGrip(
			varname, parentReferenceExpression, referenceFrame,
			safeGetterValueDescriptor.getterValue, threadLifetime, threadAdapter);
	}

	public static fromArgumentList(
		args: VariableAdapter[],
		preview: string,
		threadAdapter: ThreadAdapter
	): VariableAdapter {
		const variableAdapter = new VariableAdapter('arguments', undefined, undefined, preview, threadAdapter);
		variableAdapter._variablesProvider = new ArgumentListAdapter(args, threadAdapter);
		return variableAdapter;
	}

	public static sortVariables(variables: VariableAdapter[]): void {
		variables.sort((var1, var2) => compareStrings(var1.varname, var2.varname));
	}

	private static isFunctionGrip(grip: FirefoxDebugProtocol.Grip) {
		return (
			(typeof grip === 'object') &&
			(grip.type === 'object') &&
			((<FirefoxDebugProtocol.ObjectGrip>grip).class === 'Function')
		);
	}
}


================================================
FILE: src/adapter/adapter/variablesProvider.ts
================================================
import { ThreadAdapter } from './thread';
import { VariableAdapter } from './variable';
import { FrameAdapter } from './frame';

/**
 * This interface must be implemented by any adapter that can provide child variables.
 */
export interface VariablesProvider {
	readonly variablesProviderId: number;
	readonly threadAdapter: ThreadAdapter;
	readonly referenceFrame: FrameAdapter | undefined;
	readonly referenceExpression: string | undefined;
	getVariables(): Promise<VariableAdapter[]>;
}


================================================
FILE: src/adapter/configuration.ts
================================================
import * as os from 'os';
import * as path from 'path';
import * as uuid from 'uuid';
import isAbsoluteUrl from 'is-absolute-url';
import RegExpEscape from 'escape-string-regexp';
import { Log } from './util/log';
import { findAddonId, normalizePath } from './util/misc';
import { isExecutable } from './util/fs';
import { Minimatch } from 'minimatch';
import FirefoxProfile from 'firefox-profile';
import { isWindowsPlatform } from '../common/util';
import { LaunchConfiguration, AttachConfiguration, CommonConfiguration, ReloadConfiguration, DetailedReloadConfiguration, TabFilterConfiguration } from '../common/configuration';
import { urlDirname } from './util/net';

let log = Log.create('ParseConfiguration');

export interface NormalizedReloadConfiguration {
	watch: string[];
	ignore: string[];
	debounce: number;
}

export interface ParsedTabFilterConfiguration {
	include: RegExp[];
	exclude: RegExp[];
}

export interface ParsedConfiguration {
	attach?: ParsedAttachConfiguration;
	launch?: ParsedLaunchConfiguration;
	addon?: ParsedAddonConfiguration;
	pathMappings: PathMappings;
	pathMappingIndex: string;
	filesToSkip: RegExp[];
	reloadOnChange?: NormalizedReloadConfiguration,
	tabFilter: ParsedTabFilterConfiguration,
	clearConsoleOnReload: boolean,
	showConsoleCallLocation: boolean;
	liftAccessorsFromPrototypes: number;
	suggestPathMappingWizard: boolean;
	terminate: boolean;
	enableCRAWorkaround: boolean;
}

export interface ParsedAttachConfiguration {
	host: string;
	port: number;
	url?: string;
	firefoxExecutable?: string;
	profileDir?: string;
	reloadTabs: boolean;
}

export interface FirefoxPreferences {
	[key: string]: boolean | number | string;
}

type PathMapping = { url: string | RegExp, path: string | null };
export type PathMappings = PathMapping[];

export interface ParsedLaunchConfiguration {
	firefoxExecutable: string;
	firefoxArgs: string[];
	profileDir: string;
	srcProfileDir?: string;
	preferences: FirefoxPreferences;
	tmpDirs: string[];
	port: number;
	timeout: number;
	detached: boolean;
}

export interface ParsedAddonConfiguration {
	path: string;
	id: string | undefined;
	popupAutohideButton: boolean;
}

/**
 * Reads the configuration that was provided by VS Code, checks that it's consistent,
 * adds default values and returns it in a form that is easier to work with
 */
export async function parseConfiguration(
	config: LaunchConfiguration | AttachConfiguration
): Promise<ParsedConfiguration> {

	let attach: ParsedAttachConfiguration | undefined = undefined;
	let launch: ParsedLaunchConfiguration | undefined = undefined;
	let addon: ParsedAddonConfiguration | undefined = undefined;
	let port = config.port || 6000;
	let timeout = 5;
	let pathMappings: PathMappings = [];
	let url: string | undefined = undefined;

	if (config.request === 'launch') {

		let tmpDirs: string[] = [];

		if (config.reAttach) {
			attach = {
				host: 'localhost', port,
				reloadTabs: (config.reloadOnAttach !== false)
			};
		}

		let firefoxExecutable = await findFirefoxExecutable(config.firefoxExecutable);

		let firefoxArgs: string[] = [ '-start-debugger-server', String(port), '-no-remote' ];
		if (config.firefoxArgs) {
			firefoxArgs.push(...config.firefoxArgs);
		}

		let { profileDir, srcProfileDir } = await parseProfileConfiguration(config, tmpDirs);

		firefoxArgs.push('-profile', profileDir);

		let preferences = createFirefoxPreferences(config.preferences);

		if (config.file) {
			if (!path.isAbsolute(config.file)) {
				throw 'The "file" property in the launch configuration has to be an absolute path';
			}

			let fileUrl = config.file;
			if (isWindowsPlatform()) {
				fileUrl = 'file:///' + fileUrl.replace(/\\/g, '/');
			} else {
				fileUrl = 'file://' + fileUrl;
			}
			firefoxArgs.push(fileUrl);
			url = fileUrl;

		} else if (config.url) {
			firefoxArgs.push(config.url);
			url = config.url;
		} else if (config.addonPath) {
			firefoxArgs.push('about:blank');
		} else {
			throw 'You need to set either "file" or "url" in the launch configuration';
		}

		if (typeof config.timeout === 'number') {
			timeout = config.timeout;
		}

		let detached = true;
		if (os.platform() === 'darwin') {
			if (!config.reAttach) {
				detached = false;
				if (config.keepProfileChanges) {
					// on MacOS we need to terminate the browser using `process.kill()`, which may
					// be interpreted by Firefox as a crash, so we add this option to prevent
					// starting into safe mode
					preferences['toolkit.startup.max_resumed_crashes'] = -1;
				}
			}
		}

		launch = {
			firefoxExecutable, firefoxArgs, profileDir, srcProfileDir,
			preferences, tmpDirs, port, timeout, detached
		};

	} else { // config.request === 'attach'

		const firefoxExecutable = config.firefoxExecutable ? await findFirefoxExecutable(config.firefoxExecutable) : undefined;

		url = config.url;
		attach = {
			host: config.host || 'localhost', port, url, firefoxExecutable, profileDir: config.profileDir,
			reloadTabs: !!config.reloadOnAttach
		};
	}

	if (config.pathMappings) {
		pathMappings.push(...config.pathMappings.map(harmonizeTrailingSlashes).map(handleWildcards));
	}

	if (config.addonPath) {
		addon = await parseAddonConfiguration(config, pathMappings);
	}

	const webRoot = parseWebRootConfiguration(config, pathMappings);

	if (webRoot) {
		pathMappings.push({ url: 'webpack:///~/', path: webRoot + '/node_modules/' });
		pathMappings.push({ url: 'webpack:///./~/', path: webRoot + '/node_modules/' });
		pathMappings.push({ url: 'webpack:///./', path: webRoot + '/' });
		pathMappings.push({ url: 'webpack:///src/', path: webRoot + '/src/' });
		pathMappings.push({ url: 'webpack:///node_modules/', path: webRoot + '/node_modules/' });
		pathMappings.push({ url: 'webpack:///webpack', path: null });
		pathMappings.push({ url: 'webpack:///(webpack)', path: null });
		pathMappings.push({ url: 'webpack:///pages/', path: webRoot + '/pages/' });
		pathMappings.push({ url: 'webpack://[name]_[chunkhash]/node_modules/', path: webRoot + '/node_modules/' });
		pathMappings.push({ url: 'webpack://[name]_[chunkhash]/', path: null });
	}
	pathMappings.push({ url: (isWindowsPlatform() ? 'webpack:///' : 'webpack://'), path: '' });

	pathMappings.push({ url: (isWindowsPlatform() ? 'file:///' : 'file://'), path: ''});

	const pathMappingIndex = config.pathMappingIndex ?? 'index.html';

	let filesToSkip = parseSkipFilesConfiguration(config);

	let reloadOnChange = parseReloadConfiguration(config.reloadOnChange);

	const tabFilter = parseTabFilterConfiguration(config.tabFilter, url);

	const clearConsoleOnReload = !!config.clearConsoleOnReload;

	let showConsoleCallLocation = config.showConsoleCallLocation || false;
	let liftAccessorsFromPrototypes = config.liftAccessorsFromPrototypes || 0;
	let suggestPathMappingWizard = config.suggestPathMappingWizard;
	if (suggestPathMappingWizard === undefined) {
		suggestPathMappingWizard = true;
	}
	const terminate = (config.request === 'launch') && !config.reAttach;
	const enableCRAWorkaround = !!config.enableCRAWorkaround;

	return {
		attach, launch, addon, pathMappings, pathMappingIndex, filesToSkip, reloadOnChange, tabFilter, clearConsoleOnReload,
		showConsoleCallLocation, liftAccessorsFromPrototypes, suggestPathMappingWizard, terminate,
		enableCRAWorkaround
	};
}

function harmonizeTrailingSlashes(pathMapping: PathMapping): PathMapping {

	if ((typeof pathMapping.url === 'string') && (typeof pathMapping.path === 'string') &&
		(pathMapping.path.length > 0)) {

		if (pathMapping.url.endsWith('/')) {
			if (pathMapping.path.endsWith('/')) {
				return pathMapping;
			} else {
				return { url: pathMapping.url, path: pathMapping.path + '/' };
			}
		} else {
			if (pathMapping.path.endsWith('/')) {
				return { url: pathMapping.url + '/', path: pathMapping.path };
			} else {
				return pathMapping;
			}
		}

	} else {
		return pathMapping;
	}
}

function handleWildcards(pathMapping: PathMapping): PathMapping {

	if ((typeof pathMapping.url === 'string') && (pathMapping.url.indexOf('*') >= 0)) {

		const regexp = '^' + pathMapping.url.split('*').map(RegExpEscape).join('[^/]*') + '(.*)$';

		return {
			url: new RegExp(regexp),
			path: pathMapping.path
		};

	} else {
		return pathMapping;
	}
}

async function findFirefoxExecutable(configuredPath?: string): Promise<string> {

	let candidates: string[];
	if (configuredPath) {
		if ([ 'stable', 'developer', 'nightly' ].indexOf(configuredPath) >= 0) {
			candidates = getExecutableCandidates(configuredPath as any);
		} else if (await isExecutable(configuredPath)) {
			return configuredPath;
		} else {
			throw 'Couldn\'t find the Firefox executable. Please correct the path given in your launch configuration.';
		}
	} else {
		candidates = getExecutableCandidates();
	}

	for (let i = 0; i < candidates.length; i++) {
		if (await isExecutable(candidates[i])) {
			return candidates[i];
		}
	}

	throw 'Couldn\'t find the Firefox executable. Please specify the path by setting "firefoxExecutable" in your launch configuration.';
}

export function getExecutableCandidates(edition?: 'stable' | 'developer' | 'nightly'): string[] {

	if (edition === undefined) {
		return [ ...getExecutableCandidates('developer'), ...getExecutableCandidates('stable') ];
	}

	const platform = os.platform();

	if ([ 'linux', 'freebsd', 'sunos' ].indexOf(platform) >= 0) {
		const paths = process.env.PATH!.split(':');
		switch (edition) {

			case 'stable':
				return [
					...paths.map(dir => path.join(dir, 'firefox'))
				];

			case 'developer':
				return [
					...paths.map(dir => path.join(dir, 'firefox-developer-edition')),
					...paths.map(dir => path.join(dir, 'firefox-developer')),
				];

			case 'nightly':
				return [
					...paths.map(dir => path.join(dir, 'firefox-nightly')),
				];
		}
	}

	switch (edition) {

		case 'stable':
			if (platform === 'darwin') {
				return [ '/Applications/Firefox.app/Contents/MacOS/firefox' ];
			} else if (platform === 'win32') {
				return [
					'C:\\Program Files\\Mozilla Firefox\\firefox.exe',
					'C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe'
				];
			}
			break;

		case 'developer':
			if (platform === 'darwin') {
				return [
					'/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox',
					'/Applications/FirefoxDeveloperEdition.app/Contents/MacOS/firefox'
				];
			} else if (platform === 'win32') {
				return [
					'C:\\Program Files\\Firefox Developer Edition\\firefox.exe',
					'C:\\Program Files (x86)\\Firefox Developer Edition\\firefox.exe'
				];
			}
			break;

		case 'nightly':
			if (platform === 'darwin') {
				return [ '/Applications/Firefox Nightly.app/Contents/MacOS/firefox' ]
			} else if (platform === 'win32') {
				return [
					'C:\\Program Files\\Firefox Nightly\\firefox.exe',
					'C:\\Program Files (x86)\\Firefox Nightly\\firefox.exe'
				];
			}
			break;
	}

	return [];
}

async function parseProfileConfiguration(config: LaunchConfiguration, tmpDirs: string[])
: Promise<{ profileDir: string, srcProfileDir?: string }> {

	let profileDir: string;
	let srcProfileDir: string | undefined;

	if (config.profileDir) {
		if (config.profile) {
			throw 'You can set either "profile" or "profileDir", but not both';
		}
		srcProfileDir = config.profileDir;
	} else if (config.profile) {
		srcProfileDir = await findFirefoxProfileDir(config.profile);
	}

	if (config.keepProfileChanges) {
		if (srcProfileDir) {
			profileDir = srcProfileDir;
			srcProfileDir = undefined;
		} else {
			throw 'To enable "keepProfileChanges" you need to set either "profile" or "profileDir"';
		}
	} else {
		const tmpDir = config.tmpDir || os.tmpdir();
		profileDir = path.join(tmpDir, `vscode-firefox-debug-profile-${uuid.v4()}`);
		tmpDirs.push(profileDir);
	}

	return { profileDir, srcProfileDir };
}

function findFirefoxProfileDir(profileName: string): Promise<string | undefined> {
	return new Promise<string | undefined>((resolve, reject) => {

		let finder = new FirefoxProfile.Finder();

		finder.getPath(profileName, (err, path) => {
			if (err) {
				reject(err);
			} else {
				resolve(path);
			}
		});
	});
}

function createFirefoxPreferences(
	additionalPreferences?: { [key: string]: boolean | number | string | null }
): FirefoxPreferences {

	let preferences: FirefoxPreferences = {};

	// Remote debugging settings
	preferences['devtools.chrome.enabled'] = true;
	preferences['devtools.debugger.prompt-connection'] = false;
	preferences['devtools.debugger.remote-enabled'] = true;
	preferences['extensions.autoDisableScopes'] = 10;
	preferences['xpinstall.signatures.required'] = false;
	preferences['extensions.sdk.console.logLevel'] = 'all';
	// Skip check for default browser on startup
	preferences['browser.shell.checkDefaultBrowser'] = false;
	// Hide the telemetry infobar
	preferences['datareporting.policy.dataSubmissionPolicyBypassNotification'] = true;
	// Do not redirect user when a milestone upgrade of Firefox is detected
	preferences['browser.startup.homepage_override.mstone'] = 'ignore';
	// Disable the UI tour
	preferences['browser.uitour.enabled'] = false;
	// Do not warn on quitting Firefox
	preferences['browser.warnOnQuit'] = false;

	if (additionalPreferences !== undefined) {
		for (let key in additionalPreferences) {
			let value = additionalPreferences[key];
			if (value !== null) {
				preferences[key] = value;
			} else {
				delete preferences[key];
			}
		}
	}

	return preferences;
}

function parseWebRootConfiguration(config: CommonConfiguration, pathMappings: PathMappings): string | undefined {

	if (config.url) {
		if (!config.webRoot) {
			if ((config.request === 'launch') && !config.pathMappings) {
				throw `If you set "url" you also have to set "webRoot" or "pathMappings" in the ${config.request} configuration`;
			}
			return undefined;
		} else if (!path.isAbsolute(config.webRoot) && !isAbsoluteUrl(config.webRoot)) {
			throw `The "webRoot" property in the ${config.request} configuration has to be an absolute path`;
		}

		let webRootUrl = config.url;
		if (webRootUrl.lastIndexOf('/') > 7) {
			webRootUrl = webRootUrl.substr(0, webRootUrl.lastIndexOf('/'));
		}

		let webRoot = isAbsoluteUrl(config.webRoot) ? config.webRoot : normalizePath(config.webRoot);

		pathMappings.forEach((pathMapping) => {
			const to = pathMapping.path;
			if ((typeof to === 'string') && (to.substr(0, 10) === '${webRoot}')) {
				pathMapping.path = webRoot + to.substr(10);
			}
		});

		pathMappings.push({ url: webRootUrl, path: webRoot });

		return webRoot;

	} else if (config.webRoot) {
		throw `If you set "webRoot" you also have to set "url" in the ${config.request} configuration`;
	}

	return undefined;
}

function parseSkipFilesConfiguration(config: CommonConfiguration): RegExp[] {

	let filesToSkip: RegExp[] = [];

	if (config.skipFiles) {
		config.skipFiles.forEach((glob) => {

			let minimatch = new Minimatch(glob);
			let regExp = minimatch.makeRe();

			if (regExp) {
				filesToSkip.push(regExp);
			} else {
				log.warn(`Invalid glob pattern "${glob}" specified in "skipFiles"`);
			}
		})
	}

	return filesToSkip;
}

function parseReloadConfiguration(
	reloadConfig: ReloadConfiguration | undefined
): NormalizedReloadConfiguration | undefined {

	if (reloadConfig === undefined) {
		return undefined;
	}

	const defaultDebounce = 100;

	if (typeof reloadConfig === 'string') {

		return {
			watch: [ normalizePath(reloadConfig) ],
			ignore: [],
			debounce: defaultDebounce
		};

	} else if (Array.isArray(reloadConfig)) {

		return {
			watch: reloadConfig.map(path => normalizePath(path)),
			ignore: [],
			debounce: defaultDebounce
		};

	} else {

		let _config = <DetailedReloadConfiguration>reloadConfig;

		let watch: string[];
		if (typeof _config.watch === 'string') {
			watch = [ _config.watch ];
		} else {
			watch = _config.watch;
		}

		watch = watch.map((path) => normalizePath(path));

		let ignore: string[];
		if (_config.ignore === undefined) {
			ignore = [];
		} else if (typeof _config.ignore === 'string') {
			ignore = [ _config.ignore ];
		} else {
			ignore = _config.ignore;
		}

		ignore = ignore.map((path) => normalizePath(path));

		let debounce: number;
		if (typeof _config.debounce === 'number') {
			debounce = _config.debounce;
		} else {
			debounce = (_config.debounce !== false) ? defaultDebounce : 0;
		}

		return { watch, ignore, debounce };
	}
}

function parseTabFilterConfiguration(
	tabFilterConfig?: TabFilterConfiguration,
	url?: string
): ParsedTabFilterConfiguration {

	if (tabFilterConfig === undefined) {

		if (url) {
			return { include: [ new RegExp(RegExpEscape(urlDirname(url)) + '.*') ], exclude: [] };
		} else {
			return { include: [ /.*/ ], exclude: [] };
		}

	}

	if ((typeof tabFilterConfig === 'string') || Array.isArray(tabFilterConfig)) {

		return { include: parseTabFilter(tabFilterConfig), exclude: [] }

	} else {

		return {
			include: (tabFilterConfig.include !== undefined) ? parseTabFilter(tabFilterConfig.include) : [ /.*/ ],
			exclude: (tabFilterConfig.exclude !== undefined) ? parseTabFilter(tabFilterConfig.exclude) : []
		}
	}
}

function parseTabFilter(tabFilter: string | string[]): RegExp[] {

	if (typeof tabFilter === 'string') {

		const parts = tabFilter.split('*').map(part => RegExpEscape(part));
		const regExp = new RegExp(`^${parts.join('.*')}$`);
		return [ regExp ];

	} else {

		return tabFilter.map(f => parseTabFilter(f)[0]);

	}
}

async function parseAddonConfiguration(
	config: LaunchConfiguration | AttachConfiguration,
	pathMappings: PathMappings
): Promise<ParsedAddonConfiguration> {

	let addonPath = config.addonPath!;
	const popupAutohideButton = (config.popupAutohideButton !== false);

	let addonId = await findAddonId(addonPath);

	let sanitizedAddonPath = addonPath;
	if (sanitizedAddonPath[sanitizedAddonPath.length - 1] === '/') {
		sanitizedAddonPath = sanitizedAddonPath.substr(0, sanitizedAddonPath.length - 1);
	}
	pathMappings.push({
		url: new RegExp('^moz-extension://[0-9a-f-]*(/.*)$'),
		path: sanitizedAddonPath
	});

	if (addonId) {
		// this pathMapping may no longer be necessary, I haven't seen this kind of URL recently...
		let rewrittenAddonId = addonId.replace('{', '%7B').replace('}', '%7D');
		pathMappings.push({
			url: new RegExp(`^jar:file:.*/extensions/${rewrittenAddonId}.xpi!(/.*)$`),
			path: sanitizedAddonPath
		});
	}

	return {
		path: addonPath, id: addonId, popupAutohideButton
	}
}


================================================
FILE: src/adapter/debugAdapterBase.ts
================================================
import process from 'process';
import util from 'util';
import { DebugProtocol } from '@vscode/debugprotocol';
import { DebugSession } from '@vscode/debugadapter';
import { Log } from './util/log';

const log = Log.create('main');
process.on('unhandledRejection', (e: any) => log.error(`Unhandled rejection: ${util.inspect(e)}\n${e.stack}`));

/**
 * This class extends the base class provided by VS Code for debug adapters,
 * offering a Promise-based API instead of the callback-based API used by VS Code
 */
export abstract class DebugAdapterBase extends DebugSession {

	public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) {
		super(debuggerLinesStartAt1, isServer);
	}

	protected abstract initialize(args: DebugProtocol.InitializeRequestArguments): DebugProtocol.Capabilities | undefined;
	protected abstract launch(args: DebugProtocol.LaunchRequestArguments): Promise<void>;
	protected abstract attach(args: DebugProtocol.AttachRequestArguments): Promise<void>;
	protected abstract disconnect(args: DebugProtocol.DisconnectArguments): Promise<void>;
	protected abstract breakpointLocations(args: DebugProtocol.BreakpointLocationsArguments): Promise<{ breakpoints: DebugProtocol.BreakpointLocation[] }>;
	protected abstract setBreakpoints(args: DebugProtocol.SetBreakpointsArguments): { breakpoints: DebugProtocol.Breakpoint[] };
	protected abstract setExceptionBreakpoints(args: DebugProtocol.SetExceptionBreakpointsArguments): void;
	protected abstract pause(args: DebugProtocol.PauseArguments): Promise<void>;
	protected abstract next(args: DebugProtocol.NextArguments): Promise<void>;
	protected abstract stepIn(args: DebugProtocol.StepInArguments): Promise<void>;
	protected abstract stepOut(args: DebugProtocol.StepOutArguments): Promise<void>;
	protected abstract continue(args: DebugProtocol.ContinueArguments): Promise<{ allThreadsContinued?: boolean }>;
	protected abstract getSource(args: DebugProtocol.SourceArguments): Promise<{ content: string, mimeType?: string }>;
	protected abstract getThreads(): { threads: DebugProtocol.Thread[] };
	protected abstract getStackTrace(args: DebugProtocol.StackTraceArguments): Promise<{ stackFrames: DebugProtocol.StackFrame[], totalFrames?: number }>;
	protected abstract getScopes(args: DebugProtocol.ScopesArguments): Promise<{ scopes: DebugProtocol.Scope[] }>;
	protected abstract getVariables(args: DebugProtocol.VariablesArguments): Promise<{ variables: DebugProtocol.Variable[] }>;
	protected abstract setVariable(args: DebugProtocol.SetVariableArguments): Promise<{ value: string, variablesReference?: number }>;
	protected abstract evaluate(args: DebugProtocol.EvaluateArguments): Promise<{ result: string, type?: string, variablesReference: number, namedVariables?: number, indexedVariables?: number }>;
	protected abstract getCompletions(args: DebugProtocol.CompletionsArguments): Promise<{ targets: DebugProtocol.CompletionItem[] }>;
	protected abstract dataBreakpointInfo(args: DebugProtocol.DataBreakpointInfoArguments): Promise<{ dataId: string | null, description: string, accessTypes?: DebugProtocol.DataBreakpointAccessType[], canPersist?: boolean }>;
	protected abstract setDataBreakpoints(args: DebugProtocol.SetDataBreakpointsArguments): Promise<{ breakpoints: DebugProtocol.Breakpoint[] }>;
	protected abstract restartFrame(args: DebugProtocol.RestartFrameArguments): Promise<void>;
	protected abstract reloadAddon(): Promise<void>;
	protected abstract toggleSkippingFile(url: string): Promise<void>;
	protected abstract setPopupAutohide(popupAutohide: boolean): Promise<void>;
	protected abstract togglePopupAutohide(): Promise<boolean>;
	protected abstract setActiveEventBreakpoints(args: string[]): Promise<void>;

	protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
		this.handleRequest(response, () => this.initialize(args));
	}

	protected disconnectRequest(response: DebugProtocol.DisconnectResponse, args: DebugProtocol.DisconnectArguments): void {
		this.handleRequestAsync(response, () => this.disconnect(args));
	}

	protected launchRequest(response: DebugProtocol.LaunchResponse, args: DebugProtocol.LaunchRequestArguments): void {
		this.handleRequestAsync(response, () => this.launch(args));
	}

	protected attachRequest(response: DebugProtocol.AttachResponse, args: DebugProtocol.AttachRequestArguments): void {
		this.handleRequestAsync(response, () => this.attach(args));
	}

	protected breakpointLocationsRequest(response: DebugProtocol.BreakpointLocationsResponse, args: DebugProtocol.BreakpointLocationsArguments, request?: DebugProtocol.Request): void {
		this.handleRequestAsync(response, () => this.breakpointLocations(args));
	}

	protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
		this.handleRequest(response, () => this.setBreakpoints(args));
	}

	protected setExceptionBreakPointsRequest(response: DebugProtocol.SetExceptionBreakpointsResponse, args: DebugProtocol.SetExceptionBreakpointsArguments): void {
		this.handleRequest(response, () => this.setExceptionBreakpoints(args));
	}

	protected pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments): void {
		this.handleRequestAsync(response, () => this.pause(args));
	}

	protected nextRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments): void {
		this.handleRequestAsync(response, () => this.next(args));
	}

	protected stepInRequest(response: DebugProtocol.StepInResponse, args: DebugProtocol.StepInArguments): void {
		this.handleRequestAsync(response, () => this.stepIn(args));
	}

	protected stepOutRequest(response: DebugProtocol.StepOutResponse, args: DebugProtocol.StepOutArguments): void {
		this.handleRequestAsync(response, () => this.stepOut(args));
	}

	protected continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
		this.handleRequestAsync(response, () => this.continue(args));
	}

	protected sourceRequest(response: DebugProtocol.SourceResponse, args: DebugProtocol.SourceArguments): void {
		this.handleRequestAsync(response, () => this.getSource(args));
	}

	protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {
		this.handleRequest(response, () => this.getThreads());
	}

	protected stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): void {
		this.handleRequestAsync(response, () => this.getStackTrace(args));
	}

	protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
		this.handleRequestAsync(response, () => this.getScopes(args));
	}

	protected variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): void {
		this.handleRequestAsync(response, () => this.getVariables(args));
	}

	protected setVariableRequest(response: DebugProtocol.SetVariableResponse, args: DebugProtocol.SetVariableArguments): void {
		this.handleRequestAsync(response, () => this.setVariable(args));
	}

	protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void {
		this.handleRequestAsync(response, () => this.evaluate(args));
	}

	protected completionsRequest(response: DebugProtocol.CompletionsResponse, args: DebugProtocol.CompletionsArguments): void {
		this.handleRequestAsync(response, () => this.getCompletions(args));
	}

	protected dataBreakpointInfoRequest(response: DebugProtocol.DataBreakpointInfoResponse, args: DebugProtocol.DataBreakpointInfoArguments): void {
		this.handleRequestAsync(response, () => this.dataBreakpointInfo(args));
	}

	protected setDataBreakpointsRequest(response: DebugProtocol.SetDataBreakpointsResponse, args: DebugProtocol.SetDataBreakpointsArguments): void {
		this.handleRequestAsync(response, () => this.setDataBreakpoints(args));
	}

	protected restartFrameRequest(response: DebugProtocol.RestartFrameResponse, args: DebugProtocol.RestartFrameArguments): void {
		this.handleRequestAsync(response, () => this.restartFrame(args));
	}

	protected customRequest(command: string, response: DebugProtocol.Response, args: any): void {
		this.handleRequestAsync(response, async () => {
			switch(command) {

				case 'reloadAddon':
				return await this.reloadAddon();

				case 'toggleSkippingFile':
				return await this.toggleSkippingFile(<string>args);

				case 'setPopupAutohide':
				return await this.setPopupAutohide(args === 'true');

				case 'togglePopupAutohide':
				return await this.togglePopupAutohide();

				case 'setActiveEventBreakpoints':
				return await this.setActiveEventBreakpoints(args);
			}
		});
	}

	private handleRequest<TResponse extends DebugProtocol.Response, TResponseBody>(response: TResponse, executeRequest: () => TResponseBody): void {
		try {
			response.body = executeRequest();
		} catch (err) {
			response.success = false;
			response.message = this.errorString(err);
		}
		this.sendResponse(response);
	}

	private async handleRequestAsync<TResponse extends DebugProtocol.Response, TResponseBody>(response: TResponse, executeRequest: () => Promise<TResponseBody>): Promise<void> {
		try {
			response.body = await executeRequest();
		} catch (err) {
			response.success = false;
			response.message = this.errorString(err);
		}
		this.sendResponse(response);
	}

	private errorString(err: any) {
		if ((typeof err === 'object') && (err !== null) && (typeof err.message === 'string')) {
			return err.message;
		} else {
			return String(err);
		}
	}
}

================================================
FILE: src/adapter/firefox/README.md
================================================
This folder contains the code for launching and talking to Firefox.

The [`launchFirefox()`](./launch.ts) function launches Firefox and establishes the TCP connection for
the debugger protocol. The connection's socket is passed to the [`DebugConnection`](./connection.ts)
class which implements the 
[Firefox Remote Debugging Protocol](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md)
using the [`DebugProtocolTransport`](./transport.ts) class for the
[transport layer](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md#stream-transport)
of the protocol.
It passes the responses and events it receives to [proxy classes](./actorProxy) for the Firefox
[actors](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md#actors).
The [`sourceMaps`](./sourceMaps) folder contains the debug adapter's source-map support.


================================================
FILE: src/adapter/firefox/actorProxy/README.md
================================================
This folder contains proxy classes for the Firefox
[actors](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md#actors).
They implement the [`ActorProxy`](./interface.ts) interface and provide a Promise-based API for
sending requests to and an EventEmitter-based API for receiving events from these actors.


================================================
FILE: src/adapter/firefox/actorProxy/addons.ts
================================================
import { Log } from '../../util/log';
import { DebugConnection } from '../connection';
import { BaseActorProxy } from './base';

let log = Log.create('AddonsActorProxy');

/**
 * Proxy class for an addons actor
 * ([spec](https://github.com/mozilla/gecko-dev/blob/master/devtools/shared/specs/addon/addons.js))
 */
export class AddonsActorProxy extends BaseActorProxy {

	constructor(name: string, connection: DebugConnection) {
		super(name, connection, log);
	}

	public installAddon(addonPath: string): Promise<FirefoxDebugProtocol.InstallAddonResponse> {
		return this.sendCachedRequest(
			`installTemporaryAddon:${addonPath}`,
			{ type: 'installTemporaryAddon', addonPath }
		);
	}
}


================================================
FILE: src/adapter/firefox/actorProxy/base.ts
================================================
import { EventEmitter } from 'events';
import { DebugConnection } from '../connection';
import { ActorProxy } from './interface';
import { PendingRequests } from '../../util/pendingRequests';
import { Log } from '../../util/log';

export abstract class BaseActorProxy extends EventEmitter implements ActorProxy {

	private readonly pendingRequests = new PendingRequests<any>();
	private readonly cachedRequestPromises = new Map<string, Promise<any>>();

	constructor(
		public readonly name: string,
		protected readonly connection: DebugConnection,
		private readonly log: Log
	) {
		super();
		this.connection.register(this);
	}

	sendRequest<T extends Omit<FirefoxDebugProtocol.Request, 'to'>, S>(request: T): Promise<S> {
		return new Promise<S>((resolve, reject) => {
			this.pendingRequests.enqueue({ resolve, reject });
			this.connection.sendRequest({ ...request, to: this.name });
		});
	}

	sendCachedRequest<T extends Omit<FirefoxDebugProtocol.Request, 'to'>, R, S>(key: string, request: T, convert?: (r: R) => S): Promise<S> {
		if (!this.cachedRequestPromises.has(key)) {
			this.cachedRequestPromises.set(key, (async () => {
				const response: R = await this.sendRequest(request);
				return convert ? convert(response) : response;
			})());
		}
		return this.cachedRequestPromises.get(key)!;
	}

	sendRequestWithoutResponse<T extends Omit<FirefoxDebugProtocol.Request, 'to'>>(request: T): void {
		this.connection.sendRequest({ ...request, to: this.name });
	}

	async getRequestTypes(): Promise<string[]> {
		return (await this.sendRequest<any, FirefoxDebugProtocol.RequestTypesResponse>(
			{ type: 'requestTypes' })
		).requestTypes;
	}

	isEvent(message: FirefoxDebugProtocol.Response): boolean {
		return !!message.type;
	}

	handleEvent(event: FirefoxDebugProtocol.Event): void {
		this.log.warn(`Unknown message: ${JSON.stringify(event)}`);
	}

	receiveMessage(message: FirefoxDebugProtocol.Response): void {
		if (message.error) {
			this.pendingRequests.rejectOne(message);
		} else if (this.isEvent(message)) {
			this.handleEvent(message as FirefoxDebugProtocol.Event);
		} else {
			this.pendingRequests.resolveOne(message);
		}
	}

	dispose(): void {
		this.connection.unregister(this);
	}
}


================================================
FILE: src/adapter/firefox/actorProxy/breakpointList.ts
================================================
import { Log } from '../../util/log';
import { DebugConnection } from '../connection';
import { BaseActorProxy } from './base';

const log = Log.create('BreakpointListActorProxy');

export class BreakpointListActorProxy extends BaseActorProxy {

	constructor(name: string, connection: DebugConnection) {
		super(name, connection, log);
	}

	public async setBreakpoint(sourceUrl: string, line: number, column: number, condition?: string, logValue?: string) {
		await this.sendRequest({
			type: 'setBreakpoint',
			location: { sourceUrl, line, column },
			options: { condition, logValue }
		});
	}

	public async removeBreakpoint(sourceUrl: string, line: number, column: number) {
		await this.sendRequest({ type: 'removeBreakpoint', location: { sourceUrl, line, column } });
	}

	public async setActiveEventBreakpoints(ids: string[]) {
		await this.sendRequest({ type: 'setActiveEventBreakpoints', ids });
	}
}


================================================
FILE: src/adapter/firefox/actorProxy/console.ts
================================================
import { Log } from '../../util/log';
import { DebugConnection } from '../connection';
import { exceptionGripToString } from '../../util/misc';
import { BaseActorProxy } from './base';
import { DeferredMap } from '../../../common/deferredMap';

let log = Log.create('ConsoleActorProxy');

/**
 * Proxy class for a console actor
 */
export class ConsoleActorProxy extends BaseActorProxy {

	private evaluationResults = new DeferredMap<string, FirefoxDebugProtocol.Grip>();

	constructor(name: string, connection: DebugConnection) {
		super(name, connection, log);
	}

	public async evaluate(expr: string, disableBreaks: boolean, frameActorName?: string): Promise<FirefoxDebugProtocol.Grip> {
		const resultIDResponse: FirefoxDebugProtocol.ResultIDResponse = await this.sendRequest({
			type: 'evaluateJSAsync',
			text: expr, frameActor: frameActorName, disableBreaks
		});
		const result = await this.evaluationResults.get(resultIDResponse.resultID);
		this.evaluationResults.delete(resultIDResponse.resultID);
		return result;
	}

	public async autoComplete(text: string, column: number, frameActor?: string) {
		const response: FirefoxDebugProtocol.AutoCompleteResponse = await this.sendRequest({ type: 'autocomplete', text, cursor: column, frameActor });
		return response.matches;
	}

	handleEvent(event: FirefoxDebugProtocol.EvaluationResultResponse): void {
		if (event.type === 'evaluationResult') {
			this.evaluationResults.set(event.resultID, event.exceptionMessage ? exceptionGripToString(event.exception) : event.result);
		} else {
			log.warn(`Unknown message: ${JSON.stringify(event)}`);
		}
	}
}


================================================
FILE: src/adapter/firefox/actorProxy/descriptor.ts
================================================
import { Log } from '../../util/log';
import { DebugConnection } from '../connection';
import { BaseActorProxy } from './base';
import { WatcherActorProxy } from './watcher';

let log = Log.create('DescriptorActorProxy');

export type DescriptorType = 'tab' | 'webExtension' | 'process';

/**
 * Proxy class for a TabDescriptor or WebExtensionDescriptor actor
 */
export class DescriptorActorProxy extends BaseActorProxy {

	constructor(
		name: string,
		public readonly type: DescriptorType,
		connection: DebugConnection
	) {
		super(name, connection, log);
	}

	public async getWatcher(): Promise<WatcherActorProxy> {
		return await this.sendCachedRequest(
			'getWatcher',
				{ type: 'getWatcher',
					enableWindowGlobalThreadActors: this.type === 'process' ? true : undefined,
					isServerTargetSwitchingEnabled: this.type !== 'process' ? true : undefined,
					isPopupDebuggingEnabled: this.type === 'tab' ? false : undefined,
				},
			(response: FirefoxDebugProtocol.GetWatcherResponse) =>
				new WatcherActorProxy(response.actor, !!response.traits.content_script, this.connection)
		);
	}

	public async reload() {
		await this.sendRequest({ type: 'reloadDescriptor' });
	}

	public onDestroyed(cb: () => void) {
		this.on('destroyed', cb);
	}

	handleEvent(event: FirefoxDebugProtocol.DescriptorDestroyedEvent): void {
		if (event.type === 'descriptor-destroyed') {
			log.debug(`Descriptor ${this.name} destroyed`);
			this.emit('destroyed');
		} else {
			log.warn(`Unknown message: ${JSON.stringify(event)}`);
		}
	}
}


================================================
FILE: src/adapter/firefox/actorProxy/device.ts
================================================
import { Log } from '../../util/log';
import { DebugConnection } from '../connection';
import { BaseActorProxy } from './base';

let log = Log.create('DeviceActorProxy');

/**
 * Proxy class for the device actor
 */
export class DeviceActorProxy extends BaseActorProxy {

	constructor(name: string, connection: DebugConnection) {
		super(name, connection, log);
	}

	public getDescription(): Promise<FirefoxDebugProtocol.DeviceDescription> {
		return this.sendCachedRequest(
			'getDescription',
			{ type: 'getDescription' },
			(response: FirefoxDebugProtocol.DeviceDescriptionResponse) => response.value
		);
	}
}


================================================
FILE: src/adapter/firefox/actorProxy/frame.ts
================================================
import { Log } from '../../util/log';
import { DebugConnection } from '../connection';
import { BaseActorProxy } from './base';

let log = Log.create('FrameActorProxy');

/**
 * Proxy class for a frame actor
 * ([docs](https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md#listing-stack-frames),
 * [spec](https://github.com/mozilla/gecko-dev/blob/master/devtools/shared/specs/frame.js))
 */
export class FrameActorProxy extends BaseActorProxy {

	constructor(name: string, connection: DebugConnection) {
		super(name, connection, log);
	}

	isEvent(message: FirefoxDebugProtocol.Response): boolean {
		return false;
	}

	public getEnvironment(): Promise<FirefoxDebugProtocol.Environment> {
		return this.sendCachedRequest('getEnvironment', { type: 'getEnvironment' });
	}
}


================================================
FILE: src/adapter/firefox/actorProxy/interface.ts
================================================
/**
 * An ActorProxy is a client-side reference to an actor on the server side of the 
 * Mozilla Debugging Protocol as defined in
 * https://github.com/mozilla/gecko-dev/blob/master/devtools/docs/backend/protocol.md
 */
export interface ActorProxy {

	/** the name that is used for the actor in Firefox debug protocol messages */
	readonly name: string;

	/** called by the [DebugConnection](../connection.ts) class to deliver this actor's messages */
	receiveMessage(response: FirefoxDebugProtocol.Response): void;
}


====
Download .txt
gitextract_cmpgi7eh/

├── .gitignore
├── .mocharc.json
├── .vscode/
│   ├── extensions.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── .vscodeignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── dist/
│   ├── README.md
│   ├── package.json
│   └── terminator/
│       ├── main.js
│       └── manifest.json
├── package.json
├── src/
│   ├── README.md
│   ├── adapter/
│   │   ├── README.md
│   │   ├── adapter/
│   │   │   ├── README.md
│   │   │   ├── addonManager.ts
│   │   │   ├── breakpoint.ts
│   │   │   ├── breakpointsManager.ts
│   │   │   ├── consoleAPICall.ts
│   │   │   ├── dataBreakpointsManager.ts
│   │   │   ├── descriptor.ts
│   │   │   ├── environment.ts
│   │   │   ├── eventBreakpointsManager.ts
│   │   │   ├── frame.ts
│   │   │   ├── getterValue.ts
│   │   │   ├── objectGrip.ts
│   │   │   ├── preview.ts
│   │   │   ├── registry.ts
│   │   │   ├── scope.ts
│   │   │   ├── skipFilesManager.ts
│   │   │   ├── source.ts
│   │   │   ├── sourcesManager.ts
│   │   │   ├── thread.ts
│   │   │   ├── variable.ts
│   │   │   └── variablesProvider.ts
│   │   ├── configuration.ts
│   │   ├── debugAdapterBase.ts
│   │   ├── firefox/
│   │   │   ├── README.md
│   │   │   ├── actorProxy/
│   │   │   │   ├── README.md
│   │   │   │   ├── addons.ts
│   │   │   │   ├── base.ts
│   │   │   │   ├── breakpointList.ts
│   │   │   │   ├── console.ts
│   │   │   │   ├── descriptor.ts
│   │   │   │   ├── device.ts
│   │   │   │   ├── frame.ts
│   │   │   │   ├── interface.ts
│   │   │   │   ├── longString.ts
│   │   │   │   ├── objectGrip.ts
│   │   │   │   ├── preference.ts
│   │   │   │   ├── root.ts
│   │   │   │   ├── source.ts
│   │   │   │   ├── target.ts
│   │   │   │   ├── thread.ts
│   │   │   │   ├── threadConfiguration.ts
│   │   │   │   └── watcher.ts
│   │   │   ├── connection.ts
│   │   │   ├── launch.ts
│   │   │   ├── protocol.d.ts
│   │   │   ├── sourceMaps/
│   │   │   │   ├── README.md
│   │   │   │   ├── info.ts
│   │   │   │   ├── manager.ts
│   │   │   │   ├── source.ts
│   │   │   │   └── thread.ts
│   │   │   └── transport.ts
│   │   ├── firefoxDebugAdapter.ts
│   │   ├── firefoxDebugSession.ts
│   │   ├── location.ts
│   │   └── util/
│   │       ├── delayedTask.ts
│   │       ├── forkedLauncher.ts
│   │       ├── fs.ts
│   │       ├── log.ts
│   │       ├── misc.ts
│   │       ├── net.ts
│   │       ├── pathMapper.ts
│   │       └── pendingRequests.ts
│   ├── common/
│   │   ├── configuration.ts
│   │   ├── customEvents.ts
│   │   ├── deferredMap.ts
│   │   └── util.ts
│   ├── extension/
│   │   ├── addPathMapping.ts
│   │   ├── debugConfigurationProvider.ts
│   │   ├── eventBreakpointsProvider.ts
│   │   ├── loadedScripts/
│   │   │   ├── fileNode.ts
│   │   │   ├── nonLeafNode.ts
│   │   │   ├── provider.ts
│   │   │   ├── rootNode.ts
│   │   │   ├── sessionNode.ts
│   │   │   └── treeNode.ts
│   │   ├── main.ts
│   │   ├── pathMappingWizard.ts
│   │   └── popupAutohideManager.ts
│   ├── test/
│   │   ├── setup.ts
│   │   ├── sourceMapUtil.ts
│   │   ├── testAccessorProperties.ts
│   │   ├── testConfigurationParser.ts
│   │   ├── testConsole.ts
│   │   ├── testDataBreakpoints.ts
│   │   ├── testDebugAddons.ts
│   │   ├── testDebugWebWorkers.ts
│   │   ├── testEvaluate.ts
│   │   ├── testGulpSourceMaps.ts
│   │   ├── testHitBreakpoints.ts
│   │   ├── testInspectVariables.ts
│   │   ├── testSetBreakpoints.ts
│   │   ├── testSkipFiles.ts
│   │   ├── testSourceActorCollection.ts
│   │   ├── testStepThrough.ts
│   │   ├── testTerminateAndCleanup.ts
│   │   ├── testWebpackSourceMaps.ts
│   │   └── util.ts
│   └── typings/
│       ├── gulp-nop.d.ts
│       └── map-sources.d.ts
├── testdata/
│   ├── web/
│   │   ├── debuggerStatement.js
│   │   ├── dlscript.js
│   │   ├── exception-sourcemap.js
│   │   ├── exception-sourcemap.ts
│   │   ├── exception.js
│   │   ├── index.html
│   │   ├── main.js
│   │   ├── skip.js
│   │   ├── sourceMaps/
│   │   │   ├── modules/
│   │   │   │   ├── f.js
│   │   │   │   ├── g.js
│   │   │   │   └── index.html
│   │   │   └── scripts/
│   │   │       ├── f.js
│   │   │       ├── g.js
│   │   │       └── index.html
│   │   ├── tsconfig.json
│   │   └── worker.js
│   ├── webExtension/
│   │   ├── addOn/
│   │   │   ├── backgroundscript.js
│   │   │   ├── contentscript.js
│   │   │   └── manifest.json
│   │   └── index.html
│   └── webExtension2/
│       ├── addOn/
│       │   ├── backgroundscript.js
│       │   ├── contentscript.js
│       │   └── manifest.json
│       └── index.html
├── tsconfig.json
└── webpack.config.js
Download .txt
SYMBOL INDEX (824 symbols across 92 files)

FILE: src/adapter/adapter/addonManager.ts
  class AddonManager (line 21) | class AddonManager {
    method constructor (line 30) | constructor(
    method sessionStarted (line 36) | public async sessionStarted(
    method reloadAddon (line 54) | public async reloadAddon(): Promise<void> {
    method fetchDescriptor (line 62) | private async fetchDescriptor(rootActor: RootActorProxy): Promise<void> {

FILE: src/adapter/adapter/breakpoint.ts
  class BreakpointInfo (line 4) | class BreakpointInfo {
    method constructor (line 18) | public constructor(
    method isEquivalent (line 26) | public isEquivalent(other: BreakpointInfo | DebugProtocol.SourceBreakp...

FILE: src/adapter/adapter/breakpointsManager.ts
  class BreakpointsManager (line 15) | class BreakpointsManager {
    method constructor (line 20) | constructor(
    method setBreakpoints (line 65) | public setBreakpoints(
    method getBreakpoints (line 154) | public getBreakpoints(sourcePathOrUrl: string) {
    method verifyBreakpoint (line 158) | private verifyBreakpoint(breakpointInfo: BreakpointInfo): void {
    method getOrCreateBreakpointInfo (line 170) | private getOrCreateBreakpointInfo(
  function convertLogpointMessage (line 195) | function convertLogpointMessage(msg: string): string {

FILE: src/adapter/adapter/consoleAPICall.ts
  class ConsoleAPICallAdapter (line 8) | class ConsoleAPICallAdapter implements VariablesProvider {
    method constructor (line 15) | public constructor(
    method getVariables (line 24) | public getVariables(): Promise<VariableAdapter[]> {
  class ArgumentListAdapter (line 29) | class ArgumentListAdapter implements VariablesProvider {
    method constructor (line 35) | public constructor(
    method getVariables (line 42) | public getVariables(): Promise<VariableAdapter[]> {

FILE: src/adapter/adapter/dataBreakpointsManager.ts
  class DataBreakpointsManager (line 9) | class DataBreakpointsManager {
    method constructor (line 13) | constructor(
    method encodeDataId (line 17) | public static encodeDataId(variablesProviderId: number, property: stri...
    method decodeDataId (line 21) | public static decodeDataId(dataId: string): { variablesProviderId: num...
    method setDataBreakpoints (line 31) | public async setDataBreakpoints(newDataBreakpoints: DebugProtocol.Data...
    method addDataBreakpoint (line 55) | private async addDataBreakpoint(dataId: string, type: 'get' | 'set'): ...
    method removeDataBreakpoint (line 71) | private async removeDataBreakpoint(dataId: string): Promise<void> {

FILE: src/adapter/adapter/descriptor.ts
  class DescriptorAdapter (line 8) | class DescriptorAdapter {
    method constructor (line 15) | public constructor(
    method dispose (line 29) | public dispose() {

FILE: src/adapter/adapter/environment.ts
  method constructor (line 16) | public constructor(environment: T) {
  method from (line 24) | public static from(environment: FirefoxDebugProtocol.Environment): Envir...
  method getScopeAdapters (line 39) | public getScopeAdapters(frameAdapter: FrameAdapter): ScopeAdapter[] {
  method getAllScopeAdapters (line 46) | protected getAllScopeAdapters(frameAdapter: FrameAdapter): ScopeAdapter[] {
  class ObjectEnvironmentAdapter (line 65) | class ObjectEnvironmentAdapter extends EnvironmentAdapter<FirefoxDebugPr...
    method constructor (line 67) | public constructor(environment: FirefoxDebugProtocol.ObjectEnvironment) {
    method getOwnScopeAdapter (line 71) | protected getOwnScopeAdapter(frameAdapter: FrameAdapter): ScopeAdapter {
  class FunctionEnvironmentAdapter (line 93) | class FunctionEnvironmentAdapter extends EnvironmentAdapter<FirefoxDebug...
    method constructor (line 95) | public constructor(environment: FirefoxDebugProtocol.FunctionEnvironme...
    method getOwnScopeAdapter (line 99) | protected getOwnScopeAdapter(frameAdapter: FrameAdapter): ScopeAdapter {
  class WithEnvironmentAdapter (line 114) | class WithEnvironmentAdapter extends EnvironmentAdapter<FirefoxDebugProt...
    method constructor (line 116) | public constructor(environment: FirefoxDebugProtocol.WithEnvironment) {
    method getOwnScopeAdapter (line 120) | protected getOwnScopeAdapter(frameAdapter: FrameAdapter): ScopeAdapter {
  class BlockEnvironmentAdapter (line 142) | class BlockEnvironmentAdapter extends EnvironmentAdapter<FirefoxDebugPro...
    method constructor (line 144) | public constructor(environment: FirefoxDebugProtocol.BlockEnvironment) {
    method getOwnScopeAdapter (line 148) | protected getOwnScopeAdapter(frameAdapter: FrameAdapter): ScopeAdapter {

FILE: src/adapter/adapter/eventBreakpointsManager.ts
  class EventBreakpointsManager (line 5) | class EventBreakpointsManager {
    method constructor (line 9) | constructor(
    method setActiveEventBreakpoints (line 54) | public async setActiveEventBreakpoints(ids: string[]) {

FILE: src/adapter/adapter/frame.ts
  class FrameAdapter (line 14) | class FrameAdapter {
    method constructor (line 19) | public constructor(
    method getStackframe (line 27) | public async getStackframe(): Promise<StackFrame> {
    method getScopeAdapters (line 63) | public async getScopeAdapters(): Promise<ScopeAdapter[]> {
    method dispose (line 85) | public dispose(): void {

FILE: src/adapter/adapter/getterValue.ts
  class GetterValueAdapter (line 23) | class GetterValueAdapter implements VariablesProvider {
    method threadAdapter (line 26) | public get threadAdapter(): ThreadAdapter {
    method referenceExpression (line 30) | public get referenceExpression(): string | undefined {
    method referenceFrame (line 34) | public get referenceFrame(): FrameAdapter | undefined {
    method constructor (line 38) | public constructor(private readonly variableAdapter: VariableAdapter) {
    method getVariables (line 43) | public async getVariables(): Promise<VariableAdapter[]> {

FILE: src/adapter/adapter/objectGrip.ts
  class ObjectGripAdapter (line 10) | class ObjectGripAdapter implements VariablesProvider {
    method threadAdapter (line 14) | public get threadAdapter(): ThreadAdapter {
    method referenceExpression (line 18) | public get referenceExpression(): string | undefined {
    method referenceFrame (line 22) | public get referenceFrame(): FrameAdapter | undefined {
    method constructor (line 26) | public constructor(
    method getVariables (line 42) | public async getVariables(): Promise<VariableAdapter[]> {
    method fetchAccessorsFromPrototypes (line 112) | private async fetchAccessorsFromPrototypes(
    method dispose (line 150) | public dispose(): void {

FILE: src/adapter/adapter/preview.ts
  function renderPreview (line 12) | function renderPreview(objectGrip: FirefoxDebugProtocol.ObjectGrip): str...
  function renderObjectPreview (line 66) | function renderObjectPreview(preview: FirefoxDebugProtocol.ObjectPreview...
  function renderDOMElementPreview (line 108) | function renderDOMElementPreview(preview: FirefoxDebugProtocol.DOMNodePr...
  function renderArrayLikePreview (line 134) | function renderArrayLikePreview(preview: FirefoxDebugProtocol.ArrayLikeP...
  function renderFunctionGrip (line 155) | function renderFunctionGrip(functionGrip: FirefoxDebugProtocol.FunctionG...
  function renderGripOrNull (line 175) | function renderGripOrNull(gripOrNull: FirefoxDebugProtocol.Grip | null):...
  function renderGrip (line 183) | function renderGrip(grip: FirefoxDebugProtocol.Grip): string {

FILE: src/adapter/adapter/registry.ts
  class Registry (line 7) | class Registry<T> extends EventEmitter implements Iterable<[number, T]> {
    method register (line 15) | public register(obj: T): number {
    method unregister (line 22) | public unregister(id: number): boolean {
    method has (line 26) | public has(id: number): boolean {
    method find (line 30) | public find(id: number): T | undefined {
    method count (line 34) | public get count() {
    method map (line 42) | public map<S>(f: (obj: T) => S): S[] {
    method filter (line 50) | public filter(f: (obj: T) => boolean): T[] {
    method onRegistered (line 60) | public onRegistered(cb: (obj: T) => void) {
  method [Symbol.iterator] (line 38) | public [Symbol.iterator](): Iterator<[number, T]> {

FILE: src/adapter/adapter/scope.ts
  method threadAdapter (line 14) | public get threadAdapter(): ThreadAdapter {
  method constructor (line 21) | protected constructor(
  method fromGrip (line 29) | public static fromGrip(name: string, grip: FirefoxDebugProtocol.Grip, re...
  method addThis (line 37) | public addThis(thisValue: FirefoxDebugProtocol.Grip) {
  method addReturnValue (line 42) | public addReturnValue(returnValue: FirefoxDebugProtocol.Grip) {
  method getScope (line 47) | public getScope(): Scope {
  method getVariables (line 51) | public async getVariables(): Promise<VariableAdapter[]> {
  method dispose (line 69) | public dispose(): void {
  class SingleValueScopeAdapter (line 74) | class SingleValueScopeAdapter extends ScopeAdapter {
    method constructor (line 78) | public constructor(name: string, grip: FirefoxDebugProtocol.Grip, refe...
    method getVariablesInt (line 84) | protected getVariablesInt(): Promise<VariableAdapter[]> {
  class ObjectScopeAdapter (line 89) | class ObjectScopeAdapter extends ScopeAdapter {
    method constructor (line 93) | public constructor(name: string, object: FirefoxDebugProtocol.ObjectGr...
    method getVariablesInt (line 99) | protected getVariablesInt(): Promise<VariableAdapter[]> {
  class LocalVariablesScopeAdapter (line 104) | class LocalVariablesScopeAdapter extends ScopeAdapter {
    method constructor (line 108) | public constructor(name: string, variableDescriptors: FirefoxDebugProt...
    method getVariablesInt (line 120) | protected getVariablesInt(): Promise<VariableAdapter[]> {
  class FunctionScopeAdapter (line 125) | class FunctionScopeAdapter extends ScopeAdapter {
    method constructor (line 129) | public constructor(name: string, bindings: FirefoxDebugProtocol.Functi...
    method getVariablesInt (line 149) | protected getVariablesInt(): Promise<VariableAdapter[]> {

FILE: src/adapter/adapter/skipFilesManager.ts
  class SkipFilesManager (line 15) | class SkipFilesManager {
    method constructor (line 25) | public constructor(
    method shouldSkip (line 31) | public shouldSkip(pathOrUrl: string): boolean {
    method toggleSkipping (line 67) | public async toggleSkipping(pathOrUrl: string): Promise<void> {

FILE: src/adapter/adapter/source.ts
  class SourceAdapter (line 14) | class SourceAdapter {
    method isBlackBoxed (line 24) | public get isBlackBoxed() { return this.blackboxed; }
    method constructor (line 26) | public constructor(
    method setBlackBoxed (line 55) | public async setBlackBoxed(blackboxed: boolean) {
    method getBreakableLines (line 64) | public getBreakableLines(): Promise<number[]> {
    method getBreakableLocations (line 68) | public getBreakableLocations(line: number): Promise<MappedLocation[]> {
    method fetchSource (line 72) | public fetchSource(): Promise<FirefoxDebugProtocol.Grip> {
    method findNextBreakableLocation (line 76) | public async findNextBreakableLocation(
  class SourceActorCollection (line 102) | class SourceActorCollection {
    method constructor (line 108) | public constructor(actor: ISourceActorProxy) {
    method add (line 113) | public add(actor: ISourceActorProxy) {
    method remove (line 121) | public remove(actor: ISourceActorProxy) {
    method runWithSomeActor (line 133) | public async runWithSomeActor<T>(fn: (actor: ISourceActorProxy) => Pro...
    method runWithAllActors (line 148) | public async runWithAllActors<T>(fn: (actor: ISourceActorProxy) => Pro...

FILE: src/adapter/adapter/sourcesManager.ts
  class SourcesManager (line 12) | class SourcesManager {
    method constructor (line 19) | constructor(private readonly pathMapper: PathMapper) {}
    method addActor (line 21) | public addActor(actor: ISourceActorProxy) {
    method removeActor (line 52) | public removeActor(actor: ISourceActorProxy) {
    method getAdapterForID (line 62) | public getAdapterForID(id: number) {
    method getAdapterForPath (line 66) | public getAdapterForPath(path: string) {
    method getExistingAdapterForPath (line 70) | public getExistingAdapterForPath(path: string) {
    method getAdapterForActor (line 74) | public getAdapterForActor(actor: string) {
    method getAdapterForUrl (line 78) | public getAdapterForUrl(url: string) {
    method findSourceAdaptersForPathOrUrl (line 82) | public findSourceAdaptersForPathOrUrl(pathOrUrl: string): SourceAdapte...
    method findSourceAdaptersForUrlWithoutQuery (line 90) | public findSourceAdaptersForUrlWithoutQuery(url: string): SourceAdapte...

FILE: src/adapter/adapter/thread.ts
  type TargetType (line 17) | type TargetType = 'tab' | 'iframe' | 'worker' | 'backgroundScript' | 'co...
  class ThreadAdapter (line 22) | class ThreadAdapter extends EventEmitter {
    method actorName (line 25) | public get actorName() {
    method url (line 28) | public get url(): string | undefined {
    method constructor (line 61) | public constructor(
    method registerScopeAdapter (line 73) | public registerScopeAdapter(scopeAdapter: ScopeAdapter) {
    method registerObjectGripAdapter (line 77) | public registerObjectGripAdapter(objectGripAdapter: ObjectGripAdapter) {
    method threadLifetime (line 88) | public threadLifetime(objectGripAdapter: ObjectGripAdapter): void {
    method interrupt (line 102) | public interrupt(): Promise<void> {
    method resume (line 106) | public resume(): Promise<void> {
    method stepOver (line 110) | public stepOver(): Promise<void> {
    method stepIn (line 114) | public stepIn(): Promise<void> {
    method stepOut (line 118) | public stepOut(): Promise<void> {
    method restartFrame (line 122) | public restartFrame(frameActor: string): Promise<void> {
    method fetchAllStackFrames (line 126) | public fetchAllStackFrames(): Promise<FrameAdapter[]> {
    method fetchStackFrames (line 168) | public async fetchStackFrames(start: number, count: number): Promise<[...
    method triggerStackframeRefresh (line 178) | public triggerStackframeRefresh(): void {
    method fetchVariables (line 182) | public async fetchVariables(variablesProvider: VariablesProvider): Pro...
    method evaluateRaw (line 189) | public evaluateRaw(expr: string, skipBreakpoints: boolean, frameActorN...
    method evaluate (line 193) | public async evaluate(expr: string, skipBreakpoints: boolean, frameAct...
    method autoComplete (line 199) | public async autoComplete(text: string, column: number, frameActorName...
    method variableFromGrip (line 203) | private variableFromGrip(grip: FirefoxDebugProtocol.Grip | undefined, ...
    method disposePauseLifetimeAdapters (line 214) | public async disposePauseLifetimeAdapters(): Promise<void> {
    method dispose (line 236) | public async dispose(): Promise<void> {

FILE: src/adapter/adapter/variable.ts
  class VariableAdapter (line 22) | class VariableAdapter {
    method variablesProvider (line 26) | public get variablesProvider(): VariablesProvider | undefined {
    method constructor (line 30) | public constructor(
    method getVariable (line 38) | public getVariable(): Variable {
    method fromGrip (line 52) | public static fromGrip(
    method fromPropertyDescriptor (line 132) | public static fromPropertyDescriptor(
    method fromSafeGetterValueDescriptor (line 185) | public static fromSafeGetterValueDescriptor(
    method fromArgumentList (line 199) | public static fromArgumentList(
    method sortVariables (line 209) | public static sortVariables(variables: VariableAdapter[]): void {
    method isFunctionGrip (line 213) | private static isFunctionGrip(grip: FirefoxDebugProtocol.Grip) {

FILE: src/adapter/adapter/variablesProvider.ts
  type VariablesProvider (line 8) | interface VariablesProvider {

FILE: src/adapter/configuration.ts
  type NormalizedReloadConfiguration (line 17) | interface NormalizedReloadConfiguration {
  type ParsedTabFilterConfiguration (line 23) | interface ParsedTabFilterConfiguration {
  type ParsedConfiguration (line 28) | interface ParsedConfiguration {
  type ParsedAttachConfiguration (line 45) | interface ParsedAttachConfiguration {
  type FirefoxPreferences (line 54) | interface FirefoxPreferences {
  type PathMapping (line 58) | type PathMapping = { url: string | RegExp, path: string | null };
  type PathMappings (line 59) | type PathMappings = PathMapping[];
  type ParsedLaunchConfiguration (line 61) | interface ParsedLaunchConfiguration {
  type ParsedAddonConfiguration (line 73) | interface ParsedAddonConfiguration {
  function parseConfiguration (line 83) | async function parseConfiguration(
  function harmonizeTrailingSlashes (line 227) | function harmonizeTrailingSlashes(pathMapping: PathMapping): PathMapping {
  function handleWildcards (line 251) | function handleWildcards(pathMapping: PathMapping): PathMapping {
  function findFirefoxExecutable (line 267) | async function findFirefoxExecutable(configuredPath?: string): Promise<s...
  function getExecutableCandidates (line 291) | function getExecutableCandidates(edition?: 'stable' | 'developer' | 'nig...
  function parseProfileConfiguration (line 363) | async function parseProfileConfiguration(config: LaunchConfiguration, tm...
  function findFirefoxProfileDir (line 394) | function findFirefoxProfileDir(profileName: string): Promise<string | un...
  function createFirefoxPreferences (line 409) | function createFirefoxPreferences(
  function parseWebRootConfiguration (line 447) | function parseWebRootConfiguration(config: CommonConfiguration, pathMapp...
  function parseSkipFilesConfiguration (line 484) | function parseSkipFilesConfiguration(config: CommonConfiguration): RegEx...
  function parseReloadConfiguration (line 505) | function parseReloadConfiguration(
  function parseTabFilterConfiguration (line 566) | function parseTabFilterConfiguration(
  function parseTabFilter (line 594) | function parseTabFilter(tabFilter: string | string[]): RegExp[] {
  function parseAddonConfiguration (line 609) | async function parseAddonConfiguration(

FILE: src/adapter/debugAdapterBase.ts
  method constructor (line 16) | public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = f...
  method initializeRequest (line 49) | protected initializeRequest(response: DebugProtocol.InitializeResponse, ...
  method disconnectRequest (line 53) | protected disconnectRequest(response: DebugProtocol.DisconnectResponse, ...
  method launchRequest (line 57) | protected launchRequest(response: DebugProtocol.LaunchResponse, args: De...
  method attachRequest (line 61) | protected attachRequest(response: DebugProtocol.AttachResponse, args: De...
  method breakpointLocationsRequest (line 65) | protected breakpointLocationsRequest(response: DebugProtocol.BreakpointL...
  method setBreakPointsRequest (line 69) | protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsRe...
  method setExceptionBreakPointsRequest (line 73) | protected setExceptionBreakPointsRequest(response: DebugProtocol.SetExce...
  method pauseRequest (line 77) | protected pauseRequest(response: DebugProtocol.PauseResponse, args: Debu...
  method nextRequest (line 81) | protected nextRequest(response: DebugProtocol.NextResponse, args: DebugP...
  method stepInRequest (line 85) | protected stepInRequest(response: DebugProtocol.StepInResponse, args: De...
  method stepOutRequest (line 89) | protected stepOutRequest(response: DebugProtocol.StepOutResponse, args: ...
  method continueRequest (line 93) | protected continueRequest(response: DebugProtocol.ContinueResponse, args...
  method sourceRequest (line 97) | protected sourceRequest(response: DebugProtocol.SourceResponse, args: De...
  method threadsRequest (line 101) | protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {
  method stackTraceRequest (line 105) | protected stackTraceRequest(response: DebugProtocol.StackTraceResponse, ...
  method scopesRequest (line 109) | protected scopesRequest(response: DebugProtocol.ScopesResponse, args: De...
  method variablesRequest (line 113) | protected variablesRequest(response: DebugProtocol.VariablesResponse, ar...
  method setVariableRequest (line 117) | protected setVariableRequest(response: DebugProtocol.SetVariableResponse...
  method evaluateRequest (line 121) | protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args...
  method completionsRequest (line 125) | protected completionsRequest(response: DebugProtocol.CompletionsResponse...
  method dataBreakpointInfoRequest (line 129) | protected dataBreakpointInfoRequest(response: DebugProtocol.DataBreakpoi...
  method setDataBreakpointsRequest (line 133) | protected setDataBreakpointsRequest(response: DebugProtocol.SetDataBreak...
  method restartFrameRequest (line 137) | protected restartFrameRequest(response: DebugProtocol.RestartFrameRespon...
  method customRequest (line 141) | protected customRequest(command: string, response: DebugProtocol.Respons...
  method handleRequest (line 163) | private handleRequest<TResponse extends DebugProtocol.Response, TRespons...
  method handleRequestAsync (line 173) | private async handleRequestAsync<TResponse extends DebugProtocol.Respons...
  method errorString (line 183) | private errorString(err: any) {

FILE: src/adapter/firefox/actorProxy/addons.ts
  class AddonsActorProxy (line 11) | class AddonsActorProxy extends BaseActorProxy {
    method constructor (line 13) | constructor(name: string, connection: DebugConnection) {
    method installAddon (line 17) | public installAddon(addonPath: string): Promise<FirefoxDebugProtocol.I...

FILE: src/adapter/firefox/actorProxy/base.ts
  method constructor (line 12) | constructor(
  method sendRequest (line 21) | sendRequest<T extends Omit<FirefoxDebugProtocol.Request, 'to'>, S>(reque...
  method sendCachedRequest (line 28) | sendCachedRequest<T extends Omit<FirefoxDebugProtocol.Request, 'to'>, R,...
  method sendRequestWithoutResponse (line 38) | sendRequestWithoutResponse<T extends Omit<FirefoxDebugProtocol.Request, ...
  method getRequestTypes (line 42) | async getRequestTypes(): Promise<string[]> {
  method isEvent (line 48) | isEvent(message: FirefoxDebugProtocol.Response): boolean {
  method handleEvent (line 52) | handleEvent(event: FirefoxDebugProtocol.Event): void {
  method receiveMessage (line 56) | receiveMessage(message: FirefoxDebugProtocol.Response): void {
  method dispose (line 66) | dispose(): void {

FILE: src/adapter/firefox/actorProxy/breakpointList.ts
  class BreakpointListActorProxy (line 7) | class BreakpointListActorProxy extends BaseActorProxy {
    method constructor (line 9) | constructor(name: string, connection: DebugConnection) {
    method setBreakpoint (line 13) | public async setBreakpoint(sourceUrl: string, line: number, column: nu...
    method removeBreakpoint (line 21) | public async removeBreakpoint(sourceUrl: string, line: number, column:...
    method setActiveEventBreakpoints (line 25) | public async setActiveEventBreakpoints(ids: string[]) {

FILE: src/adapter/firefox/actorProxy/console.ts
  class ConsoleActorProxy (line 12) | class ConsoleActorProxy extends BaseActorProxy {
    method constructor (line 16) | constructor(name: string, connection: DebugConnection) {
    method evaluate (line 20) | public async evaluate(expr: string, disableBreaks: boolean, frameActor...
    method autoComplete (line 30) | public async autoComplete(text: string, column: number, frameActor?: s...
    method handleEvent (line 35) | handleEvent(event: FirefoxDebugProtocol.EvaluationResultResponse): void {

FILE: src/adapter/firefox/actorProxy/descriptor.ts
  type DescriptorType (line 8) | type DescriptorType = 'tab' | 'webExtension' | 'process';
  class DescriptorActorProxy (line 13) | class DescriptorActorProxy extends BaseActorProxy {
    method constructor (line 15) | constructor(
    method getWatcher (line 23) | public async getWatcher(): Promise<WatcherActorProxy> {
    method reload (line 36) | public async reload() {
    method onDestroyed (line 40) | public onDestroyed(cb: () => void) {
    method handleEvent (line 44) | handleEvent(event: FirefoxDebugProtocol.DescriptorDestroyedEvent): void {

FILE: src/adapter/firefox/actorProxy/device.ts
  class DeviceActorProxy (line 10) | class DeviceActorProxy extends BaseActorProxy {
    method constructor (line 12) | constructor(name: string, connection: DebugConnection) {
    method getDescription (line 16) | public getDescription(): Promise<FirefoxDebugProtocol.DeviceDescriptio...

FILE: src/adapter/firefox/actorProxy/frame.ts
  class FrameActorProxy (line 12) | class FrameActorProxy extends BaseActorProxy {
    method constructor (line 14) | constructor(name: string, connection: DebugConnection) {
    method isEvent (line 18) | isEvent(message: FirefoxDebugProtocol.Response): boolean {
    method getEnvironment (line 22) | public getEnvironment(): Promise<FirefoxDebugProtocol.Environment> {

FILE: src/adapter/firefox/actorProxy/interface.ts
  type ActorProxy (line 6) | interface ActorProxy {

FILE: src/adapter/firefox/actorProxy/longString.ts
  class LongStringGripActorProxy (line 12) | class LongStringGripActorProxy extends BaseActorProxy {
    method constructor (line 14) | constructor(private grip: FirefoxDebugProtocol.LongStringGrip, connect...
    method fetchContent (line 18) | public fetchContent(): Promise<string> {

FILE: src/adapter/firefox/actorProxy/objectGrip.ts
  class ObjectGripActorProxy (line 12) | class ObjectGripActorProxy extends BaseActorProxy {
    method constructor (line 16) | constructor(name: string, connection: DebugConnection) {
    method refCount (line 20) | public get refCount() {
    method increaseRefCount (line 24) | public increaseRefCount() {
    method decreaseRefCount (line 28) | public decreaseRefCount() {
    method fetchPrototypeAndProperties (line 35) | public fetchPrototypeAndProperties(): Promise<FirefoxDebugProtocol.Pro...
    method addWatchpoint (line 42) | public addWatchpoint(property: string, label: string, watchpointType: ...
    method removeWatchpoint (line 46) | public removeWatchpoint(property: string): void {
    method threadLifetime (line 50) | public threadLifetime(): Promise<void> {

FILE: src/adapter/firefox/actorProxy/preference.ts
  class PreferenceActorProxy (line 11) | class PreferenceActorProxy extends BaseActorProxy {
    method constructor (line 13) | constructor(name: string, connection: DebugConnection) {
    method getBoolPref (line 17) | public async getBoolPref(pref: string): Promise<boolean> {
    method getCharPref (line 24) | public getCharPref(pref: string): Promise<string> {
    method getIntPref (line 30) | public async getIntPref(pref: string): Promise<number> {
    method setBoolPref (line 37) | public setBoolPref(pref: string, val: boolean): Promise<void> {
    method setCharPref (line 43) | public setCharPref(pref: string, val: string): Promise<void> {
    method setIntPref (line 49) | public setIntPref(pref: string, val: number): Promise<void> {
    method getPref (line 55) | private async getPref(
    method setPref (line 66) | private setPref(

FILE: src/adapter/firefox/actorProxy/root.ts
  type FetchRootResult (line 12) | interface FetchRootResult {
  class RootActorProxy (line 23) | class RootActorProxy extends BaseActorProxy {
    method constructor (line 27) | constructor(connection: DebugConnection) {
    method isEvent (line 31) | isEvent(message: FirefoxDebugProtocol.Response): boolean {
    method fetchRoot (line 35) | public async fetchRoot(): Promise<FetchRootResult> {
    method getProcess (line 61) | public async getProcess(id: number): Promise<DescriptorActorProxy> {
    method fetchTabs (line 70) | public async fetchTabs(): Promise<Map<string, DescriptorActorProxy>> {
    method fetchAddons (line 113) | public async fetchAddons(): Promise<FirefoxDebugProtocol.Addon[]> {
    method handleEvent (line 118) | handleEvent(event: FirefoxDebugProtocol.Event): void {
    method onInit (line 128) | public onInit(cb: (response: FirefoxDebugProtocol.InitialResponse) => ...
    method onTabOpened (line 132) | public onTabOpened(cb: (actorsForTab: DescriptorActorProxy) => void) {
    method onTabClosed (line 136) | public onTabClosed(cb: (actorsForTab: DescriptorActorProxy) => void) {
    method onTabListChanged (line 140) | public onTabListChanged(cb: () => void) {
    method onAddonListChanged (line 144) | public onAddonListChanged(cb: () => void) {

FILE: src/adapter/firefox/actorProxy/source.ts
  type ISourceActorProxy (line 8) | interface ISourceActorProxy {
  class SourceActorProxy (line 24) | class SourceActorProxy extends BaseActorProxy implements ISourceActorPro...
    method constructor (line 26) | constructor(
    method url (line 33) | public get url() {
    method getBreakableLines (line 37) | public getBreakableLines(): Promise<number[]> {
    method getBreakableLocations (line 47) | public async getBreakableLocations(line: number): Promise<MappedLocati...
    method getBreakpointPositionsForRange (line 62) | public getBreakpointPositionsForRange(range: Range): Promise<FirefoxDe...
    method fetchSource (line 78) | public fetchSource(): Promise<FirefoxDebugProtocol.Grip> {
    method setBlackbox (line 88) | public async setBlackbox(blackbox: boolean): Promise<void> {

FILE: src/adapter/firefox/actorProxy/target.ts
  class TargetActorProxy (line 8) | class TargetActorProxy extends BaseActorProxy {
    method constructor (line 12) | constructor(
    method reload (line 19) | public reload() {
    method onConsoleMessages (line 23) | public onConsoleMessages(cb: (consoleMessages: FirefoxDebugProtocol.Co...
    method onErrorMessages (line 27) | public onErrorMessages(cb: (errorMessages: { pageError: FirefoxDebugPr...
    method onSources (line 31) | public onSources(cb: (sources: ISourceActorProxy[]) => void) {
    method onThreadState (line 47) | public onThreadState(cb: (threadState: FirefoxDebugProtocol.ThreadStat...
    method handleEvent (line 51) | handleEvent(event: FirefoxDebugProtocol.ResourcesAvailableEvent | Fire...

FILE: src/adapter/firefox/actorProxy/thread.ts
  type IThreadActorProxy (line 7) | interface IThreadActorProxy {
  class ThreadActorProxy (line 21) | class ThreadActorProxy extends BaseActorProxy implements IThreadActorPro...
    method constructor (line 23) | constructor(name: string, connection: DebugConnection) {
    method resume (line 27) | public async resume(resumeLimitType?: 'next' | 'step' | 'finish' | 're...
    method interrupt (line 32) | public async interrupt(immediately?: boolean): Promise<void> {
    method fetchStackFrames (line 36) | public async fetchStackFrames(start = 0, count = 1000): Promise<Firefo...
    method getAvailableEventBreakpoints (line 41) | public async getAvailableEventBreakpoints() : Promise<FirefoxDebugProt...
    method handleEvent (line 49) | handleEvent(event: FirefoxDebugProtocol.Event): void {

FILE: src/adapter/firefox/actorProxy/threadConfiguration.ts
  class ThreadConfigurationActorProxy (line 7) | class ThreadConfigurationActorProxy extends BaseActorProxy {
    method constructor (line 9) | constructor(name: string, connection: DebugConnection) {
    method updateConfiguration (line 13) | public async updateConfiguration(configuration: Partial<FirefoxDebugPr...

FILE: src/adapter/firefox/actorProxy/watcher.ts
  type ResourceType (line 11) | type ResourceType = 'console-message' | 'error-message' | 'source' | 'th...
  type TargetType (line 12) | type TargetType = 'frame' | 'worker' | 'content_script';
  class WatcherActorProxy (line 16) | class WatcherActorProxy extends BaseActorProxy {
    method constructor (line 18) | constructor(
    method getBreakpointList (line 26) | public async getBreakpointList() {
    method getThreadConfiguration (line 34) | public async getThreadConfiguration() {
    method watchResources (line 42) | public async watchResources(resourceTypes: ResourceType[]) {
    method watchTargets (line 46) | public async watchTargets(targetType: TargetType) {
    method onTargetAvailable (line 50) | public onTargetAvailable(cb: (target: [TargetActorProxy, IThreadActorP...
    method onTargetDestroyed (line 54) | public onTargetDestroyed(cb: (targetActorName: string) => void) {
    method handleEvent (line 58) | handleEvent(event: FirefoxDebugProtocol.TargetAvailableEvent | Firefox...

FILE: src/adapter/firefox/connection.ts
  class DebugConnection (line 15) | class DebugConnection {
    method constructor (line 22) | constructor(pathMapper: PathMapper, sources: SourcesManager, socket: S...
    method sendRequest (line 41) | public sendRequest<T extends FirefoxDebugProtocol.Request>(request: T) {
    method register (line 48) | public register(actor: ActorProxy): void {
    method unregister (line 52) | public unregister(actor: ActorProxy): void {
    method has (line 56) | public has(actorName: string): boolean {
    method getOrCreate (line 60) | public getOrCreate<T extends ActorProxy>(actorName: string, createActo...
    method disconnect (line 68) | public disconnect(): Promise<void> {

FILE: src/adapter/firefox/launch.ts
  function launchFirefox (line 22) | async function launchFirefox(launch: ParsedLaunchConfiguration): Promise...
  function openNewTab (line 77) | async function openNewTab(
  function prepareDebugProfile (line 117) | async function prepareDebugProfile(config: ParsedLaunchConfiguration): P...
  function createDebugProfile (line 130) | function createDebugProfile(config: ParsedLaunchConfiguration): Promise<...

FILE: src/adapter/firefox/protocol.d.ts
  type Request (line 3) | interface Request {
  type Response (line 8) | interface Response {
  type Event (line 13) | interface Event extends Response {
  type TypedResponse (line 17) | interface TypedResponse extends Response {
  type ErrorResponse (line 21) | interface ErrorResponse extends Response {
  type RequestTypesResponse (line 26) | interface RequestTypesResponse extends Response {
  type InitialResponse (line 30) | interface InitialResponse extends Response {
  type RootResponse (line 42) | interface RootResponse extends Response {
  type GetProcessResponse (line 48) | interface GetProcessResponse {
  type ProcessDescriptor (line 52) | interface ProcessDescriptor {
  type TabsResponse (line 63) | interface TabsResponse extends Response {
  type Tab (line 67) | interface Tab {
  type TabDescriptor (line 75) | interface TabDescriptor {
  type TabDescriptorTargetResponse (line 79) | interface TabDescriptorTargetResponse extends Response {
  type AddonsResponse (line 83) | interface AddonsResponse extends Response {
  type Addon (line 87) | interface Addon {
  type InstallAddonResponse (line 103) | interface InstallAddonResponse extends Response {
  type GetTargetResponse (line 110) | interface GetTargetResponse extends Response {
  type DeviceDescriptionResponse (line 119) | interface DeviceDescriptionResponse extends Response {
  type DeviceDescription (line 123) | interface DeviceDescription {
  type TabAttachedResponse (line 128) | interface TabAttachedResponse extends TypedResponse {
  type TabWillNavigateResponse (line 132) | interface TabWillNavigateResponse extends TypedResponse {
  type TabDidNavigateResponse (line 137) | interface TabDidNavigateResponse extends TypedResponse {
  type FramesDestroyedResponse (line 143) | interface FramesDestroyedResponse extends TypedResponse {
  type FrameUpdateResponse (line 147) | interface FrameUpdateResponse extends TypedResponse {
  type WorkersResponse (line 156) | interface WorkersResponse extends Response {
  type Worker (line 160) | interface Worker {
  type WorkerAttachedResponse (line 166) | interface WorkerAttachedResponse extends TypedResponse {
  type WorkerConnectedResponse (line 170) | interface WorkerConnectedResponse extends TypedResponse {
  type LegacyGetCachedMessagesResponse (line 175) | interface LegacyGetCachedMessagesResponse extends Response {
  type LegacyCachedMessage (line 179) | type LegacyCachedMessage =
  type GetCachedMessagesResponse (line 183) | interface GetCachedMessagesResponse extends Response {
  type CachedMessage (line 187) | type CachedMessage =
  type PageErrorResponse (line 191) | interface PageErrorResponse extends TypedResponse {
  type PageErrorResponseBody (line 195) | interface PageErrorResponseBody {
  type ConsoleAPICallResponse (line 217) | interface ConsoleAPICallResponse extends TypedResponse {
  type ConsoleAPICallResponseBody (line 221) | interface ConsoleAPICallResponseBody {
  type ConsoleMessage (line 238) | interface ConsoleMessage {
  type LogMessageResponse (line 254) | interface LogMessageResponse extends TypedResponse {
  type ResultIDResponse (line 259) | interface ResultIDResponse extends Response {
  type EvaluationResultResponse (line 263) | interface EvaluationResultResponse extends TypedResponse {
  type AutoCompleteResponse (line 274) | interface AutoCompleteResponse extends Response {
  type ThreadPausedResponse (line 279) | interface ThreadPausedResponse extends TypedResponse {
  type ThreadPausedReason (line 286) | interface ThreadPausedReason {
  type GetBreakableLinesResponse (line 294) | interface GetBreakableLinesResponse extends Response {
  type GetBreakpointPositionsCompressedResponse (line 298) | interface GetBreakpointPositionsCompressedResponse extends Response {
  type BreakpointPositions (line 302) | interface BreakpointPositions {
  type SourceResponse (line 306) | interface SourceResponse extends Response {
  type SetBreakpointResponse (line 310) | interface SetBreakpointResponse extends Response {
  type PrototypeAndPropertiesResponse (line 316) | interface PrototypeAndPropertiesResponse extends TypedResponse {
  type GetWatcherResponse (line 323) | interface GetWatcherResponse extends Response {
  type GetBreakpointListResponse (line 330) | interface GetBreakpointListResponse extends Response {
  type GetThreadConfigurationResponse (line 336) | interface GetThreadConfigurationResponse extends Response {
  type ThreadConfiguration (line 342) | interface ThreadConfiguration {
  type GetAvailableEventBreakpointsResponse (line 354) | interface GetAvailableEventBreakpointsResponse extends Response {
  type AvailableEventCategory (line 358) | interface AvailableEventCategory {
  type AvailableEvent (line 363) | interface AvailableEvent {
  type TargetAvailableEvent (line 372) | interface TargetAvailableEvent extends Event {
  type TargetDestroyedEvent (line 394) | interface TargetDestroyedEvent extends Event {
  type DescriptorDestroyedEvent (line 401) | interface DescriptorDestroyedEvent extends Event {
  type ThreadState (line 405) | interface ThreadState {
  type CompletionValue (line 411) | interface CompletionValue {
  type Frame (line 417) | interface Frame {
  type GlobalFrame (line 426) | interface GlobalFrame extends Frame {
  type CallFrame (line 430) | interface CallFrame extends Frame {
  type EvalFrame (line 435) | interface EvalFrame extends Frame {
  type ClientEvalFrame (line 438) | interface ClientEvalFrame extends Frame {
  type SourceLocation (line 441) | interface SourceLocation {
  type Source (line 447) | interface Source {
  type SourceResource (line 461) | interface SourceResource extends Source {
  type ConsoleMessageResource (line 465) | interface ConsoleMessageResource {
  type ErrorMessageResource (line 470) | interface ErrorMessageResource {
  type ThreadStateResource (line 475) | interface ThreadStateResource extends ThreadState {
  type ResourceAvailableForm (line 479) | interface ResourceAvailableForm extends Event {
  type Sources (line 484) | type Sources = ['source', Source[]];
  type ConsoleMessages (line 485) | type ConsoleMessages = ['console-message', ConsoleMessage[]];
  type ErrorMessages (line 486) | type ErrorMessages = ['error-message', PageError[]];
  type ThreadStates (line 487) | type ThreadStates = ['thread-state', ThreadState[]];
  type Resources (line 488) | type Resources = (Sources | ConsoleMessages | ErrorMessages | ThreadStat...
  type ResourcesAvailableEvent (line 490) | interface ResourcesAvailableEvent extends Event {
  type FrameUpdateEvent (line 495) | interface FrameUpdateEvent extends Event {
  type PageError (line 499) | interface PageError {
  type Environment (line 521) | interface Environment {
  type ObjectEnvironment (line 527) | interface ObjectEnvironment extends Environment {
  type FunctionEnvironment (line 531) | interface FunctionEnvironment extends Environment {
  type WithEnvironment (line 538) | interface WithEnvironment extends Environment {
  type BlockEnvironment (line 542) | interface BlockEnvironment extends Environment {
  type Bindings (line 546) | interface Bindings {
  type FunctionBindings (line 550) | interface FunctionBindings extends Bindings {
  type PropertyDescriptor (line 554) | interface PropertyDescriptor {
  type DataPropertyDescriptor (line 559) | interface DataPropertyDescriptor extends PropertyDescriptor {
  type AccessorPropertyDescriptor (line 564) | interface AccessorPropertyDescriptor extends PropertyDescriptor {
  type SafeGetterValueDescriptor (line 569) | interface SafeGetterValueDescriptor {
  type PropertyDescriptors (line 576) | interface PropertyDescriptors {
  type SafeGetterValueDescriptors (line 580) | interface SafeGetterValueDescriptors {
  type NamedPropertyDescriptor (line 584) | interface NamedPropertyDescriptor {
  type NamedDataPropertyDescriptor (line 589) | interface NamedDataPropertyDescriptor {
  type Grip (line 594) | type Grip = boolean | number | string | ComplexGrip;
  type ComplexGrip (line 596) | interface ComplexGrip {
  type ObjectGrip (line 600) | interface ObjectGrip extends ComplexGrip {
  type Preview (line 607) | type Preview = ObjectPreview | DatePreview | ObjectWithURLPreview | DOMN...
  type ObjectPreview (line 610) | interface ObjectPreview {
  type PropertyPreview (line 619) | interface PropertyPreview {
  type DatePreview (line 628) | interface DatePreview {
  type ObjectWithURLPreview (line 633) | interface ObjectWithURLPreview {
  type DOMNodePreview (line 638) | interface DOMNodePreview {
  type DOMEventPreview (line 648) | interface DOMEventPreview {
  type ArrayLikePreview (line 655) | interface ArrayLikePreview {
  type SafeGetterValuePreview (line 661) | interface SafeGetterValuePreview {
  type ErrorPreview (line 668) | interface ErrorPreview {
  type FunctionGrip (line 678) | interface FunctionGrip extends ObjectGrip {
  type LongStringGrip (line 690) | interface LongStringGrip extends ComplexGrip {
  type SymbolGrip (line 697) | interface SymbolGrip extends ComplexGrip {
  type BigIntGrip (line 702) | interface BigIntGrip extends ComplexGrip {

FILE: src/adapter/firefox/sourceMaps/info.ts
  constant GREATEST_LOWER_BOUND (line 8) | let GREATEST_LOWER_BOUND = SourceMapConsumer.GREATEST_LOWER_BOUND;
  constant LEAST_UPPER_BOUND (line 9) | let LEAST_UPPER_BOUND = SourceMapConsumer.LEAST_UPPER_BOUND;
  type MappingItem (line 15) | interface MappingItem {
  class SourceMappingInfo (line 22) | class SourceMappingInfo {
    method hasSourceMap (line 26) | public get hasSourceMap(): boolean { return !!this.sourceMapConsumer; }
    method constructor (line 28) | public constructor(
    method computeColumnSpans (line 36) | public computeColumnSpans(): void {
    method originalLocationFor (line 43) | public originalLocationFor(generatedLocation: LocationWithColumn): Url...
    method eachMapping (line 89) | public eachMapping(callback: (mapping: MappingItem) => void): void {
    method sourceContentFor (line 103) | public sourceContentFor(source: string): string | undefined {
    method syncBlackboxFlag (line 110) | public syncBlackboxFlag(): void {
    method disposeSource (line 122) | public disposeSource(source: ISourceActorProxy): void {
    method resolveSource (line 135) | public resolveSource(sourceUrl: string): string {
    method findUnresolvedSource (line 158) | public findUnresolvedSource(resolvedSource: string): string | undefined {

FILE: src/adapter/firefox/sourceMaps/manager.ts
  class SourceMapsManager (line 18) | class SourceMapsManager {
    method constructor (line 23) | public constructor(
    method getOrCreateSourceMappingInfo (line 29) | public getOrCreateSourceMappingInfo(source: FirefoxDebugProtocol.Sourc...
    method getSourceMappingInfo (line 60) | public getSourceMappingInfo(actor: string): Promise<SourceMappingInfo> {
    method findOriginalLocation (line 78) | public async findOriginalLocation(
    method applySourceMapToFrame (line 117) | public async applySourceMapToFrame(frame: FirefoxDebugProtocol.Frame):...
    method createSourceMappingInfo (line 139) | private async createSourceMappingInfo(source: FirefoxDebugProtocol.Sou...
    method createOriginalSource (line 218) | private createOriginalSource(

FILE: src/adapter/firefox/sourceMaps/source.ts
  type Breakables (line 9) | interface Breakables {
  class SourceMappingSourceActorProxy (line 14) | class SourceMappingSourceActorProxy implements ISourceActorProxy {
    method name (line 16) | public get name(): string {
    method url (line 20) | public get url(): string {
    method underlyingActor (line 24) | public get underlyingActor(): SourceActorProxy { return this.sourceMap...
    method constructor (line 28) | public constructor(
    method getBreakableLines (line 33) | public async getBreakableLines(): Promise<number[]> {
    method getBreakableLocations (line 43) | public async getBreakableLocations(line: number): Promise<MappedLocati...
    method getAllBreakables (line 53) | private async getAllBreakables(): Promise<Breakables> {
    method fetchSource (line 154) | public async fetchSource(): Promise<FirefoxDebugProtocol.Grip> {
    method setBlackbox (line 167) | public async setBlackbox(blackbox: boolean): Promise<void> {
    method dispose (line 172) | public dispose(): void {

FILE: src/adapter/firefox/sourceMaps/thread.ts
  class SourceMappingThreadActorProxy (line 8) | class SourceMappingThreadActorProxy extends EventEmitter implements IThr...
    method constructor (line 10) | public constructor(
    method name (line 17) | public get name(): string {
    method fetchStackFrames (line 21) | public async fetchStackFrames(
    method resume (line 33) | public resume(resumeLimitType?: 'next' | 'step' | 'finish' | 'restart'...
    method interrupt (line 37) | public interrupt(immediately: boolean = true): Promise<void> {
    method getAvailableEventBreakpoints (line 41) | public async getAvailableEventBreakpoints() : Promise<FirefoxDebugProt...
    method dispose (line 45) | public dispose(): void {

FILE: src/adapter/firefox/transport.ts
  class DebugProtocolTransport (line 12) | class DebugProtocolTransport extends EventEmitter {
    method constructor (line 19) | constructor(
    method sendMessage (line 83) | public sendMessage(msg: any): void {
    method disconnect (line 89) | public disconnect(): Promise<void> {

FILE: src/adapter/firefoxDebugAdapter.ts
  class FirefoxDebugAdapter (line 19) | class FirefoxDebugAdapter extends DebugAdapterBase {
    method constructor (line 23) | public constructor(debuggerLinesStartAt1: boolean, isServer: boolean =...
    method initialize (line 33) | protected initialize(args: DebugProtocol.InitializeRequestArguments): ...
    method launch (line 68) | protected async launch(args: LaunchConfiguration): Promise<void> {
    method attach (line 72) | protected async attach(args: AttachConfiguration): Promise<void> {
    method startSession (line 76) | private async startSession(config: LaunchConfiguration | AttachConfigu...
    method breakpointLocations (line 85) | protected async breakpointLocations(
    method setBreakpoints (line 99) | protected setBreakpoints(args: DebugProtocol.SetBreakpointsArguments):...
    method setExceptionBreakpoints (line 128) | protected setExceptionBreakpoints(args: DebugProtocol.SetExceptionBrea...
    method pause (line 140) | protected async pause(args: DebugProtocol.PauseArguments): Promise<voi...
    method next (line 152) | protected async next(args: DebugProtocol.NextArguments): Promise<void> {
    method stepIn (line 160) | protected async stepIn(args: DebugProtocol.StepInArguments): Promise<v...
    method stepOut (line 168) | protected async stepOut(args: DebugProtocol.StepOutArguments): Promise...
    method continue (line 176) | protected async continue(args: DebugProtocol.ContinueArguments): Promi...
    method getSource (line 185) | protected async getSource(args: DebugProtocol.SourceArguments): Promis...
    method getThreads (line 222) | protected getThreads(): { threads: DebugProtocol.Thread[] } {
    method getStackTrace (line 232) | protected async getStackTrace(args: DebugProtocol.StackTraceArguments)...
    method getScopes (line 247) | protected async getScopes(args: DebugProtocol.ScopesArguments): Promis...
    method getVariables (line 262) | protected async getVariables(args: DebugProtocol.VariablesArguments): ...
    method setVariable (line 290) | protected async setVariable(args: DebugProtocol.SetVariableArguments):...
    method evaluate (line 308) | protected async evaluate(args: DebugProtocol.EvaluateArguments): Promi...
    method getCompletions (line 371) | protected async getCompletions(args: DebugProtocol.CompletionsArgument...
    method dataBreakpointInfo (line 408) | protected async dataBreakpointInfo(args: DebugProtocol.DataBreakpointI...
    method setDataBreakpoints (line 440) | protected async setDataBreakpoints(args: DebugProtocol.SetDataBreakpoi...
    method restartFrame (line 453) | protected async restartFrame(args: DebugProtocol.RestartFrameArguments...
    method reloadAddon (line 465) | protected async reloadAddon(): Promise<void> {
    method toggleSkippingFile (line 473) | protected async toggleSkippingFile(url: string): Promise<void> {
    method setPopupAutohide (line 487) | protected async setPopupAutohide(enabled: boolean): Promise<void> {
    method togglePopupAutohide (line 491) | protected async togglePopupAutohide(): Promise<boolean> {
    method setActiveEventBreakpoints (line 498) | protected setActiveEventBreakpoints(args: string[] | undefined): Promi...
    method disconnect (line 502) | protected async disconnect(args: DebugProtocol.DisconnectArguments): P...
    method getThreadAdapter (line 506) | private getThreadAdapter(threadId: number): ThreadAdapter {

FILE: src/adapter/firefoxDebugSession.ts
  type ThreadConfiguration (line 51) | type ThreadConfiguration = Pick<
  class FirefoxDebugSession (line 56) | class FirefoxDebugSession {
    method constructor (line 102) | public constructor(
    method start (line 121) | public start(): Promise<void> {
    method stop (line 255) | public async stop(): Promise<void> {
    method setThreadConfiguration (line 259) | public setThreadConfiguration(threadConfiguration: ThreadConfiguration) {
    method setActiveThread (line 268) | public setActiveThread(threadAdapter: ThreadAdapter): void {
    method getActiveThread (line 272) | public getActiveThread(): ThreadAdapter | undefined {
    method getOrCreateObjectGripActorProxy (line 288) | public getOrCreateObjectGripActorProxy(objectGrip: FirefoxDebugProtoco...
    method getOrCreateLongStringGripActorProxy (line 293) | public getOrCreateLongStringGripActorProxy(longStringGrip: FirefoxDebu...
    method connectToFirefox (line 298) | private async connectToFirefox(): Promise<Socket> {
    method disconnectFirefoxAndCleanup (line 343) | private async disconnectFirefoxAndCleanup(): Promise<void> {
    method attachDescriptor (line 392) | public async attachDescriptor(descriptorActor: DescriptorActorProxy) {
    method attachThread (line 504) | private async attachThread(
    method attachSource (line 632) | private attachSource(sourceActor: ISourceActorProxy, threadAdapter: Th...
    method sendConsoleMessage (line 660) | private async sendConsoleMessage(message: FirefoxDebugProtocol.Console...
    method addLocation (line 722) | private async addLocation(
    method sendStoppedEvent (line 739) | public sendStoppedEvent(
    method sendThreadStartedEvent (line 769) | private sendThreadStartedEvent(threadAdapter: ThreadAdapter): void {
    method sendThreadExitedEvent (line 778) | private sendThreadExitedEvent(threadAdapter: ThreadAdapter): void {
    method sendNewSourceEvent (line 786) | private sendNewSourceEvent(threadAdapter: ThreadAdapter, sourceAdapter...
    method sendCustomEvent (line 800) | public sendCustomEvent(event: string, eventBody: any): void {

FILE: src/adapter/location.ts
  type Location (line 1) | interface Location {
  type UrlLocation (line 6) | interface UrlLocation extends Location {
  type LocationWithColumn (line 10) | interface LocationWithColumn extends Location {
  type MappedLocation (line 14) | interface MappedLocation extends LocationWithColumn {
  type Range (line 18) | interface Range {

FILE: src/adapter/util/delayedTask.ts
  class DelayedTask (line 5) | class DelayedTask<T> {
    method constructor (line 13) | public constructor(
    method execute (line 25) | public async execute(): Promise<void> {
    method cancel (line 45) | public cancel(reason?: any): void {

FILE: src/adapter/util/fs.ts
  function isExecutable (line 7) | async function isExecutable(path: string): Promise<boolean> {
  function normalizePath (line 19) | function normalizePath(sourcePathOrUrl: string): string {

FILE: src/adapter/util/log.ts
  type NumericLogLevel (line 4) | enum NumericLogLevel { Debug, Info, Warn, Error }
  class Log (line 10) | class Log {
    method setConfig (line 19) | public static async setConfig(newConfig: LogConfiguration) {
    method create (line 37) | public static create(name: string): Log {
    method constructor (line 45) | constructor(private name: string) {
    method debug (line 50) | public debug(msg: string): void {
    method info (line 54) | public info(msg: string): void {
    method warn (line 58) | public warn(msg: string): void {
    method error (line 62) | public error(msg: string): void {
    method isDebugEnabled (line 66) | public isDebugEnabled(): boolean {
    method isInfoEnabled (line 70) | public isInfoEnabled(): boolean {
    method isWarnEnabled (line 74) | public isWarnEnabled(): boolean {
    method isErrorEnabled (line 78) | public isErrorEnabled(): boolean {
    method configure (line 82) | private configure() {
    method convertLogLevel (line 104) | private convertLogLevel(logLevel: LogLevel): NumericLogLevel | undefin...
    method log (line 124) | private log(msg: string, level: NumericLogLevel, displayLevel: string) {

FILE: src/adapter/util/misc.ts
  function pathsAreEqual (line 10) | function pathsAreEqual(path1: string, path2: string | undefined) {
  function normalizePath (line 22) | function normalizePath(rawPath: string) {
  function shortenUrl (line 34) | function shortenUrl(url: string) {
  function exceptionGripToString (line 47) | function exceptionGripToString(grip: FirefoxDebugProtocol.Grip | null | ...
  function accessorExpression (line 78) | function accessorExpression(objectExpression: string | undefined, proper...
  function findAddonId (line 94) | async function findAddonId(addonPath: string): Promise<string | undefine...
  function compareStrings (line 105) | function compareStrings(s1: string, s2: string): number {

FILE: src/adapter/util/net.ts
  function connect (line 17) | function connect(port: number, host?: string): Promise<net.Socket> {
  function waitForSocket (line 31) | async function waitForSocket(port: number, timeout: number): Promise<net...
  function urlBasename (line 45) | function urlBasename(url: string): string {
  function urlDirname (line 54) | function urlDirname(url: string): string {
  function getUri (line 66) | async function getUri(uri: string): Promise<string> {

FILE: src/adapter/util/pathMapper.ts
  class PathMapper (line 18) | class PathMapper {
    method constructor (line 20) | constructor(
    method convertFirefoxSourceToPath (line 26) | public convertFirefoxSourceToPath(source: FirefoxDebugProtocol.Source)...
    method convertFirefoxUrlToPath (line 85) | public convertFirefoxUrlToPath(url: string): string | undefined {
    method removeQueryString (line 139) | removeQueryString(path: string): string {

FILE: src/adapter/util/pendingRequests.ts
  type PendingRequest (line 5) | interface PendingRequest<T> {
  class PendingRequests (line 10) | class PendingRequests<T> {
    method enqueue (line 14) | public enqueue(req: PendingRequest<T>) {
    method resolveOne (line 18) | public resolveOne(t: T) {
    method rejectOne (line 27) | public rejectOne(err: any) {
    method isEmpty (line 36) | public isEmpty(): boolean {
    method resolveAll (line 40) | public resolveAll(t: T) {
    method rejectAll (line 45) | public rejectAll(err: any) {

FILE: src/common/configuration.ts
  type LaunchConfiguration (line 6) | interface LaunchConfiguration extends CommonConfiguration, DebugProtocol...
  type AttachConfiguration (line 22) | interface AttachConfiguration extends CommonConfiguration, DebugProtocol...
  type CommonConfiguration (line 31) | interface CommonConfiguration {
  type ReloadConfiguration (line 53) | type ReloadConfiguration = string | string[] | DetailedReloadConfiguration;
  type DetailedReloadConfiguration (line 55) | interface DetailedReloadConfiguration {
  type TabFilterConfiguration (line 61) | type TabFilterConfiguration = string | string[] | DetailedTabFilterConfi...
  type DetailedTabFilterConfiguration (line 63) | interface DetailedTabFilterConfiguration {
  type LogLevel (line 68) | type LogLevel = 'Debug' | 'Info' | 'Warn' | 'Error';
  type LogConfiguration (line 70) | interface LogConfiguration {

FILE: src/common/customEvents.ts
  type ThreadStartedEventBody (line 1) | interface ThreadStartedEventBody {
  type ThreadExitedEventBody (line 6) | interface ThreadExitedEventBody {
  type NewSourceEventBody (line 10) | interface NewSourceEventBody {
  type RemoveSourcesEventBody (line 19) | interface RemoveSourcesEventBody {
  type PopupAutohideEventBody (line 23) | interface PopupAutohideEventBody {
  type AvailableEventCategory (line 27) | interface AvailableEventCategory {
  type AvailableEvent (line 32) | interface AvailableEvent {
  type AvailableEventsEventBody (line 37) | type AvailableEventsEventBody = AvailableEventCategory[];

FILE: src/common/deferredMap.ts
  class DeferredMap (line 1) | class DeferredMap<S, T> {
    method get (line 6) | public get(key: S): Promise<T> {
    method getExisting (line 19) | public getExisting(key: S): T | undefined {
    method getAllExisting (line 23) | public getAllExisting(): T[] {
    method set (line 27) | public set(key: S, value: T): void {
    method delete (line 38) | public delete(key: S) {

FILE: src/common/util.ts
  function delay (line 3) | function delay(timeout: number): Promise<void> {
  function isWindowsPlatform (line 9) | function isWindowsPlatform(): boolean {

FILE: src/extension/addPathMapping.ts
  type LaunchConfig (line 5) | interface LaunchConfig {
  type LaunchConfigReference (line 10) | interface LaunchConfigReference {
  function addPathMapping (line 16) | async function addPathMapping(treeNode: TreeNode): Promise<void> {
  function addNullPathMapping (line 45) | async function addNullPathMapping(treeNode: TreeNode): Promise<void> {
  function _findLaunchConfig (line 58) | function _findLaunchConfig(): LaunchConfigReference | undefined {
  function findLaunchConfig (line 81) | function findLaunchConfig(
  function addPathMappingToLaunchConfig (line 102) | async function addPathMappingToLaunchConfig(
  function showLaunchConfig (line 132) | async function showLaunchConfig(workspaceFolder: vscode.WorkspaceFolder)...

FILE: src/extension/debugConfigurationProvider.ts
  class DebugConfigurationProvider (line 8) | class DebugConfigurationProvider implements vscode.DebugConfigurationPro...
    method resolveDebugConfiguration (line 21) | resolveDebugConfiguration(
    method overrideFromSettings (line 65) | private overrideFromSettings(
    method getSetting (line 107) | private getSetting<T>(settings: vscode.WorkspaceConfiguration, key: st...
    method resolveWorkspaceFolder (line 118) | private resolveWorkspaceFolder(
    method checkLocal (line 149) | private checkLocal(

FILE: src/extension/eventBreakpointsProvider.ts
  class EventBreakpointsProvider (line 4) | class EventBreakpointsProvider implements vscode.TreeDataProvider<TreeNo...
    method constructor (line 12) | constructor() {
    method setAvailableEvents (line 16) | setAvailableEvents(availableEvents: AvailableEventCategory[]) {
    method getAvailableEvents (line 21) | getAvailableEvents() {
    method updateActiveEventBreakpoints (line 25) | updateActiveEventBreakpoints(event: vscode.TreeCheckboxChangeEvent<Tre...
    method getTreeItem (line 32) | getTreeItem(element: TreeNode): vscode.TreeItem | Thenable<vscode.Tree...
    method getChildren (line 36) | getChildren(element?: TreeNode | undefined): vscode.ProviderResult<Tre...
  type TreeNode (line 41) | interface TreeNode {
  class RootNode (line 47) | class RootNode implements TreeNode {
    method constructor (line 51) | constructor(private readonly provider: EventBreakpointsProvider) {
    method setChecked (line 55) | setChecked(checked: boolean): void {}
    method getChildren (line 57) | getChildren(): TreeNode[] {
  class CategoryNode (line 62) | class CategoryNode implements TreeNode {
    method constructor (line 66) | constructor(
    method setChecked (line 76) | setChecked(checked: boolean): void {
    method getChildren (line 86) | getChildren(): TreeNode[] {
  class EventNode (line 91) | class EventNode implements TreeNode {
    method constructor (line 95) | constructor(
    method setChecked (line 105) | setChecked(checked: boolean): void {

FILE: src/extension/loadedScripts/fileNode.ts
  class FileNode (line 6) | class FileNode extends TreeNode {
    method constructor (line 8) | public constructor(
    method getChildren (line 32) | public getChildren(): TreeNode[] {
    method getFullPath (line 36) | public getFullPath(): string {

FILE: src/extension/loadedScripts/nonLeafNode.ts
  method constructor (line 11) | public constructor(label: string, parent: TreeNode) {
  method addSource (line 15) | public addSource(
  method getChildren (line 76) | public getChildren(): TreeNode[] {
  method addChild (line 84) | private addChild(newChild: DirectoryNode | FileNode): void {
  class ThreadNode (line 114) | class ThreadNode extends NonLeafNode {
    method constructor (line 118) | public constructor(threadInfo: ThreadStartedEventBody, parent: Session...
    method removeSources (line 124) | public removeSources(): TreeNode | undefined {
  class DirectoryNode (line 130) | class DirectoryNode extends NonLeafNode {
    method constructor (line 132) | public constructor(public path: string[], parent: TreeNode) {
    method split (line 141) | public split(atIndex: number): void {
    method getFullPath (line 152) | public getFullPath(): string {

FILE: src/extension/loadedScripts/provider.ts
  class LoadedScriptsProvider (line 6) | class LoadedScriptsProvider implements vscode.TreeDataProvider<TreeNode> {
    method constructor (line 13) | public constructor() {
    method getTreeItem (line 17) | public getTreeItem(node: TreeNode): vscode.TreeItem {
    method getChildren (line 21) | public getChildren(node?: TreeNode): vscode.ProviderResult<TreeNode[]> {
    method hasSession (line 26) | public hasSession(sessionId: string) {
    method addSession (line 30) | public addSession(session: vscode.DebugSession) {
    method removeSession (line 35) | public removeSession(sessionId: string) {
    method addThread (line 40) | public async addThread(threadInfo: ThreadStartedEventBody, sessionId: ...
    method removeThread (line 45) | public async removeThread(threadId: number, sessionId: string) {
    method addSource (line 50) | public async addSource(sourceInfo: NewSourceEventBody, sessionId: stri...
    method removeSources (line 55) | public async removeSources(threadId: number, sessionId: string) {
    method getSourceUrls (line 60) | public async getSourceUrls(sessionId: string): Promise<string[] | unde...
    method sendTreeDataChangedEvent (line 64) | private sendTreeDataChangedEvent(changedItem: TreeNode | undefined) {

FILE: src/extension/loadedScripts/rootNode.ts
  class RootNode (line 7) | class RootNode extends TreeNode {
    method constructor (line 12) | public constructor() {
    method waitForSession (line 17) | private waitForSession(sessionId: string): Promise<SessionNode> {
    method hasSession (line 21) | public hasSession(sessionId: string): boolean {
    method addSession (line 25) | public addSession(session: vscode.DebugSession): TreeNode | undefined {
    method removeSession (line 30) | public removeSession(sessionId: string): TreeNode | undefined {
    method addThread (line 35) | public async addThread(
    method removeThread (line 45) | public async removeThread(
    method addSource (line 55) | public async addSource(
    method removeSources (line 65) | public async removeSources(threadId: number, sessionId: string): Promi...
    method getSourceUrls (line 72) | public async getSourceUrls(sessionId: string): Promise<string[] | unde...
    method getChildren (line 79) | public getChildren(): TreeNode[] {
    method fixChangedItem (line 99) | private fixChangedItem(changedItem: TreeNode | undefined): TreeNode | ...

FILE: src/extension/loadedScripts/sessionNode.ts
  class SessionNode (line 7) | class SessionNode extends TreeNode {
    method id (line 13) | public get id() {
    method constructor (line 17) | public constructor(private session: vscode.DebugSession, parent: RootN...
    method addThread (line 22) | public addThread(threadInfo: ThreadStartedEventBody): TreeNode | undef...
    method removeThread (line 38) | public removeThread(threadId: number): TreeNode | undefined {
    method addSource (line 45) | public addSource(sourceInfo: NewSourceEventBody): TreeNode | undefined {
    method removeSources (line 82) | public removeSources(threadId: number): TreeNode | undefined {
    method getSourceUrls (line 91) | public getSourceUrls(): string[] {
    method getChildren (line 95) | public getChildren(): TreeNode[] {
    method fixChangedItem (line 113) | private fixChangedItem(changedItem: TreeNode | undefined): TreeNode | ...
  function splitURL (line 128) | function splitURL(urlString: string): string[] {

FILE: src/extension/loadedScripts/treeNode.ts
  method constructor (line 7) | public constructor(
  method getFullPath (line 17) | public getFullPath(): string {

FILE: src/extension/main.ts
  function activate (line 11) | function activate(context: vscode.ExtensionContext) {
  function sendCustomRequest (line 96) | async function sendCustomRequest(command: string, args?: any): Promise<a...
  function onDidStartSession (line 104) | function onDidStartSession(
  function onDidTerminateSession (line 114) | function onDidTerminateSession(
  function onCustomEvent (line 128) | function onCustomEvent(
  function openScript (line 169) | async function openScript(pathOrUri: string) {

FILE: src/extension/pathMappingWizard.ts
  type PathMapping (line 7) | interface PathMapping {
  function createPathMappingForActiveTextEditor (line 12) | async function createPathMappingForActiveTextEditor(loadedScriptsProvide...
  function createPathMappingForPath (line 70) | async function createPathMappingForPath(
  function createPathMapping (line 120) | async function createPathMapping(
  function findBestMatch (line 150) | function findBestMatch(vscPath: string, ffUrls: URL[]): URL | undefined {
  function createPathMappingForMatch (line 183) | async function createPathMappingForMatch(
  function generalizePathMapping (line 206) | function generalizePathMapping(pathMapping: PathMapping): PathMapping | ...
  function checkPathMapping (line 221) | async function checkPathMapping(pathMapping: PathMapping, ffUrls: URL[])...
  function applyPathMapping (line 246) | function applyPathMapping(ffUrl: string, pathMapping: PathMapping): stri...
  function isWindowsAbsolutePath (line 260) | function isWindowsAbsolutePath(path: string): boolean {
  function vscodePathToUri (line 264) | function vscodePathToUri(path: string): vscode.Uri {
  function vscodeUriToPath (line 272) | function vscodeUriToPath(uri: vscode.Uri): string {
  function vscodePathSep (line 276) | function vscodePathSep(path: string): string {

FILE: src/extension/popupAutohideManager.ts
  class PopupAutohideManager (line 3) | class PopupAutohideManager {
    method constructor (line 7) | constructor(
    method setPopupAutohide (line 11) | public async setPopupAutohide(popupAutohide: boolean): Promise<void> {
    method togglePopupAutohide (line 16) | public async togglePopupAutohide(): Promise<void> {
    method enableButton (line 21) | public enableButton(popupAutohide: boolean): void {
    method disableButton (line 33) | public disableButton(): void {
    method setButtonText (line 40) | private setButtonText(popupAutohide: boolean): void {

FILE: src/test/setup.ts
  method beforeAll (line 7) | async beforeAll() {

FILE: src/test/sourceMapUtil.ts
  function testSourcemaps (line 9) | async function testSourcemaps(
  function checkDebuggeeState (line 41) | async function checkDebuggeeState(
  function copyFiles (line 63) | async function copyFiles(sourceDir: string, targetDir: string, files: st...
  function injectScriptTags (line 68) | async function injectScriptTags(targetDir: string, scripts: string[]): P...
  function waitForStreamEnd (line 76) | function waitForStreamEnd(s: Stream): Promise<void> {

FILE: src/test/testAccessorProperties.ts
  function startAndGetProperties (line 92) | async function startAndGetProperties(dc: DebugClient, bpLine: number, tr...

FILE: src/test/testConfigurationParser.ts
  function assertPromiseRejects (line 797) | async function assertPromiseRejects(promise: Promise<any>, reason: strin...

FILE: src/test/testDataBreakpoints.ts
  function setupDataBreakpoint (line 60) | async function setupDataBreakpoint(sourcePath: string): Promise<string> {

FILE: src/test/testDebugAddons.ts
  constant TESTDATA_PATH (line 8) | const TESTDATA_PATH = path.join(__dirname, '../../testdata');
  function debugWebExtension (line 46) | async function debugWebExtension(dc: DebugClient, addonDirectory = 'webE...

FILE: src/test/testGulpSourceMaps.ts
  constant TESTDATA_PATH (line 16) | const TESTDATA_PATH = path.join(__dirname, '../../testdata/web/sourceMap...
  type TargetPaths (line 66) | interface TargetPaths {
  function prepareTargetDir (line 72) | async function prepareTargetDir(
  function build (line 103) | function build(

FILE: src/test/testInspectVariables.ts
  function factorial (line 181) | function factorial(n: number): number {

FILE: src/test/testSourceActorCollection.ts
  class FakeSourceActorProxy (line 7) | class FakeSourceActorProxy implements ISourceActorProxy {
    method constructor (line 19) | constructor(public readonly name: string) {}
    method getBreakableLines (line 20) | getBreakableLines(): Promise<number[]> {
    method getBreakableLocations (line 23) | getBreakableLocations(line: number): Promise<MappedLocation[]> {
    method fetchSource (line 26) | fetchSource(): Promise<FirefoxDebugProtocol.Grip> {
    method setBlackbox (line 29) | setBlackbox(blackbox: boolean): Promise<void> {
    method dispose (line 32) | dispose(): void {
  function getName (line 40) | async function getName(actor: ISourceActorProxy) {
  function getNameOrFail (line 44) | async function getNameOrFail(actor: ISourceActorProxy) {

FILE: src/test/testWebpackSourceMaps.ts
  constant TESTDATA_PATH (line 12) | const TESTDATA_PATH = path.join(__dirname, '../../testdata/web/sourceMap...
  function prepareTargetDir (line 76) | async function prepareTargetDir(): Promise<string> {
  type Devtool (line 85) | type Devtool = `${'inline-' | 'hidden-' | 'eval-' | ''}${'nosources-' | ...
  function build (line 87) | function build(targetDir: string, devtool: Devtool): Promise<void> {

FILE: src/test/util.ts
  function initDebugClient (line 8) | async function initDebugClient(
  function initDebugClientForAddon (line 44) | async function initDebugClientForAddon(
  function processEnvironmentVariables (line 100) | function processEnvironmentVariables(launchArgs: LaunchConfiguration) {
  function waitForUnoccupiedPort (line 122) | async function waitForUnoccupiedPort(port: number, timeout: number) {
  function isPortOccupied (line 135) | async function isPortOccupied(port: number): Promise<boolean> {
  function receivePageLoadedEvent (line 152) | async function receivePageLoadedEvent(dc: DebugClient, lenient: boolean ...
  function setBreakpoints (line 164) | async function setBreakpoints(
  function receiveBreakpointEvent (line 200) | function receiveBreakpointEvent(dc: DebugClient): Promise<DebugProtocol....
  function receiveStoppedEvent (line 204) | function receiveStoppedEvent(dc: DebugClient): Promise<DebugProtocol.Eve...
  function collectOutputEvents (line 208) | function collectOutputEvents(dc: DebugClient, count: number): Promise<De...
  function runCommandAndReceiveStoppedEvent (line 225) | async function runCommandAndReceiveStoppedEvent(dc: DebugClient, command...
  function evaluate (line 231) | function evaluate(dc: DebugClient, js: string): Promise<DebugProtocol.Ev...
  function evaluateDelayed (line 235) | function evaluateDelayed(dc: DebugClient, js: string, delay: number): Pr...
  function evaluateCloaked (line 240) | function evaluateCloaked(dc: DebugClient, js: string): Promise<DebugProt...
  function assertPromiseTimeout (line 246) | async function assertPromiseTimeout(promise: Promise<any>, timeout: numb...
  function findVariable (line 256) | function findVariable(variables: DebugProtocol.Variable[], varName: stri...
  function findTabThread (line 265) | async function findTabThread(dc: DebugClient): Promise<number> {
  function setConsoleThread (line 275) | async function setConsoleThread(dc: DebugClient, threadId: number): Prom...

FILE: testdata/web/debuggerStatement.js
  function debuggerStatement (line 3) | function debuggerStatement() {

FILE: testdata/web/dlscript.js
  function dynTest (line 1) | function dynTest() {

FILE: testdata/web/main.js
  function noop (line 1) | function noop() {
  function vars (line 7) | function vars(arg) {
  function factorial (line 23) | function factorial(n) {
  function loadScript (line 31) | function loadScript(url) {
  function throwUncaughtException (line 39) | function throwUncaughtException() {
  function throwAndCatchException (line 43) | function throwAndCatchException() {
  function startWorker (line 51) | function startWorker() {
  function callWorker (line 59) | function callWorker() {
  function doEval (line 70) | function doEval(expr) {
  function testSkipFiles (line 74) | function testSkipFiles() {
  function log (line 79) | function log(...x) {
  function getterAndSetter (line 83) | function getterAndSetter() {
  class ProtoGetterBase (line 101) | class ProtoGetterBase {
    method constructor (line 102) | constructor() {
    method z (line 105) | get z() { return this._z; }
  class ProtoGetter (line 107) | class ProtoGetter extends ProtoGetterBase {
    method constructor (line 108) | constructor() {
    method y (line 112) | get y() { return this._y; }
  function protoGetter (line 114) | function protoGetter() {
  function inc (line 119) | function inc(o) {

FILE: testdata/web/skip.js
  function dummyFunc (line 1) | function dummyFunc() {
  function throwError (line 4) | function throwError() {

FILE: testdata/web/sourceMaps/modules/f.js
  function f (line 4) | function f() {

FILE: testdata/web/sourceMaps/modules/g.js
  function g (line 4) | function g(y) {

FILE: testdata/web/sourceMaps/scripts/f.js
  function f (line 4) | function f() {

FILE: testdata/web/sourceMaps/scripts/g.js
  function g (line 4) | function g(y) {
Condensed preview — 144 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (545K chars).
[
  {
    "path": ".gitignore",
    "chars": 109,
    "preview": "node_modules/\n.nyc_output/\ncoverage/\ndist/*.bundle.js\ndist/*.bundle.js.map\ndist/mappings.wasm\ndist/*LICENSE*\n"
  },
  {
    "path": ".mocharc.json",
    "chars": 152,
    "preview": "{\n\t\"require\": [\"ts-node/register/transpile-only\", \"src/test/setup.ts\"],\n\t\"timeout\": 20000,\n\t\"slow\": 6000,\n\t\"exit\": true,"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 460,
    "preview": "{\n\t// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.\n\t// Extension identif"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 992,
    "preview": "{\n\t\"version\": \"0.2.0\",\n\t\"configurations\": [\n\t\t{\n\t\t\t\"type\": \"pwa-node\",\n\t\t\t\"request\": \"launch\",\n\t\t\t\"name\": \"debug server\""
  },
  {
    "path": ".vscode/settings.json",
    "chars": 240,
    "preview": "{\n\t\"editor.insertSpaces\": false,\n\t\"files.exclude\": {\n\t\t\".git\": true,\n\t\t\"node_modules\": true,\n\t\t\".nyc_output\": true,\n\t\t\"c"
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 384,
    "preview": "{\n\t\"version\": \"2.0.0\",\n\t\"tasks\": [\n\t\t{\n\t\t\t\"type\": \"npm\",\n\t\t\t\"script\": \"watch\",\n\t\t\t\"label\": \"watch\",\n\t\t\t\"isBackground\": t"
  },
  {
    "path": ".vscodeignore",
    "chars": 189,
    "preview": "src/**\nnode_modules/**\n**/*.map\npackage-lock.json\ntsconfig.json\nwebpack.config.js\n.vscode/**\n.gitignore\n.nyc_output/**\nc"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 15370,
    "preview": "### Version 2.15.0\n* fix various issues when debugging multiple tabs\n* use the URL in thread names\n\n### Version 2.14.1\n*"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 1226,
    "preview": "## Mozilla Community Participation Guidelines\n\nThis repository is governed by Mozilla's code of conduct and etiquette gu"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1938,
    "preview": "# Hacking the VS Code Debug Adapter for Firefox\n\n## Prerequisites\nFirst of all, you should familiarize yourself with the"
  },
  {
    "path": "LICENSE",
    "chars": 1102,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015-2017 Holger Benl <hbenl@evandor.de>\n\nPermission is hereby granted, free of cha"
  },
  {
    "path": "README.md",
    "chars": 21476,
    "preview": "<h1 align=\"center\">\n  <br>\n    <img src=\"https://github.com/firefox-devtools/vscode-firefox-debug/blob/master/icon.png?r"
  },
  {
    "path": "dist/README.md",
    "chars": 1985,
    "preview": "# Debug Adapter for Firefox\n\nThis package implements the [Debug Adapter Protocol](https://microsoft.github.io/debug-adap"
  },
  {
    "path": "dist/package.json",
    "chars": 632,
    "preview": "{\n  \"name\": \"firefox-debugadapter\",\n  \"version\": \"2.15.0\",\n  \"author\": \"Holger Benl <hbenl@evandor.de>\",\n  \"description\""
  },
  {
    "path": "dist/terminator/main.js",
    "chars": 122,
    "preview": "browser.windows.getAll().then((windows) => {\n\tfor (const window of windows) {\n\t\tbrowser.windows.remove(window.id);\n\t}\n})"
  },
  {
    "path": "dist/terminator/manifest.json",
    "chars": 374,
    "preview": "{\n\t\"description\": \"A WebExtension that terminates Firefox by closing all its windows\",\n\t\"manifest_version\": 2,\n\t\"name\": "
  },
  {
    "path": "package.json",
    "chars": 32988,
    "preview": "{\n  \"name\": \"vscode-firefox-debug\",\n  \"displayName\": \"Debugger for Firefox\",\n  \"version\": \"2.15.0\",\n  \"author\": \"Holger "
  },
  {
    "path": "src/README.md",
    "chars": 1461,
    "preview": "This folder contains the sources for the Debug Adapter for Firefox extension.\nThey are grouped into the following subfol"
  },
  {
    "path": "src/adapter/README.md",
    "chars": 832,
    "preview": "This folder contains the sources for the Firefox\n[debug adapter](https://code.visualstudio.com/api/extension-guides/debu"
  },
  {
    "path": "src/adapter/adapter/README.md",
    "chars": 468,
    "preview": "This folder contains classes that translate between the\n[Firefox Remote Debugging Protocol](https://github.com/mozilla/g"
  },
  {
    "path": "src/adapter/adapter/addonManager.ts",
    "chars": 2798,
    "preview": "import { Log } from '../util/log';\nimport * as path from 'path';\nimport { ParsedAddonConfiguration } from '../configurat"
  },
  {
    "path": "src/adapter/adapter/breakpoint.ts",
    "chars": 1086,
    "preview": "import { DebugProtocol } from '@vscode/debugprotocol';\nimport { MappedLocation } from '../location';\n\nexport class Break"
  },
  {
    "path": "src/adapter/adapter/breakpointsManager.ts",
    "chars": 7730,
    "preview": "import { Log } from '../util/log';\nimport { BreakpointInfo } from './breakpoint';\nimport { DebugProtocol } from '@vscode"
  },
  {
    "path": "src/adapter/adapter/consoleAPICall.ts",
    "chars": 1426,
    "preview": "import { VariablesProvider } from './variablesProvider';\nimport { VariableAdapter } from './variable';\nimport { ThreadAd"
  },
  {
    "path": "src/adapter/adapter/dataBreakpointsManager.ts",
    "chars": 2771,
    "preview": "import { Log } from '../util/log';\nimport { VariablesProvider } from './variablesProvider';\nimport { Registry } from './"
  },
  {
    "path": "src/adapter/adapter/descriptor.ts",
    "chars": 1628,
    "preview": "import { Registry } from './registry';\nimport { DescriptorActorProxy } from '../firefox/actorProxy/descriptor';\nimport {"
  },
  {
    "path": "src/adapter/adapter/environment.ts",
    "chars": 4814,
    "preview": "import { Log } from '../util/log';\nimport { ScopeAdapter, ObjectScopeAdapter, LocalVariablesScopeAdapter, FunctionScopeA"
  },
  {
    "path": "src/adapter/adapter/eventBreakpointsManager.ts",
    "chars": 1710,
    "preview": "import { AvailableEventCategory } from '../../common/customEvents';\nimport { FirefoxDebugSession } from '../firefoxDebug"
  },
  {
    "path": "src/adapter/adapter/frame.ts",
    "chars": 2299,
    "preview": "import { Log } from '../util/log';\nimport { ThreadAdapter } from './thread';\nimport { EnvironmentAdapter } from './envir"
  },
  {
    "path": "src/adapter/adapter/getterValue.ts",
    "chars": 2732,
    "preview": "import { VariablesProvider } from './variablesProvider';\nimport { ThreadAdapter } from './thread';\nimport { FrameAdapter"
  },
  {
    "path": "src/adapter/adapter/objectGrip.ts",
    "chars": 5593,
    "preview": "import { VariablesProvider } from './variablesProvider';\nimport { VariableAdapter } from './variable';\nimport { FrameAda"
  },
  {
    "path": "src/adapter/adapter/preview.ts",
    "chars": 5846,
    "preview": "import { Log } from '../util/log';\n\nconst log = Log.create('Preview');\n\nconst maxProperties = 5;\nconst maxArrayItems = 5"
  },
  {
    "path": "src/adapter/adapter/registry.ts",
    "chars": 1396,
    "preview": "import { EventEmitter } from 'events';\n\n/**\n * A generic collection of objects identified by a numerical ID.\n * The ID i"
  },
  {
    "path": "src/adapter/adapter/scope.ts",
    "chars": 4886,
    "preview": "import { ThreadAdapter } from './thread';\nimport { FrameAdapter } from './frame';\nimport { VariableAdapter } from './var"
  },
  {
    "path": "src/adapter/adapter/skipFilesManager.ts",
    "chars": 2418,
    "preview": "import isAbsoluteUrl from 'is-absolute-url';\nimport { Log } from '../util/log';\nimport { isWindowsPlatform as detectWind"
  },
  {
    "path": "src/adapter/adapter/source.ts",
    "chars": 4463,
    "preview": "import { Log } from '../util/log';\nimport { MappedLocation } from '../location';\nimport { DebugProtocol } from '@vscode/"
  },
  {
    "path": "src/adapter/adapter/sourcesManager.ts",
    "chars": 2979,
    "preview": "import { Log } from '../util/log';\nimport { ISourceActorProxy } from \"../firefox/actorProxy/source\";\nimport { DeferredMa"
  },
  {
    "path": "src/adapter/adapter/thread.ts",
    "chars": 7728,
    "preview": "import { EventEmitter } from 'events';\nimport { IThreadActorProxy } from '../firefox/actorProxy/thread';\nimport { Consol"
  },
  {
    "path": "src/adapter/adapter/variable.ts",
    "chars": 7440,
    "preview": "import { Log } from '../util/log';\nimport { ThreadAdapter } from './thread';\nimport { ObjectGripAdapter } from './object"
  },
  {
    "path": "src/adapter/adapter/variablesProvider.ts",
    "chars": 490,
    "preview": "import { ThreadAdapter } from './thread';\nimport { VariableAdapter } from './variable';\nimport { FrameAdapter } from './"
  },
  {
    "path": "src/adapter/configuration.ts",
    "chars": 18427,
    "preview": "import * as os from 'os';\nimport * as path from 'path';\nimport * as uuid from 'uuid';\nimport isAbsoluteUrl from 'is-abso"
  },
  {
    "path": "src/adapter/debugAdapterBase.ts",
    "chars": 9622,
    "preview": "import process from 'process';\nimport util from 'util';\nimport { DebugProtocol } from '@vscode/debugprotocol';\nimport { "
  },
  {
    "path": "src/adapter/firefox/README.md",
    "chars": 909,
    "preview": "This folder contains the code for launching and talking to Firefox.\n\nThe [`launchFirefox()`](./launch.ts) function launc"
  },
  {
    "path": "src/adapter/firefox/actorProxy/README.md",
    "chars": 338,
    "preview": "This folder contains proxy classes for the Firefox\n[actors](https://github.com/mozilla/gecko-dev/blob/master/devtools/do"
  },
  {
    "path": "src/adapter/firefox/actorProxy/addons.ts",
    "chars": 691,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/base.ts",
    "chars": 2221,
    "preview": "import { EventEmitter } from 'events';\nimport { DebugConnection } from '../connection';\nimport { ActorProxy } from './in"
  },
  {
    "path": "src/adapter/firefox/actorProxy/breakpointList.ts",
    "chars": 912,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/console.ts",
    "chars": 1612,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { exceptionGripToString } "
  },
  {
    "path": "src/adapter/firefox/actorProxy/descriptor.ts",
    "chars": 1537,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/device.ts",
    "chars": 617,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/frame.ts",
    "chars": 804,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/interface.ts",
    "chars": 519,
    "preview": "/**\n * An ActorProxy is a client-side reference to an actor on the server side of the \n * Mozilla Debugging Protocol as "
  },
  {
    "path": "src/adapter/firefox/actorProxy/longString.ts",
    "chars": 852,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/objectGrip.ts",
    "chars": 1500,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/preference.ts",
    "chars": 1668,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/root.ts",
    "chars": 4633,
    "preview": "import { Log } from '../../util/log';\nimport { DescriptorActorProxy } from './descriptor';\nimport { PreferenceActorProxy"
  },
  {
    "path": "src/adapter/firefox/actorProxy/source.ts",
    "chars": 2950,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { MappedLocation, Range } "
  },
  {
    "path": "src/adapter/firefox/actorProxy/target.ts",
    "chars": 2870,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/thread.ts",
    "chars": 2247,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/threadConfiguration.ts",
    "chars": 530,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/actorProxy/watcher.ts",
    "chars": 2857,
    "preview": "import { Log } from '../../util/log';\nimport { DebugConnection } from '../connection';\nimport { BaseActorProxy } from '."
  },
  {
    "path": "src/adapter/firefox/connection.ts",
    "chars": 2177,
    "preview": "import { Log } from '../util/log';\nimport { Socket } from 'net';\nimport { DebugProtocolTransport } from './transport';\ni"
  },
  {
    "path": "src/adapter/firefox/launch.ts",
    "chars": 4649,
    "preview": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { spawn, fork, ChildProcess } from 'child_process';"
  },
  {
    "path": "src/adapter/firefox/protocol.d.ts",
    "chars": 14713,
    "preview": "declare namespace FirefoxDebugProtocol {\n\n\tinterface Request {\n\t\tto: string;\n\t\ttype: string;\n\t}\n\n\tinterface Response {\n\t"
  },
  {
    "path": "src/adapter/firefox/sourceMaps/README.md",
    "chars": 1107,
    "preview": "This folder contains the debug adapter's source-map support.\n\nIt contains the [`SourceMappingSourceActorProxy`](./source"
  },
  {
    "path": "src/adapter/firefox/sourceMaps/info.ts",
    "chars": 5099,
    "preview": "import * as url from 'url';\nimport { Log } from '../../util/log';\nimport { isWindowsPlatform as detectWindowsPlatform } "
  },
  {
    "path": "src/adapter/firefox/sourceMaps/manager.ts",
    "chars": 7290,
    "preview": "import * as url from 'url';\nimport * as fs from 'fs-extra';\nimport isAbsoluteUrl from 'is-absolute-url';\nimport { Source"
  },
  {
    "path": "src/adapter/firefox/sourceMaps/source.ts",
    "chars": 5474,
    "preview": "import { Log } from '../../util/log';\nimport { ISourceActorProxy, SourceActorProxy } from '../actorProxy/source';\nimport"
  },
  {
    "path": "src/adapter/firefox/sourceMaps/thread.ts",
    "chars": 1452,
    "preview": "import { EventEmitter } from 'events';\nimport { Log } from '../../util/log';\nimport { DebugConnection } from '../connect"
  },
  {
    "path": "src/adapter/firefox/transport.ts",
    "chars": 3277,
    "preview": "import { Socket } from 'net';\nimport { Log } from '../util/log';\nimport { EventEmitter } from 'events';\n\nlet log = Log.c"
  },
  {
    "path": "src/adapter/firefoxDebugAdapter.ts",
    "chars": 16955,
    "preview": "import { URI } from 'vscode-uri';\nimport { DebugProtocol } from '@vscode/debugprotocol';\nimport { DebugSession, StoppedE"
  },
  {
    "path": "src/adapter/firefoxDebugSession.ts",
    "chars": 27600,
    "preview": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { Socket } from 'net';\nimport { ChildProcess } from"
  },
  {
    "path": "src/adapter/location.ts",
    "chars": 383,
    "preview": "export interface Location {\n\tline: number;\n\tcolumn?: number;\n}\n\nexport interface UrlLocation extends Location {\n\turl?: s"
  },
  {
    "path": "src/adapter/util/delayedTask.ts",
    "chars": 1051,
    "preview": "import { Log } from './log';\n\nlet log = Log.create('DelayedTask');\n\nexport class DelayedTask<T> {\n\n\tprivate state: 'wait"
  },
  {
    "path": "src/adapter/util/forkedLauncher.ts",
    "chars": 1306,
    "preview": "import { spawn, fork } from 'child_process';\nimport * as fs from 'fs-extra';\n\n/**\n * This script is used by the [launchF"
  },
  {
    "path": "src/adapter/util/fs.ts",
    "chars": 666,
    "preview": "import * as fs from 'fs-extra';\nimport { isWindowsPlatform as detectWindowsPlatform } from '../../common/util';\nimport {"
  },
  {
    "path": "src/adapter/util/log.ts",
    "chars": 3928,
    "preview": "import * as fs from 'fs-extra';\nimport { LogConfiguration, LogLevel } from '../../common/configuration';\n\nenum NumericLo"
  },
  {
    "path": "src/adapter/util/misc.ts",
    "chars": 3278,
    "preview": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport stripJsonComments from 'strip-json-comments';\nimpor"
  },
  {
    "path": "src/adapter/util/net.ts",
    "chars": 2797,
    "preview": "import * as url from 'url';\nimport * as fs from 'fs-extra';\nimport * as net from 'net';\nimport * as http from 'http';\nim"
  },
  {
    "path": "src/adapter/util/pathMapper.ts",
    "chars": 4033,
    "preview": "import * as path from 'path';\nimport * as url from 'url';\nimport isAbsoluteUrl from 'is-absolute-url';\nimport { Log } fr"
  },
  {
    "path": "src/adapter/util/pendingRequests.ts",
    "chars": 1161,
    "preview": "import { Log } from './log';\n\nlet log = Log.create('PendingRequests');\n\nexport interface PendingRequest<T> {\n\tresolve: ("
  },
  {
    "path": "src/common/configuration.ts",
    "chars": 2027,
    "preview": "import { DebugProtocol } from '@vscode/debugprotocol';\n\n/**\n * A launch configuration, as provided by VS Code\n */\nexport"
  },
  {
    "path": "src/common/customEvents.ts",
    "chars": 679,
    "preview": "export interface ThreadStartedEventBody {\n\tname: string;\n\tid: number;\n}\n\nexport interface ThreadExitedEventBody {\n\tid: n"
  },
  {
    "path": "src/common/deferredMap.ts",
    "chars": 977,
    "preview": "export class DeferredMap<S, T> {\n\tprivate readonly pending = new Map<S, (t: T) => void>();\n\tprivate readonly existing = "
  },
  {
    "path": "src/common/util.ts",
    "chars": 250,
    "preview": "import * as os from 'os';\n\nexport function delay(timeout: number): Promise<void> {\n\treturn new Promise<void>((resolve) ="
  },
  {
    "path": "src/extension/addPathMapping.ts",
    "chars": 4544,
    "preview": "import * as path from 'path';\nimport * as vscode from 'vscode';\nimport { TreeNode } from './loadedScripts/treeNode';\n\nin"
  },
  {
    "path": "src/extension/debugConfigurationProvider.ts",
    "chars": 6636,
    "preview": "import path from 'path';\nimport * as vscode from 'vscode';\nimport { LaunchConfiguration, AttachConfiguration } from '../"
  },
  {
    "path": "src/extension/eventBreakpointsProvider.ts",
    "chars": 3289,
    "preview": "import * as vscode from 'vscode';\nimport { AvailableEvent, AvailableEventCategory } from '../common/customEvents';\n\nexpo"
  },
  {
    "path": "src/extension/loadedScripts/fileNode.ts",
    "chars": 1037,
    "preview": "import * as vscode from 'vscode';\nimport { NewSourceEventBody } from '../../common/customEvents';\nimport { TreeNode } fr"
  },
  {
    "path": "src/extension/loadedScripts/nonLeafNode.ts",
    "chars": 4578,
    "preview": "import * as vscode from 'vscode';\nimport { NewSourceEventBody, ThreadStartedEventBody } from '../../common/customEvents'"
  },
  {
    "path": "src/extension/loadedScripts/provider.ts",
    "chars": 2312,
    "preview": "import * as vscode from 'vscode';\nimport { ThreadStartedEventBody, NewSourceEventBody } from '../../common/customEvents'"
  },
  {
    "path": "src/extension/loadedScripts/rootNode.ts",
    "chars": 2860,
    "preview": "import * as vscode from 'vscode';\nimport { ThreadStartedEventBody, NewSourceEventBody } from '../../common/customEvents'"
  },
  {
    "path": "src/extension/loadedScripts/sessionNode.ts",
    "chars": 3863,
    "preview": "import * as vscode from 'vscode';\nimport { TreeNode } from './treeNode';\nimport { RootNode } from './rootNode';\nimport {"
  },
  {
    "path": "src/extension/loadedScripts/treeNode.ts",
    "chars": 511,
    "preview": "import * as vscode from 'vscode';\n\nexport abstract class TreeNode {\n\n\tpublic readonly treeItem: vscode.TreeItem;\n\n\tpubli"
  },
  {
    "path": "src/extension/main.ts",
    "chars": 6253,
    "preview": "import * as vscode from 'vscode';\nimport isAbsoluteUrl from 'is-absolute-url';\nimport { LoadedScriptsProvider } from './"
  },
  {
    "path": "src/extension/pathMappingWizard.ts",
    "chars": 7747,
    "preview": "import path from 'path';\nimport vscode from 'vscode';\nimport { URL } from 'url';\nimport { LoadedScriptsProvider } from '"
  },
  {
    "path": "src/extension/popupAutohideManager.ts",
    "chars": 1195,
    "preview": "import * as vscode from 'vscode';\n\nexport class PopupAutohideManager {\n\n\tprivate button: vscode.StatusBarItem | undefine"
  },
  {
    "path": "src/test/setup.ts",
    "chars": 305,
    "preview": "import { config } from 'dotenv';\nimport fs from 'fs-extra';\n\nconfig({ path: 'src/test/.env'});\n\nexport const mochaHooks "
  },
  {
    "path": "src/test/sourceMapUtil.ts",
    "chars": 2665,
    "preview": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { Stream } from 'stream';\nimport * as assert from '"
  },
  {
    "path": "src/test/testAccessorProperties.ts",
    "chars": 4986,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport { DebugProtocol } from '@vscode/debugprotocol';\ni"
  },
  {
    "path": "src/test/testConfigurationParser.ts",
    "chars": 27729,
    "preview": "import * as os from 'os';\nimport { LaunchConfiguration, AttachConfiguration } from '../common/configuration';\nimport { p"
  },
  {
    "path": "src/test/testConsole.ts",
    "chars": 6682,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport { DebugProtocol } from '@vscode/debugprotocol';\ni"
  },
  {
    "path": "src/test/testDataBreakpoints.ts",
    "chars": 3899,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport * as path from 'path';\nimport * as assert from 'a"
  },
  {
    "path": "src/test/testDebugAddons.ts",
    "chars": 2355,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport { DebugProtocol } from '@vscode/debugprotocol';\ni"
  },
  {
    "path": "src/test/testDebugWebWorkers.ts",
    "chars": 2180,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport * as path from 'path';\nimport * as util from './u"
  },
  {
    "path": "src/test/testEvaluate.ts",
    "chars": 9653,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport * as path from 'path';\nimport * as util from './u"
  },
  {
    "path": "src/test/testGulpSourceMaps.ts",
    "chars": 3779,
    "preview": "import * as os from 'os';\nimport * as fs from 'fs-extra';\nimport * as path from 'path';\nimport * as uuid from 'uuid';\nim"
  },
  {
    "path": "src/test/testHitBreakpoints.ts",
    "chars": 7831,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport * as path from 'path';\nimport * as util from './u"
  },
  {
    "path": "src/test/testInspectVariables.ts",
    "chars": 8669,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport * as path from 'path';\nimport * as util from './u"
  },
  {
    "path": "src/test/testSetBreakpoints.ts",
    "chars": 9428,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport * as path from 'path';\nimport * as util from './u"
  },
  {
    "path": "src/test/testSkipFiles.ts",
    "chars": 7424,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport { DebugProtocol } from '@vscode/debugprotocol';\ni"
  },
  {
    "path": "src/test/testSourceActorCollection.ts",
    "chars": 3428,
    "preview": "import assert from 'assert';\nimport { SourceActorCollection } from '../adapter/adapter/source';\nimport { ISourceActorPro"
  },
  {
    "path": "src/test/testStepThrough.ts",
    "chars": 5107,
    "preview": "import { DebugClient } from '@vscode/debugadapter-testsupport';\nimport * as path from 'path';\nimport * as util from './u"
  },
  {
    "path": "src/test/testTerminateAndCleanup.ts",
    "chars": 2543,
    "preview": "import * as os from 'os';\nimport * as path from 'path';\nimport * as fs from 'fs-extra';\nimport * as assert from 'assert'"
  },
  {
    "path": "src/test/testWebpackSourceMaps.ts",
    "chars": 3057,
    "preview": "import * as os from 'os';\nimport * as fs from 'fs-extra';\nimport * as path from 'path';\nimport * as uuid from 'uuid';\nim"
  },
  {
    "path": "src/test/util.ts",
    "chars": 7973,
    "preview": "import { delay, isWindowsPlatform } from '../common/util';\nimport { DebugClient } from '@vscode/debugadapter-testsupport"
  },
  {
    "path": "src/typings/gulp-nop.d.ts",
    "chars": 105,
    "preview": "declare module \"gulp-nop\" {\n\tfunction nop(): NodeJS.ReadWriteStream;\n\tnamespace nop {}\n\texport = nop;\n}\n\t"
  },
  {
    "path": "src/typings/map-sources.d.ts",
    "chars": 193,
    "preview": "declare module \"@gulp-sourcemaps/map-sources\" {\n\tfunction mapSources(mapFn: (sourcePath: string, file: any) => string): "
  },
  {
    "path": "testdata/web/debuggerStatement.js",
    "chars": 55,
    "preview": "debugger;\n\nfunction debuggerStatement() {\n\tdebugger;\n}\n"
  },
  {
    "path": "testdata/web/dlscript.js",
    "chars": 47,
    "preview": "function dynTest() {\n\n\tconsole.log(\"Test\");\n\n}\n"
  },
  {
    "path": "testdata/web/exception-sourcemap.js",
    "chars": 104,
    "preview": "try {\n    throw new Error();\n}\ncatch (e) {\n    noop();\n}\n//# sourceMappingURL=exception-sourcemap.js.map"
  },
  {
    "path": "testdata/web/exception-sourcemap.ts",
    "chars": 80,
    "preview": "declare function noop(): any;\ntry {\n\tthrow new Error();\n} catch(e) {\n\tnoop();\n}\n"
  },
  {
    "path": "testdata/web/exception.js",
    "chars": 50,
    "preview": "try {\n\tthrow new Error();\n} catch(e) {\n\tnoop();\n}\n"
  },
  {
    "path": "testdata/web/index.html",
    "chars": 246,
    "preview": "<html>\n\t<head>\n\t\t<meta charset=\"UTF-8\"/>\n\t\t<script>\n\t\t\twindow.onload = function() {\n\t\t\t\tconsole.log('Loaded');\n\t\t\t}\n\t\t</"
  },
  {
    "path": "testdata/web/main.js",
    "chars": 2024,
    "preview": "function noop() {\n\n\tlet dummy = 0;\n\n}\n\nfunction vars(arg) {\n\tlet bool1 = false;\n\tlet bool2 = true;\n\tlet num1 = 0;\n\tlet n"
  },
  {
    "path": "testdata/web/skip.js",
    "chars": 87,
    "preview": "function dummyFunc() {\n\tlet dummy = 0;\n}\nfunction throwError() {\n\tthrow new Error();\n}\n"
  },
  {
    "path": "testdata/web/sourceMaps/modules/f.js",
    "chars": 108,
    "preview": "import { g } from './g';\n\n// Test\nfunction f() {\n\tvar x = 1;\n\tx = 2;\n\tx = g(x);\n\tx = g(x);\n}\n\nwindow.f = f;\n"
  },
  {
    "path": "testdata/web/sourceMaps/modules/g.js",
    "chars": 56,
    "preview": "/**\n * Test\n */\nexport function g(y) {\n\treturn y * y;\n}\n"
  },
  {
    "path": "testdata/web/sourceMaps/modules/index.html",
    "chars": 225,
    "preview": "<html>\n\t<head>\n\t\t<meta charset=\"UTF-8\"/>\n\t\t<script>\n\t\t\twindow.onload = function() {\n\t\t\t\tconsole.log('Loaded');\n\t\t\t}\n\t\t</"
  },
  {
    "path": "testdata/web/sourceMaps/scripts/f.js",
    "chars": 75,
    "preview": "/**\n * Test\n */\nfunction f() {\n\tvar x = 1;\n\tx = 2;\n\tx = g(x);\n\tx = g(x);\n}\n"
  },
  {
    "path": "testdata/web/sourceMaps/scripts/g.js",
    "chars": 49,
    "preview": "/**\n * Test\n */\nfunction g(y) {\n\treturn y * y;\n}\n"
  },
  {
    "path": "testdata/web/sourceMaps/scripts/index.html",
    "chars": 203,
    "preview": "<html>\n\t<head>\n\t\t<meta charset=\"UTF-8\"/>\n\t\t<script>\n\t\t\twindow.onload = function() {\n\t\t\t\tconsole.log('Loaded');\n\t\t\t}\n\t\t</"
  },
  {
    "path": "testdata/web/tsconfig.json",
    "chars": 115,
    "preview": "{\n    \"compilerOptions\": {\n        \"sourceMap\": true\n    },\n    \"files\": [\n        \"exception-sourcemap.ts\"\n    ]\n}"
  },
  {
    "path": "testdata/web/worker.js",
    "chars": 54,
    "preview": "onmessage = function(e) {\n\tpostMessage(e.data.foo);\n}\n"
  },
  {
    "path": "testdata/webExtension/addOn/backgroundscript.js",
    "chars": 85,
    "preview": "chrome.runtime.onMessage.addListener((msg) => {\n\tconsole.log('foo: ' + msg.foo);\n});\n"
  },
  {
    "path": "testdata/webExtension/addOn/contentscript.js",
    "chars": 235,
    "preview": "let messageBox = document.getElementById('messageBox');\nsetInterval(() => {\n\tlet message = messageBox.textContent;\n\tif ("
  },
  {
    "path": "testdata/webExtension/addOn/manifest.json",
    "chars": 461,
    "preview": "{\n\n\t\"description\": \"A WebExtension used for testing vscode-firefox-debug\",\n\t\"manifest_version\": 2,\n\t\"name\": \"Test\",\n\t\"ve"
  },
  {
    "path": "testdata/webExtension/index.html",
    "chars": 347,
    "preview": "<html>\n\t<head>\n\t\t<meta charset=\"UTF-8\"/>\n\t\t<script>\n\t\t\twindow.onload = function() {\n\t\t\t\tconsole.log('Loaded');\n\t\t\t}\n\t\t\tf"
  },
  {
    "path": "testdata/webExtension2/addOn/backgroundscript.js",
    "chars": 85,
    "preview": "chrome.runtime.onMessage.addListener((msg) => {\n\tconsole.log('foo: ' + msg.foo);\n});\n"
  },
  {
    "path": "testdata/webExtension2/addOn/contentscript.js",
    "chars": 235,
    "preview": "let messageBox = document.getElementById('messageBox');\nsetInterval(() => {\n\tlet message = messageBox.textContent;\n\tif ("
  },
  {
    "path": "testdata/webExtension2/addOn/manifest.json",
    "chars": 371,
    "preview": "{\n\n\t\"description\": \"A WebExtension used for testing vscode-firefox-debug\",\n\t\"manifest_version\": 2,\n\t\"name\": \"Test\",\n\t\"ve"
  },
  {
    "path": "testdata/webExtension2/index.html",
    "chars": 347,
    "preview": "<html>\n\t<head>\n\t\t<meta charset=\"UTF-8\"/>\n\t\t<script>\n\t\t\twindow.onload = function() {\n\t\t\t\tconsole.log('Loaded');\n\t\t\t}\n\t\t\tf"
  },
  {
    "path": "tsconfig.json",
    "chars": 449,
    "preview": "{\n\t\"compilerOptions\": {\n\t\t\"target\": \"es2015\",\n\t\t\"lib\": [ \"es2015\" ],\n\t\t\"module\": \"commonjs\",\n\t\t\"noEmit\": true,\n\t\t\"strict"
  },
  {
    "path": "webpack.config.js",
    "chars": 923,
    "preview": "const path = require('path');\nconst CopyPlugin = require('copy-webpack-plugin');\n\nmodule.exports = {\n\tcontext: path.reso"
  }
]

About this extraction

This page contains the full source code of the firefox-devtools/vscode-firefox-debug GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 144 files (485.7 KB), approximately 120.7k tokens, and a symbol index with 824 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!