From 53920c0a6a87156eaef10e0abcd023614f862ab9 Mon Sep 17 00:00:00 2001 From: D Date: Wed, 9 Jan 2019 20:36:09 -0800 Subject: [PATCH 01/23] Initial bulk of the work to refactor/rewrite the crdp debug adapters to the V2 architecture --- .vscode/launch.json | 38 +- .vscode/settings.json | 9 +- build.cmd | 2 + filesWithIssues.cmd | 2 + package-lock.json | 1179 +++----- package.json | 16 +- src/chrome/breakOnLoadHelper.ts | 148 +- src/chrome/chromeConnection.ts | 32 +- src/chrome/chromeDebugAdapter.ts | 2501 +++-------------- src/chrome/chromeDebugSession.ts | 76 +- src/chrome/chromeUtils.ts | 12 +- .../chromeDebugAdapter/cdaConfiguration.ts | 42 + .../client/chromeDebugAdapter/cdaState.ts | 111 + .../chromeDebugAdapterV2.ts | 126 + .../client/chromeDebugAdapter/connectedCDA.ts | 223 ++ .../chromeDebugAdapter/connectedCDAEvents.ts | 49 + .../chromeDebugAdapter/unconnectedCDA.ts | 128 + .../unconnectedCDACommonLogic.ts | 111 + .../chromeDebugAdapter/uninitializedCDA.ts | 68 + src/chrome/client/clientToInternal.ts | 103 + .../delayMessagesUntilInitializedSession.ts | 22 + .../client/doNotPauseWhileSteppingSession.ts | 50 + src/chrome/client/eventSender.ts | 96 + src/chrome/client/handlesRegistry.ts | 48 + src/chrome/client/internalToClient.ts | 131 + src/chrome/client/requests.ts | 2 + src/chrome/client/session.ts | 52 + src/chrome/collections/printting.ts | 24 + src/chrome/collections/validatedMap.ts | 2 +- src/chrome/communication/channel.ts | 25 + src/chrome/communication/channelIdentifier.ts | 3 + .../communication/collaborativeDecision.ts | 83 + src/chrome/communication/communicator.ts | 67 + src/chrome/communication/internalChannels.ts | 24 + src/chrome/communication/listeners.ts | 17 + .../notificationsCommunicator.ts | 76 + .../communication/requestsCommunicator.ts | 93 + src/chrome/communication/targetChannels.ts | 23 + .../transformedListenerRegistry.ts | 24 + src/chrome/consoleHelper.ts | 17 +- .../crdpMultiplexing/crdpMultiplexor.ts | 218 -- .../webSocketToLikeSocketProxy.ts | 4 +- src/chrome/debugee/debugeeLauncher.ts | 16 + src/chrome/dependencyInjection.ts/bind.ts | 92 + src/chrome/dependencyInjection.ts/di.ts | 38 + src/chrome/dependencyInjection.ts/types.ts | 56 +- .../extensibility/extensibilityPoints.ts | 44 + .../internal/breakpoints/bpActionWhenHit.ts | 125 + src/chrome/internal/breakpoints/bpRecipie.ts | 125 + .../bpRecipieInLoadedSourceLogic.ts | 112 + .../internal/breakpoints/bpRecipieStatus.ts | 63 + src/chrome/internal/breakpoints/bpRecipies.ts | 41 + .../breakpoints/bpsDeltaCalculator.ts | 125 + src/chrome/internal/breakpoints/breakpoint.ts | 36 + .../internal/breakpoints/breakpointsLogic.ts | 112 + .../breakpoints/breakpointsRegistry.ts | 48 + .../clientCurrentBPRecipiesRegistry.ts | 28 + .../features/hitCountBreakpoints.ts | 81 + .../features/pauseScriptLoadsToSetBPs.ts | 129 + .../features/reAddBPsWhenSourceIsLoaded.ts | 93 + .../breakpoints/hitCountConditionParser.ts | 41 + .../breakpoints/targetDuplicatedBPsLogic.ts | 37 + .../internal/domains/supportedDomains.ts | 36 + .../internal/exceptions/pauseOnException.ts | 118 + src/chrome/internal/exceptions/strategies.ts | 23 + src/chrome/internal/features/feature.ts | 27 +- src/chrome/internal/features/skipFiles.ts | 285 ++ src/chrome/internal/features/smartStep.ts | 122 + .../features/takeProperActionOnPausedEvent.ts | 91 + .../internal/formattedExceptionParser.ts | 69 + src/chrome/internal/locations/location.ts | 157 ++ .../internal/locations/rangeInScript.ts | 23 + src/chrome/internal/locations/subtypes.ts | 15 + src/chrome/internal/requests.ts | 20 + src/chrome/internal/scripts/script.ts | 6 +- .../internal/scripts/scriptsRegistry.ts | 94 + src/chrome/internal/scripts/sourcesMapper.ts | 6 +- src/chrome/internal/services/logging.ts | 28 + .../sources/features/dotScriptsCommand.ts | 68 + .../features/notifyClientOfLoadedSources.ts | 76 + src/chrome/internal/sources/sourceResolver.ts | 2 +- src/chrome/internal/sources/sourcesLogic.ts | 60 + .../internal/sources/sourcesTextLogic.ts | 33 + .../internal/sources/sourcesTreeNodeLogic.ts | 44 + .../internal/sources/unresolvedSource.ts | 51 + src/chrome/internal/stackTraces/callFrame.ts | 115 + .../internal/stackTraces/callFrameName.ts | 31 + .../stackTraces/callFramePresentation.ts | 86 + src/chrome/internal/stackTraces/scopes.ts | 11 + src/chrome/internal/stackTraces/stackTrace.ts | 8 + .../stackTraces/stackTracePresentation.ts | 27 + .../internal/stackTraces/stackTracesLogic.ts | 164 ++ .../stepping/features/asyncStepping.ts | 40 + .../stepping/features/syncStepping.ts | 77 + src/chrome/internal/stepping/stepping.ts | 44 + src/chrome/internalSourceBreakpoint.ts | 14 +- src/chrome/logging/executionLogger.ts | 43 + src/chrome/logging/methodsCalledLogger.ts | 70 + src/chrome/target/addSourceUriToExpression.ts | 15 + .../target/breakpointFeaturesSupport.ts | 34 + src/chrome/target/breakpointIdRegistry.ts | 31 + src/chrome/target/callFrameRegistry.ts | 14 + src/chrome/target/cdtpDebugger.ts | 65 + .../target/cdtpDebuggerEventsProvider.ts | 77 + src/chrome/target/cdtpDiagnostics.ts | 57 + src/chrome/target/cdtpDiagnosticsModule.ts | 34 + src/chrome/target/cdtpLocationParser.ts | 32 + .../target/cdtpOnScriptParsedEventProvider.ts | 85 + src/chrome/target/cdtpRuntime.ts | 32 + src/chrome/target/cdtpScriptsRegistry.ts | 103 + src/chrome/target/cdtpSmallerModules.ts | 138 + src/chrome/target/cdtpStackTraceParser.ts | 36 + src/chrome/target/cdtpTargetBreakpoints.ts | 137 + src/chrome/target/controlDebugeeExecution.ts | 57 + src/chrome/target/events.ts | 77 + .../target/exceptionThrownEventProvider.ts | 44 + .../target/executionContextEventsProvider.ts | 24 + src/chrome/target/inspectDebugeeState.ts | 50 + src/chrome/target/requests.ts | 25 + src/chrome/target/updateDebugeeState.ts | 26 + src/chrome/utils/combine.ts | 27 + src/chrome/utils/failures.ts | 17 + src/chrome/utils/localization.ts | 18 + .../utils/namespaceReverseLookupCreator.ts | 27 + src/chrome/utils/promises.ts | 1 + src/chrome/variables.ts | 35 +- src/debugAdapterInterfaces.d.ts | 54 +- src/index.ts | 55 +- src/nullLogger.ts | 8 +- src/sourceMaps/sourceMap.ts | 6 +- src/sourceMaps/sourceMapFactory.ts | 4 +- src/sourceMaps/sourceMaps.ts | 5 +- src/telemetry.ts | 14 +- src/transformers/basePathTransformer.ts | 31 +- src/transformers/baseSourceMapTransformer.ts | 200 +- src/transformers/eagerSourceMapTransformer.ts | 8 +- .../fallbackToClientPathTransformer.ts | 18 +- src/transformers/lineNumberTransformer.ts | 40 +- src/transformers/remotePathTransformer.ts | 51 +- src/transformers/urlPathTransformer.ts | 86 +- src/typeUtils.ts | 27 + src/utils.ts | 30 +- src/validation.ts | 14 + test/chrome/chromeDebugAdapter.test.ts | 2 +- test/testDebug/testDebug.ts | 40 + test/testDebug/testDebugAdapter.ts | 4 + test/testDebug/testDebugeeLauncher.ts | 12 + test/testDebug/testDebugeeRunner.ts | 10 + tsconfig.json | 25 +- 149 files changed, 8091 insertions(+), 3674 deletions(-) create mode 100644 build.cmd create mode 100644 filesWithIssues.cmd create mode 100644 src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts create mode 100644 src/chrome/client/chromeDebugAdapter/cdaState.ts create mode 100644 src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts create mode 100644 src/chrome/client/chromeDebugAdapter/connectedCDA.ts create mode 100644 src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts create mode 100644 src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts create mode 100644 src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts create mode 100644 src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts create mode 100644 src/chrome/client/clientToInternal.ts create mode 100644 src/chrome/client/delayMessagesUntilInitializedSession.ts create mode 100644 src/chrome/client/doNotPauseWhileSteppingSession.ts create mode 100644 src/chrome/client/eventSender.ts create mode 100644 src/chrome/client/handlesRegistry.ts create mode 100644 src/chrome/client/internalToClient.ts create mode 100644 src/chrome/client/requests.ts create mode 100644 src/chrome/client/session.ts create mode 100644 src/chrome/collections/printting.ts create mode 100644 src/chrome/communication/channel.ts create mode 100644 src/chrome/communication/channelIdentifier.ts create mode 100644 src/chrome/communication/collaborativeDecision.ts create mode 100644 src/chrome/communication/communicator.ts create mode 100644 src/chrome/communication/internalChannels.ts create mode 100644 src/chrome/communication/listeners.ts create mode 100644 src/chrome/communication/notificationsCommunicator.ts create mode 100644 src/chrome/communication/requestsCommunicator.ts create mode 100644 src/chrome/communication/targetChannels.ts create mode 100644 src/chrome/communication/transformedListenerRegistry.ts delete mode 100644 src/chrome/crdpMultiplexing/crdpMultiplexor.ts create mode 100644 src/chrome/debugee/debugeeLauncher.ts create mode 100644 src/chrome/dependencyInjection.ts/bind.ts create mode 100644 src/chrome/dependencyInjection.ts/di.ts create mode 100644 src/chrome/extensibility/extensibilityPoints.ts create mode 100644 src/chrome/internal/breakpoints/bpActionWhenHit.ts create mode 100644 src/chrome/internal/breakpoints/bpRecipie.ts create mode 100644 src/chrome/internal/breakpoints/bpRecipieInLoadedSourceLogic.ts create mode 100644 src/chrome/internal/breakpoints/bpRecipieStatus.ts create mode 100644 src/chrome/internal/breakpoints/bpRecipies.ts create mode 100644 src/chrome/internal/breakpoints/bpsDeltaCalculator.ts create mode 100644 src/chrome/internal/breakpoints/breakpoint.ts create mode 100644 src/chrome/internal/breakpoints/breakpointsLogic.ts create mode 100644 src/chrome/internal/breakpoints/breakpointsRegistry.ts create mode 100644 src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts create mode 100644 src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts create mode 100644 src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts create mode 100644 src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts create mode 100644 src/chrome/internal/breakpoints/hitCountConditionParser.ts create mode 100644 src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts create mode 100644 src/chrome/internal/domains/supportedDomains.ts create mode 100644 src/chrome/internal/exceptions/pauseOnException.ts create mode 100644 src/chrome/internal/exceptions/strategies.ts create mode 100644 src/chrome/internal/features/skipFiles.ts create mode 100644 src/chrome/internal/features/smartStep.ts create mode 100644 src/chrome/internal/features/takeProperActionOnPausedEvent.ts create mode 100644 src/chrome/internal/formattedExceptionParser.ts create mode 100644 src/chrome/internal/locations/location.ts create mode 100644 src/chrome/internal/locations/rangeInScript.ts create mode 100644 src/chrome/internal/requests.ts create mode 100644 src/chrome/internal/scripts/scriptsRegistry.ts create mode 100644 src/chrome/internal/services/logging.ts create mode 100644 src/chrome/internal/sources/features/dotScriptsCommand.ts create mode 100644 src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts create mode 100644 src/chrome/internal/sources/sourcesLogic.ts create mode 100644 src/chrome/internal/sources/sourcesTextLogic.ts create mode 100644 src/chrome/internal/sources/sourcesTreeNodeLogic.ts create mode 100644 src/chrome/internal/sources/unresolvedSource.ts create mode 100644 src/chrome/internal/stackTraces/callFrame.ts create mode 100644 src/chrome/internal/stackTraces/callFrameName.ts create mode 100644 src/chrome/internal/stackTraces/callFramePresentation.ts create mode 100644 src/chrome/internal/stackTraces/scopes.ts create mode 100644 src/chrome/internal/stackTraces/stackTrace.ts create mode 100644 src/chrome/internal/stackTraces/stackTracePresentation.ts create mode 100644 src/chrome/internal/stackTraces/stackTracesLogic.ts create mode 100644 src/chrome/internal/stepping/features/asyncStepping.ts create mode 100644 src/chrome/internal/stepping/features/syncStepping.ts create mode 100644 src/chrome/internal/stepping/stepping.ts create mode 100644 src/chrome/logging/executionLogger.ts create mode 100644 src/chrome/logging/methodsCalledLogger.ts create mode 100644 src/chrome/target/addSourceUriToExpression.ts create mode 100644 src/chrome/target/breakpointFeaturesSupport.ts create mode 100644 src/chrome/target/breakpointIdRegistry.ts create mode 100644 src/chrome/target/callFrameRegistry.ts create mode 100644 src/chrome/target/cdtpDebugger.ts create mode 100644 src/chrome/target/cdtpDebuggerEventsProvider.ts create mode 100644 src/chrome/target/cdtpDiagnostics.ts create mode 100644 src/chrome/target/cdtpDiagnosticsModule.ts create mode 100644 src/chrome/target/cdtpLocationParser.ts create mode 100644 src/chrome/target/cdtpOnScriptParsedEventProvider.ts create mode 100644 src/chrome/target/cdtpRuntime.ts create mode 100644 src/chrome/target/cdtpScriptsRegistry.ts create mode 100644 src/chrome/target/cdtpSmallerModules.ts create mode 100644 src/chrome/target/cdtpStackTraceParser.ts create mode 100644 src/chrome/target/cdtpTargetBreakpoints.ts create mode 100644 src/chrome/target/controlDebugeeExecution.ts create mode 100644 src/chrome/target/exceptionThrownEventProvider.ts create mode 100644 src/chrome/target/executionContextEventsProvider.ts create mode 100644 src/chrome/target/inspectDebugeeState.ts create mode 100644 src/chrome/target/requests.ts create mode 100644 src/chrome/target/updateDebugeeState.ts create mode 100644 src/chrome/utils/combine.ts create mode 100644 src/chrome/utils/failures.ts create mode 100644 src/chrome/utils/localization.ts create mode 100644 src/chrome/utils/namespaceReverseLookupCreator.ts create mode 100644 src/chrome/utils/promises.ts create mode 100644 src/typeUtils.ts create mode 100644 src/validation.ts create mode 100644 test/testDebug/testDebug.ts create mode 100644 test/testDebug/testDebugAdapter.ts create mode 100644 test/testDebug/testDebugeeLauncher.ts create mode 100644 test/testDebug/testDebugeeRunner.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 40155a4e9..a12522625 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -45,7 +45,7 @@ "cwd": "${workspaceFolder}/../vscode-node-debug2", "program": "${workspaceFolder}/../vscode-node-debug2/out/src/nodeDebug.js", "args": [ "--server=4712" ], - "outFiles": ["${workspaceFolder}/out/**/*.js"], + "outFiles": ["${workspaceFolder}/out/**/*.js", "${workspaceFolder}/../vscode-node-debug2/out/**/*.js"], "internalConsoleOptions": "openOnSessionStart", "smartStep": true, "skipFiles": [ @@ -60,9 +60,41 @@ // These paths are only valid for my particular setup! You need to replace them with your own. "cwd": "${workspaceFolder}/../vscode-chrome-debug", - "program": "${workspaceFolder}/../vscode-chrome-debug/out/src/chromeDebug.js", + "program": "${workspaceFolder}/../vscode-chrome-debug/out/chromeDebug.js", "args": [ "--server=4712" ], - "outFiles": ["${workspaceFolder}/out/**/*.js"], + "outFiles": ["${workspaceFolder}/out/**/*.js", "${workspaceFolder}/../vscode-chrome-debug/out/**/*.js"], + "internalConsoleOptions": "openOnSessionStart", + "smartStep": true, + "env": { + "BREAK_WHILE_DEBUGGING": "true" + } + }, + { + "name": "launch chrome-debug (No sourcemaps)", + "type": "node", + "request": "launch", + "protocol": "inspector", + + // These paths are only valid for my particular setup! You need to replace them with your own. + "cwd": "${workspaceFolder}/../vscode-chrome-debug", + "program": "${workspaceFolder}/../vscode-chrome-debug/out/chromeDebug.js", + "args": [ "--server=4712" ], + "outFiles": ["${workspaceFolder}/out/**/*.js", "${workspaceFolder}/../vscode-chrome-debug/out/**/*.js"], + "internalConsoleOptions": "openOnSessionStart", + "smartStep": true, + "sourceMaps": false + }, + { + "name": "launch test-debug", + "type": "node", + "request": "launch", + "protocol": "inspector", + + // These paths are only valid for my particular setup! You need to replace them with your own. + "cwd": "${workspaceFolder}", + "program": "${workspaceFolder}/out/test/testDebug/testDebug.js", + "args": [ "--server=4712" ], + "outFiles": ["${workspaceFolder}/out/**/*.js", "${workspaceFolder}/../vscode-chrome-debug/out/**/*.js"], "internalConsoleOptions": "openOnSessionStart", "smartStep": true }, diff --git a/.vscode/settings.json b/.vscode/settings.json index 31d032942..f4d0f339a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,8 +4,13 @@ "files.exclude": { ".git": true, "bin": true, - "node_modules": false, - "ThirdPartyNotices.txt": true + "node_modules": true, + "out": true, + "lib": true, + "i18n": true, + ".github": true, + ".vsts": true, + "ThirdPartyNotices.txt": true, }, "search.exclude": { ".git": true, diff --git a/build.cmd b/build.cmd new file mode 100644 index 000000000..17de6500a --- /dev/null +++ b/build.cmd @@ -0,0 +1,2 @@ +@gulp _dev-build +@color diff --git a/filesWithIssues.cmd b/filesWithIssues.cmd new file mode 100644 index 000000000..632bc5100 --- /dev/null +++ b/filesWithIssues.cmd @@ -0,0 +1,2 @@ +@echo off +cls && npm run build | sed -e 's/ .*//g' | grep ^src | sed -e 's/(.*//g' | uniq | sed -e 's/src/code -g src/g' diff --git a/package-lock.json b/package-lock.json index 5dd85f4de..50ccc2f13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "vscode-chrome-debug-core", - "version": "6.7.35", + "version": "10.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -154,6 +154,21 @@ "@types/node": "*" } }, + "@types/inversify-inject-decorators": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/inversify-inject-decorators/-/inversify-inject-decorators-2.0.0.tgz", + "integrity": "sha1-mlC5tHOluL1RpkV1QNEt293N8l4=", + "dev": true, + "requires": { + "inversify-inject-decorators": "*" + } + }, + "@types/lodash": { + "version": "4.14.116", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.116.tgz", + "integrity": "sha512-lRnAtKnxMXcYYXqOiotTmJd74uawNWuPnsnPrrO7HiFuE3npE2iQhfABatbYDyxTNqZNuXzcKGhw37R7RjBFLg==", + "dev": true + }, "@types/minimatch": { "version": "2.0.29", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-2.0.29.tgz", @@ -178,6 +193,12 @@ "integrity": "sha512-V746iUU7eHNdzQipoACuguDlVhC7IHK8CES1jSkuFt352wwA84BCWPXaGekBd7R5XdNK5ReHONDVKxlL9IreAw==", "dev": true }, + "@types/semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==", + "dev": true + }, "@types/source-map": { "version": "0.1.29", "resolved": "https://registry.npmjs.org/@types/source-map/-/source-map-0.1.29.tgz", @@ -410,6 +431,35 @@ "requires": { "is-descriptor": "^1.0.0" } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } } } }, @@ -420,26 +470,25 @@ "dev": true }, "brace-expansion": { - "version": "1.1.8", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "braces": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz", - "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", - "define-property": "^1.0.0", "extend-shallow": "^2.0.1", "fill-range": "^4.0.0", "isobject": "^3.0.1", - "kind-of": "^6.0.2", "repeat-element": "^1.1.2", "snapdragon": "^0.8.1", "snapdragon-node": "^2.0.1", @@ -447,21 +496,6 @@ "to-regex": "^3.0.1" }, "dependencies": { - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", @@ -582,69 +616,6 @@ "requires": { "is-descriptor": "^0.1.0" } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true } } }, @@ -743,9 +714,9 @@ } }, "color": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.0.tgz", + "integrity": "sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==", "requires": { "color-convert": "^1.9.1", "color-string": "^1.5.2" @@ -803,9 +774,13 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "convert-source-map": { - "version": "1.5.0", - "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", - "dev": true + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } }, "copy-descriptor": { "version": "0.1.1", @@ -938,6 +913,37 @@ "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } } }, "del": { @@ -979,8 +985,9 @@ "integrity": "sha512-DDGCT3YFiamX4jRPqg4galOrQS8DsU0j+xM5iaR0YB5TM1fjCZejQ7MSe9ByIMIq4IsnULY/4Qp3TBWAUjMgXw==" }, "diff": { - "version": "3.2.0", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, "doctrine": { @@ -1084,12 +1091,6 @@ "requires": { "wrappy": "1" } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true } } }, @@ -1181,69 +1182,6 @@ "requires": { "is-extendable": "^0.1.0" } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true } } }, @@ -1312,6 +1250,35 @@ "requires": { "is-extendable": "^0.1.0" } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } } } }, @@ -1395,17 +1362,6 @@ "object.defaults": "^1.1.0", "object.pick": "^1.2.0", "parse-filepath": "^1.0.1" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } } }, "first-chunk-stream": { @@ -1587,34 +1543,6 @@ "unique-stream": "^1.0.0" }, "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, "glob": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", @@ -1627,12 +1555,6 @@ "once": "^1.3.0" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "minimatch": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", @@ -1642,15 +1564,6 @@ "brace-expansion": "^1.0.0" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", @@ -1672,18 +1585,6 @@ "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true } } }, @@ -1777,6 +1678,12 @@ "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", "dev": true }, + "lodash": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", + "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", + "dev": true + }, "minimatch": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", @@ -1834,59 +1741,10 @@ "vinyl-fs": "^0.3.0" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", "dev": true } } @@ -2482,6 +2340,14 @@ "remove-trailing-separator": "^1.0.1", "to-absolute-glob": "^2.0.0", "unique-stream": "^2.0.2" + }, + "dependencies": { + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + } } }, "graceful-fs": { @@ -2578,6 +2444,14 @@ "cloneable-readable": "^1.0.0", "remove-trailing-separator": "^1.0.1", "replace-ext": "^1.0.0" + }, + "dependencies": { + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + } } }, "vinyl-fs": { @@ -2840,12 +2714,6 @@ "kind-of": "^4.0.0" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", @@ -2853,6 +2721,14 @@ "dev": true, "requires": { "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } } } } @@ -2922,6 +2798,16 @@ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", "dev": true }, + "inversify": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz", + "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==" + }, + "inversify-inject-decorators": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/inversify-inject-decorators/-/inversify-inject-decorators-3.1.0.tgz", + "integrity": "sha512-/seBlVp5bXrLQS3DpKEmlgeZL6C7Tf/QITd+IMQrbBBGuCbxb7k3hRAWu9XSreNpFzLgSboz3sClLSEmGwHphw==" + }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", @@ -2951,12 +2837,31 @@ } }, "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } + } + } } }, "is-arrayish": { @@ -2965,28 +2870,56 @@ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, "is-buffer": { - "version": "1.1.5", - "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } + } + } } }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } } }, "is-extendable": { @@ -3031,12 +2964,6 @@ "kind-of": "^3.0.2" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -3044,27 +2971,18 @@ "dev": true, "requires": { "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } } } } }, - "is-odd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -3102,14 +3020,6 @@ "dev": true, "requires": { "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": false, - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } } }, "is-regexp": { @@ -3140,14 +3050,6 @@ "dev": true, "requires": { "unc-path-regex": "^0.1.2" - }, - "dependencies": { - "unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", - "dev": true - } } }, "is-utf8": { @@ -3174,6 +3076,12 @@ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", @@ -3302,38 +3210,6 @@ "object.map": "^1.0.0", "rechoir": "^0.6.2", "resolve": "^1.1.7" - }, - "dependencies": { - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "resolve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz", - "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - } } }, "locate-path": { @@ -3347,10 +3223,9 @@ } }, "lodash": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", - "dev": true + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash._basecopy": { "version": "3.0.1", @@ -3478,29 +3353,12 @@ "dev": true }, "make-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.0.tgz", - "integrity": "sha1-V7713IXSOSO6I3ZzJNjo+PPZaUs=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { - "kind-of": "^3.1.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "kind-of": "^6.0.2" } }, "map-cache": { @@ -3576,16 +3434,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" + "is-plain-object": "^2.0.4" } } } @@ -3628,15 +3477,6 @@ "requires": { "is-plain-object": "^2.0.4" } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } } } }, @@ -3736,9 +3576,9 @@ } }, "nanomatch": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -3746,7 +3586,6 @@ "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", "is-windows": "^1.0.2", "kind-of": "^6.0.2", "object.pick": "^1.3.0", @@ -3773,22 +3612,13 @@ "requires": { "is-plain-object": "^2.0.4" } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } } } }, "natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.5.tgz", + "integrity": "sha512-1pJ+02gl2KJgCPFtpZGtuD4lGSJnIZvvFHCQTOeDRMSXjfu2GmYWuhI8NFMA4W2I5NNFRbfy/YCiVt4CgNpP8A==", "dev": true }, "noice-json-rpc": { @@ -3798,6 +3628,7 @@ }, "normalize-path": { "version": "2.1.1", + "resolved": false, "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { @@ -3854,49 +3685,6 @@ "is-descriptor": "^0.1.0" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -3904,6 +3692,14 @@ "dev": true, "requires": { "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } } } } @@ -3968,6 +3764,7 @@ }, "once": { "version": "1.4.0", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" @@ -4224,11 +4021,6 @@ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, - "process-nextick-args": { - "version": "1.0.7", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -4300,25 +4092,13 @@ "dev": true, "requires": { "resolve": "^1.1.6" - }, - "dependencies": { - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "resolve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz", - "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - } } }, + "reflect-metadata": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz", + "integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==" + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -4347,15 +4127,6 @@ "requires": { "is-plain-object": "^2.0.4" } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } } } }, @@ -4381,14 +4152,15 @@ } }, "remove-trailing-separator": { - "version": "1.0.2", - "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", "dev": true }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { @@ -4416,9 +4188,9 @@ "dev": true }, "resolve": { - "version": "1.3.3", - "resolved": false, - "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { "path-parse": "^1.0.5" @@ -4502,10 +4274,9 @@ "dev": true }, "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, "sequencify": { "version": "0.0.7", @@ -4539,15 +4310,6 @@ "requires": { "is-extendable": "^0.1.0" } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } } } }, @@ -4620,69 +4382,6 @@ "is-extendable": "^0.1.0" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -4710,6 +4409,35 @@ "requires": { "is-descriptor": "^1.0.0" } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } } } }, @@ -4722,12 +4450,6 @@ "kind-of": "^3.2.0" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -4735,6 +4457,14 @@ "dev": true, "requires": { "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } } } } @@ -4813,15 +4543,6 @@ "requires": { "is-plain-object": "^2.0.4" } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } } } }, @@ -4849,69 +4570,6 @@ "requires": { "is-descriptor": "^0.1.0" } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true } } }, @@ -4979,14 +4637,6 @@ "requires": { "first-chunk-stream": "^1.0.0", "is-utf8": "^0.2.0" - }, - "dependencies": { - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - } } }, "strip-eof": { @@ -5003,6 +4653,7 @@ }, "through": { "version": "2.3.8", + "resolved": false, "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -5023,22 +4674,32 @@ "dev": true }, "readable-stream": { - "version": "2.3.3", - "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", + "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", + "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + } } }, "string_decoder": { - "version": "1.0.3", - "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -5134,12 +4795,6 @@ "kind-of": "^3.0.2" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -5147,6 +4802,14 @@ "dev": true, "requires": { "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } } } } @@ -5181,15 +4844,6 @@ "requires": { "is-plain-object": "^2.0.4" } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } } } }, @@ -5219,9 +4873,9 @@ "dev": true }, "tslint": { - "version": "5.9.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", - "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz", + "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", "dev": true, "requires": { "babel-code-frame": "^6.22.0", @@ -5235,7 +4889,7 @@ "resolve": "^1.3.2", "semver": "^5.3.0", "tslib": "^1.8.0", - "tsutils": "^2.12.1" + "tsutils": "^2.27.2" }, "dependencies": { "ansi-styles": { @@ -5248,9 +4902,9 @@ } }, "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -5258,32 +4912,29 @@ "supports-color": "^5.3.0" } }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", "dev": true }, "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } } } }, @@ -5449,9 +5100,9 @@ } }, "typescript": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz", - "integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz", + "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==", "dev": true }, "unc-path-regex": { @@ -5505,15 +5156,6 @@ "is-extendable": "^0.1.0" } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "set-value": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", @@ -5587,13 +5229,10 @@ "dev": true }, "use": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true }, "user-home": { "version": "1.1.1", @@ -5655,18 +5294,6 @@ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", "dev": true }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", @@ -5698,12 +5325,6 @@ "clone": "^0.2.0", "clone-stats": "^0.0.1" } - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true } } }, @@ -5763,18 +5384,18 @@ } }, "vscode-debugadapter": { - "version": "1.33.0-pre.2", - "resolved": "https://registry.npmjs.org/vscode-debugadapter/-/vscode-debugadapter-1.33.0-pre.2.tgz", - "integrity": "sha512-H5J1YTjsuiBmdnjl/zvrSTNClfcoz/i4tWDoxvW4FEE3jEfhW2npapiwJkLuzVFnv7tlU0iiJzqhv2iYwBFZoA==", + "version": "1.33.0-pre.3", + "resolved": "https://registry.npmjs.org/vscode-debugadapter/-/vscode-debugadapter-1.33.0-pre.3.tgz", + "integrity": "sha512-/mhE1DUIPLdAbYzRa1jkloGnrmhpdv2gqrwZzGg0XW4Y4+vJI4IqiUY2DJGpV7ztXLx1DC8Z2RkY0ZN9HLVpeg==", "requires": { "mkdirp": "^0.5.1", - "vscode-debugprotocol": "1.32.0" + "vscode-debugprotocol": "1.33.0-pre.0" }, "dependencies": { "vscode-debugprotocol": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.32.0.tgz", - "integrity": "sha512-x3+HV+BkLqfl1ZuDJEILAv1sT5mDceuPThDXD12hwXAEjAdfc6MLQFvaoVPuO6C6gb+lHQTd0R9FNkCflEJHbA==" + "version": "1.33.0-pre.0", + "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.33.0-pre.0.tgz", + "integrity": "sha512-LRTpPDLkq7fcjvRr8Ttzo+1tiFXuxOcYQ5xhN7i/dYN6ISwg9hcQv4W74n8JBxz1nXdVpbS52KLKQMiZhBwpgg==" } } }, @@ -5825,6 +5446,12 @@ "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", "dev": true }, + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "dev": true + }, "vinyl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", @@ -5842,20 +5469,12 @@ } }, "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" - }, - "dependencies": { - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - } } }, "which-module": { diff --git a/package.json b/package.json index 4948cf687..2c9c659bf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vscode-chrome-debug-core", "displayName": "vscode-chrome-debug-core", - "version": "6.7.35", + "version": "10.0.0", "description": "A library for building VS Code debug adapters for targets that support the Chrome Remote Debug Protocol", "repository": { "type": "git", @@ -16,9 +16,14 @@ "color": "^3.0.0", "devtools-protocol": "0.0.588169", "glob": "^7.1.3", + "inversify": "^5.0.1", + "inversify-inject-decorators": "^3.1.0", + "lodash": "^4.17.11", "noice-json-rpc": "^1.2.0", + "reflect-metadata": "^0.1.12", + "semver": "^5.6.0", "source-map": "^0.6.1", - "vscode-debugadapter": "^1.33.0-pre.2", + "vscode-debugadapter": "^1.33.0-pre.3", "vscode-debugprotocol": "^1.32.0", "vscode-nls": "^4.0.0", "ws": "^6.0.0" @@ -26,10 +31,13 @@ "devDependencies": { "@types/color": "^3.0.0", "@types/glob": "^5.0.35", + "@types/inversify-inject-decorators": "^2.0.0", + "@types/lodash": "^4.14.116", "@types/minimatch": "^2.0.29", "@types/mocha": "^2.2.32", "@types/mockery": "^1.4.29", "@types/node": "^8.0.58", + "@types/semver": "^5.5.0", "@types/ws": "^6.0.0", "del": "^2.2.2", "event-stream": "^3.3.4", @@ -44,11 +52,11 @@ "mocha": "^5.2.0", "mockery": "^1.7.0", "run-sequence": "^1.2.2", - "tslint": "^5.9.1", + "tslint": "^5.11.0", "tslint-eslint-rules": "^1.5.0", "tslint-microsoft-contrib": "^5.0.3", "typemoq": "^2.1.0", - "typescript": "^2.7.2", + "typescript": "^3.1.6", "vscode-nls-dev": "^3.2.2" }, "scripts": { diff --git a/src/chrome/breakOnLoadHelper.ts b/src/chrome/breakOnLoadHelper.ts index b54dfc7b1..3c69d2a68 100644 --- a/src/chrome/breakOnLoadHelper.ts +++ b/src/chrome/breakOnLoadHelper.ts @@ -6,31 +6,36 @@ import { logger } from 'vscode-debugadapter'; import { ISetBreakpointResult, BreakOnLoadStrategy } from '../debugAdapterInterfaces'; import { Protocol as Crdp } from 'devtools-protocol'; -import { ChromeDebugAdapter } from './chromeDebugAdapter'; +import { ChromeDebugLogic } from './chromeDebugAdapter'; import * as ChromeUtils from './chromeUtils'; import * as assert from 'assert'; import { InternalSourceBreakpoint } from './internalSourceBreakpoint'; -import { utils, Version } from '..'; +import { Version, parseResourceIdentifier } from '..'; +import { PausedEvent } from './target/events'; +import { LocationInScript } from './internal/locations/location'; +import { BreakpointsLogic } from './internal/breakpoints/breakpointsLogic'; +import { IResourceIdentifier, newResourceIdentifierMap } from './internal/sources/resourceIdentifier'; export interface UrlRegexAndFileSet { urlRegex: string; - fileSet: Set; + fileSet: Set; } export class BreakOnLoadHelper { - private _doesDOMInstrumentationRecieveExtraEvent = false; + public _doesDOMInstrumentationRecieveExtraEvent = false; private _instrumentationBreakpointSet = false; // Break on load: Store some mapping between the requested file names, the regex for the file, and the chrome breakpoint id to perform lookup operations efficiently private _stopOnEntryBreakpointIdToRequestedFileName = new Map(); - private _stopOnEntryRequestedFileNameToBreakpointId = new Map(); + private _stopOnEntryRequestedFileNameToBreakpointId = newResourceIdentifierMap(); private _stopOnEntryRegexToBreakpointId = new Map(); - private _chromeDebugAdapter: ChromeDebugAdapter; + private _chromeDebugAdapter: ChromeDebugLogic; private _breakOnLoadStrategy: BreakOnLoadStrategy; - public constructor(chromeDebugAdapter: ChromeDebugAdapter, breakOnLoadStrategy: BreakOnLoadStrategy) { + public constructor(chromeDebugAdapter: ChromeDebugLogic, breakOnLoadStrategy: BreakOnLoadStrategy, + public readonly _breakpointsLogic: BreakpointsLogic) { this.validateStrategy(breakOnLoadStrategy); this._chromeDebugAdapter = chromeDebugAdapter; this._breakOnLoadStrategy = breakOnLoadStrategy; @@ -42,7 +47,7 @@ export class BreakOnLoadHelper { } } - public get stopOnEntryRequestedFileNameToBreakpointId(): Map { + public get stopOnEntryRequestedFileNameToBreakpointId(): Map { return this._stopOnEntryRequestedFileNameToBreakpointId; } @@ -54,10 +59,6 @@ export class BreakOnLoadHelper { return this._instrumentationBreakpointSet; } - private getScriptUrlFromId(scriptId: string): string { - return utils.canonicalizeUrl(this._chromeDebugAdapter.scriptsById.get(scriptId).url); - } - public async setBrowserVersion(version: Version): Promise { // On version 69 Chrome stopped sending an extra event for DOM Instrumentation: See https://bugs.chromium.org/p/chromium/issues/detail?id=882909 // On Chrome 68 we were relying on that event to make Break on load work on breakpoints on the first line of a file. On Chrome 69 we need an alternative way to make it work. @@ -69,58 +70,60 @@ export class BreakOnLoadHelper { * Checks if the event is caused by a stopOnEntry breakpoint of using the regex approach, or the paused event due to the Chrome's instrument approach * Returns whether we should continue or not on this paused event */ - public async handleOnPaused(notification: Crdp.Debugger.PausedEvent): Promise { - if (notification.hitBreakpoints && notification.hitBreakpoints.length) { - // If breakOnLoadStrategy is set to regex, we may have hit a stopOnEntry breakpoint we put. - // So we need to resolve all the pending breakpoints in this script and then decide to continue or not - if (this._breakOnLoadStrategy === 'regex') { - let shouldContinue = await this.handleStopOnEntryBreakpointAndContinue(notification); - return shouldContinue; - } - } else if (this.isInstrumentationPause(notification)) { - // This is fired when Chrome stops on the first line of a script when using the setInstrumentationBreakpoint API - const pausedScriptId = notification.callFrames[0].location.scriptId; - - // Now we wait for all the pending breakpoints to be resolved and then continue - await this._chromeDebugAdapter.getBreakpointsResolvedDefer(pausedScriptId).promise; - logger.log('BreakOnLoadHelper: Finished waiting for breakpoints to get resolved.'); - let shouldContinue = this._doesDOMInstrumentationRecieveExtraEvent || await this.handleStopOnEntryBreakpointAndContinue(notification); - return shouldContinue; - } + public async handleOnPaused(_notification: PausedEvent): Promise { + // function hasHitBreakpoints(notification: PausedEvent): notification is MakePropertyRequired { + // return !!notification.hitBreakpoints && notification.hitBreakpoints.length > 0; + // } + + // if (hasHitBreakpoints(notification)) { + // // If breakOnLoadStrategy is set to regex, we may have hit a stopOnEntry breakpoint we put. + // // So we need to resolve all the pending breakpoints in this script and then decide to continue or not + // if (this._breakOnLoadStrategy === 'regex') { + // let shouldContinue = await this.handleStopOnEntryBreakpointAndContinue(notification); + // return shouldContinue; + // } + // } else if (this.isInstrumentationPause(notification)) { + // // This is fired when Chrome stops on the first line of a script when using the setInstrumentationBreakpoint API + // const pausedScript = notification.callFrames[0].location.script; + + // // Now we wait for all the pending breakpoints to be resolved and then continue + // await this._breakpointsLogic.getBreakpointsResolvedDefer(pausedScript).promise; + // logger.log('BreakOnLoadHelper: Finished waiting for breakpoints to get resolved.'); + // let shouldContinue = this._doesDOMInstrumentationRecieveExtraEvent || await this.handleStopOnEntryBreakpointAndContinue(notification); + // return shouldContinue; + // } return false; } - private isInstrumentationPause(notification: Crdp.Debugger.PausedEvent): boolean { - return (notification.reason === 'EventListener' && notification.data.eventName === 'instrumentation:scriptFirstStatement') || - (notification.reason === 'ambiguous' && Array.isArray(notification.data.reasons) && - notification.data.reasons.every(r => r.reason === 'EventListener' && r.auxData.eventName === 'instrumentation:scriptFirstStatement')); + isInstrumentationPause(_notification: PausedEvent): any { + throw new Error('Method not implemented.'); } /** * Returns whether we should continue on hitting a stopOnEntry breakpoint * Only used when using regex approach for break on load */ - private async shouldContinueOnStopOnEntryBreakpoint(pausedLocation: Crdp.Debugger.Location): Promise { + private async shouldContinueOnStopOnEntryBreakpoint(_pausedLocation: LocationInScript): Promise { // If the file has no unbound breakpoints or none of the resolved breakpoints are at (1,1), we should continue after hitting the stopOnEntry breakpoint let shouldContinue = true; - // Important: For the logic that verifies if a user breakpoint is set in the paused location, we need to resolve pending breakpoints, and commit them, before - // using committedBreakpointsByUrl for our logic. - await this._chromeDebugAdapter.getBreakpointsResolvedDefer(pausedLocation.scriptId).promise; - - const pausedScriptUrl = this.getScriptUrlFromId(pausedLocation.scriptId); - // Important: We need to get the committed breakpoints only after all the pending breakpoints for this file have been resolved. If not this logic won't work - const committedBps = this._chromeDebugAdapter.committedBreakpointsByUrl.get(pausedScriptUrl) || []; - const anyBreakpointsAtPausedLocation = committedBps.filter(bp => - bp.actualLocation.lineNumber === pausedLocation.lineNumber && bp.actualLocation.columnNumber === pausedLocation.columnNumber).length > 0; - - // If there were any breakpoints at this location (Which generally should be (1,1)) we shouldn't continue - if (anyBreakpointsAtPausedLocation) { - // Here we need to store this information per file, but since we can safely assume that scriptParsed would immediately be followed by onPaused event - // for the breakonload files, this implementation should be fine - shouldContinue = false; - } + // // Important: For the logic that verifies if a user breakpoint is set in the paused location, we need to resolve pending breakpoints, and commit them, before + // // using committedBreakpointsByUrl for our logic. + // await this._breakpointsLogic.getBreakpointsResolvedDefer(pausedLocation.script).promise; + + // const pausedScriptUrl = pausedLocation.script; + // // Important: We need to get the committed breakpoints only after all the pending breakpoints for this file have been resolved. If not this logic won't work + // const committedBps = this._breakpointsLogic.committedBreakpointsByUrl.get(pausedScriptUrl.runtimeSource.identifier) || []; + // const anyBreakpointsAtPausedLocation = committedBps.filter(bp => + // bp.actualLocation.lineNumber === pausedLocation.lineNumber && bp.actualLocation.columnNumber === pausedLocation.columnNumber).length > 0; + + // // If there were any breakpoints at this location (Which generally should be (1,1)) we shouldn't continue + // if (anyBreakpointsAtPausedLocation) { + // // Here we need to store this information per file, but since we can safely assume that scriptParsed would immediately be followed by onPaused event + // // for the breakonload files, this implementation should be fine + // shouldContinue = false; + // } return shouldContinue; } @@ -129,30 +132,29 @@ export class BreakOnLoadHelper { * Handles a script with a stop on entry breakpoint and returns whether we should continue or not on hitting that breakpoint * Only used when using regex approach for break on load */ - private async handleStopOnEntryBreakpointAndContinue(notification: Crdp.Debugger.PausedEvent): Promise { + public async handleStopOnEntryBreakpointAndContinue(notification: PausedEvent): Promise { const hitBreakpoints = notification.hitBreakpoints; let allStopOnEntryBreakpoints = true; - const pausedScriptId = notification.callFrames[0].location.scriptId; - const pausedScriptUrl = this._chromeDebugAdapter.scriptsById.get(pausedScriptId).url; - const mappedUrl = await this._chromeDebugAdapter.pathTransformer.scriptParsed(pausedScriptUrl); + const pausedScriptUrl = notification.callFrames[0].location.script; + const mappedUrl = parseResourceIdentifier((await this._chromeDebugAdapter.pathTransformer.scriptParsed(pausedScriptUrl.runtimeSource.identifier)).textRepresentation); // If there is a breakpoint which is not a stopOnEntry breakpoint, we appear as if we hit that one // This is particularly done for cases when we end up with a user breakpoint and a stopOnEntry breakpoint on the same line for (let bp of hitBreakpoints) { - let regexAndFileNames = this._stopOnEntryBreakpointIdToRequestedFileName.get(bp); + let regexAndFileNames = {} as UrlRegexAndFileSet; // this._stopOnEntryBreakpointIdToRequestedFileName.get(bp); if (!regexAndFileNames) { - notification.hitBreakpoints = [bp]; + // notification.hitBreakpoints = [bp]; allStopOnEntryBreakpoints = false; } else { - const normalizedMappedUrl = utils.canonicalizeUrl(mappedUrl); + const normalizedMappedUrl = mappedUrl; if (regexAndFileNames.fileSet.has(normalizedMappedUrl)) { regexAndFileNames.fileSet.delete(normalizedMappedUrl); assert(this._stopOnEntryRequestedFileNameToBreakpointId.delete(normalizedMappedUrl), `Expected to delete break-on-load information associated with url: ${normalizedMappedUrl}`); if (regexAndFileNames.fileSet.size === 0) { logger.log(`Stop on entry breakpoint hit for last remaining file. Removing: ${bp} created for: ${normalizedMappedUrl}`); - await this.removeBreakpointById(bp); + // await this.removeBreakpointById(bp); assert(this._stopOnEntryRegexToBreakpointId.delete(regexAndFileNames.urlRegex), `Expected to delete break-on-load information associated with regexp: ${regexAndFileNames.urlRegex}`); } else { logger.log(`Stop on entry breakpoint hit but still has remaining files. Keeping: ${bp} that was hit for: ${normalizedMappedUrl} because it's still needed for: ${Array.from(regexAndFileNames.fileSet.entries()).join(', ')}`); @@ -182,13 +184,13 @@ export class BreakOnLoadHelper { * Adds a stopOnEntry breakpoint for the given script url * Only used when using regex approach for break on load */ - private async addStopOnEntryBreakpoint(url: string): Promise { + private async addStopOnEntryBreakpoint(url: IResourceIdentifier): Promise { let responsePs: ISetBreakpointResult[]; // Check if file already has a stop on entry breakpoint if (!this._stopOnEntryRequestedFileNameToBreakpointId.has(url)) { // Generate regex we need for the file - const normalizedUrl = utils.canonicalizeUrl(url); + const normalizedUrl = url; const urlRegex = ChromeUtils.getUrlRegexForBreakOnLoad(normalizedUrl); // Check if we already have a breakpoint for this regexp since two different files like script.ts and script.js may have the same regexp @@ -223,7 +225,7 @@ export class BreakOnLoadHelper { if (regexAndFileNames !== undefined) { regexAndFileNames.fileSet.add(normalizedUrl); } else { // else create an entry for this breakpoint id - const fileSet = new Set(); + const fileSet = new Set(); fileSet.add(normalizedUrl); this._stopOnEntryBreakpointIdToRequestedFileName.set(breakpointId, { urlRegex, fileSet }); } @@ -237,7 +239,10 @@ export class BreakOnLoadHelper { * Handles the AddBreakpoints request when break on load is active * Takes the action based on the strategy */ - public async handleAddBreakpoints(url: string, breakpoints: InternalSourceBreakpoint[]): Promise { + public async handleAddBreakpoints(url: IResourceIdentifier, breakpoints: InternalSourceBreakpoint[]): Promise<{ + breakpointId?: Crdp.Debugger.BreakpointId; + actualLocation?: LocationInScript; + }[]> { // If the strategy is set to regex, we try to match the file where user put the breakpoint through a regex and tell Chrome to put a stop on entry breakpoint there if (this._breakOnLoadStrategy === 'regex') { await this.addStopOnEntryBreakpoint(url); @@ -249,7 +254,7 @@ export class BreakOnLoadHelper { } // Temporary fix: We return an empty element for each breakpoint that was requested - return breakpoints.map(breakpoint => { return {}; }); + return breakpoints.map(() => { return {}; }); } /** @@ -262,14 +267,11 @@ export class BreakOnLoadHelper { } // Sets a breakpoint on (0,0) for the files matching the given regex - private async setStopOnEntryBreakpoint(urlRegex: string): Promise { - let result = await this._chromeDebugAdapter.chrome.Debugger.setBreakpointByUrl({ urlRegex, lineNumber: 0, columnNumber: 0 }); - return result; - } - - // Removes a breakpoint by it's chrome-crdp-id - private async removeBreakpointById(breakpointId: string): Promise { - return await this._chromeDebugAdapter.chrome.Debugger.removeBreakpoint({breakpointId: breakpointId }); + private async setStopOnEntryBreakpoint(_urlRegex: string): Promise { + // DIEGO TODO: Re-enable this code + // let result = await this._chromeDebugAdapter.chrome.Debugger.setBreakpointByUrl({ urlRegex, lineNumber: 0, columnNumber: 0 }); + // return result; + return Promise.reject(new Error('Not yet implemented')); } /** @@ -278,7 +280,7 @@ export class BreakOnLoadHelper { * set break on load breakpoints. For those files, it is called from onPaused function. * For the default Chrome's API approach, we don't need to call resolvePendingBPs from inside scriptParsed */ - public shouldResolvePendingBPs(mappedUrl: string): boolean { + public shouldResolvePendingBPs(mappedUrl: IResourceIdentifier): boolean { if (this._breakOnLoadStrategy === 'regex' && !this.stopOnEntryRequestedFileNameToBreakpointId.has(mappedUrl)) { return true; } diff --git a/src/chrome/chromeConnection.ts b/src/chrome/chromeConnection.ts index 0819baca3..3a4d3d20a 100644 --- a/src/chrome/chromeConnection.ts +++ b/src/chrome/chromeConnection.ts @@ -11,13 +11,10 @@ import * as utils from '../utils'; import { logger } from 'vscode-debugadapter'; import { ChromeTargetDiscovery, TargetVersions, Version } from './chromeTargetDiscoveryStrategy'; -import { Client, LikeSocket } from 'noice-json-rpc'; +import { Client } from 'noice-json-rpc'; import { Protocol as Crdp } from 'devtools-protocol'; -import { CRDPMultiplexor } from './crdpMultiplexing/crdpMultiplexor'; -import { WebSocketToLikeSocketProxy } from './crdpMultiplexing/webSocketToLikeSocketProxy'; - export interface ITarget { description: string; devtoolsFrontendUrl: string; @@ -73,7 +70,7 @@ class LoggingSocket extends WebSocket { }); } - public send(data: any, opts?: any, cb?: (err: Error) => void): void { + public send(data: any, _opts?: any, _?: (err: Error) => void): void { const msgStr = JSON.stringify(data); if (this.readyState !== WebSocket.OPEN) { logger.log(`→ Warning: Target not open! Message: ${msgStr}`); @@ -98,9 +95,8 @@ export class ChromeConnection implements IObservableEvents; private _attachedTarget: ITarget; public readonly events: StepProgressEventsEmitter; @@ -133,7 +129,7 @@ export class ChromeConnection implements IObservableEvents { }); } - public attachToWebsocketUrl(wsUrl: string, extraCRDPChannelPort?: number): void { + public attachToWebsocketUrl(wsUrl: string, _extraCRDPChannelPort?: number): void { /* __GDPR__FRAGMENT__ "StepNames" : { "Attach.AttachToTargetDebuggerWebsocket" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } @@ -141,15 +137,9 @@ export class ChromeConnection implements IObservableEventsthis._socket as any); - } + this._client = new Client(this._socket as any); - this._client.on('error', e => logger.error('Error handling message from target: ' + e.message)); + this._client.on('error', (e: any) => logger.error('Error handling message from target: ' + e.message)); } public getAllTargets(address = '127.0.0.1', port = 9222, targetFilter?: ITargetFilter, targetUrl?: string): Promise { @@ -168,16 +158,6 @@ export class ChromeConnection implements IObservableEvents { - // This is a CDP version difference which will have to be handled more elegantly with others later... - // For now, we need to send both messages and ignore a failing one. - return Promise.all([ - this.api.Runtime.runIfWaitingForDebugger(), - (this.api.Runtime).run() - ]) - .then(() => { }, () => { }); - } - public close(): void { this._socket.close(); } diff --git a/src/chrome/chromeDebugAdapter.ts b/src/chrome/chromeDebugAdapter.ts index f2949afa9..7d87cd2e3 100644 --- a/src/chrome/chromeDebugAdapter.ts +++ b/src/chrome/chromeDebugAdapter.ts @@ -3,41 +3,126 @@ *--------------------------------------------------------*/ import { DebugProtocol } from 'vscode-debugprotocol'; -import { InitializedEvent, TerminatedEvent, Handles, ContinuedEvent, BreakpointEvent, OutputEvent, Logger, logger, LoadedSourceEvent } from 'vscode-debugadapter'; - -import { ICommonRequestArgs, ILaunchRequestArgs, ISetBreakpointsArgs, ISetBreakpointsResponseBody, IStackTraceResponseBody, - IAttachRequestArgs, IScopesResponseBody, IVariablesResponseBody, - ISourceResponseBody, IThreadsResponseBody, IEvaluateResponseBody, ISetVariableResponseBody, IDebugAdapter, - ICompletionsResponseBody, IToggleSkipFileStatusArgs, IInternalStackTraceResponseBody, - IExceptionInfoResponseBody, ISetBreakpointResult, IRestartRequestArgs, IInitializeRequestArgs, ITelemetryPropertyCollector, IGetLoadedSourcesResponseBody, TimeTravelRuntime } from '../debugAdapterInterfaces'; -import { IChromeDebugAdapterOpts, ChromeDebugSession } from './chromeDebugSession'; +import { TerminatedEvent, ContinuedEvent, logger, } from 'vscode-debugadapter'; + +import { + ICommonRequestArgs, ILaunchRequestArgs, IScopesResponseBody, IVariablesResponseBody, + IThreadsResponseBody, IEvaluateResponseBody, ISetVariableResponseBody, + ICompletionsResponseBody, IRestartRequestArgs, TimeTravelRuntime +} from '../debugAdapterInterfaces'; + import { ChromeConnection } from './chromeConnection'; import * as ChromeUtils from './chromeUtils'; import { Protocol as Crdp } from 'devtools-protocol'; import { PropertyContainer, ScopeContainer, ExceptionContainer, isIndexedPropName, IVariableContainer } from './variables'; import * as variables from './variables'; import { formatConsoleArguments, formatExceptionDetails, clearConsoleCode } from './consoleHelper'; -import { StoppedEvent2, ReasonType } from './stoppedEvent'; -import { InternalSourceBreakpoint, stackTraceWithoutLogpointFrame } from './internalSourceBreakpoint'; +import { ReasonType } from './stoppedEvent'; +import { stackTraceWithoutLogpointFrame } from './internalSourceBreakpoint'; import * as errors from '../errors'; import * as utils from '../utils'; -import { PromiseDefer, promiseDefer } from '../utils'; -import { telemetry, BatchTelemetryReporter, IExecutionResultTelemetryProperties } from '../telemetry'; +import { telemetry, BatchTelemetryReporter } from '../telemetry'; import { StepProgressEventsEmitter } from '../executionTimingsReporter'; import { LineColTransformer } from '../transformers/lineNumberTransformer'; import { BasePathTransformer } from '../transformers/basePathTransformer'; -import { RemotePathTransformer } from '../transformers/remotePathTransformer'; import { BaseSourceMapTransformer } from '../transformers/baseSourceMapTransformer'; -import { EagerSourceMapTransformer } from '../transformers/eagerSourceMapTransformer'; -import { FallbackToClientPathTransformer } from '../transformers/fallbackToClientPathTransformer'; import { BreakOnLoadHelper } from './breakOnLoadHelper'; import * as sourceMapUtils from '../sourceMaps/sourceMapUtils'; -import * as path from 'path'; - import * as nls from 'vscode-nls'; +import { CDTPDiagnostics } from './target/cdtpDiagnostics'; +import { ISession } from './client/session'; +import { IScript } from './internal/scripts/script'; + +import { EvaluateOnCallFrameRequest } from './target/requests'; +import { PausedEvent, ConsoleAPICalledEvent, ExceptionThrownEvent, LogEntry } from './target/events'; +import { LocationInLoadedSource } from './internal/locations/location'; +import { EvaluateArguments, CompletionsArguments } from './internal/requests'; +import { EventSender } from './client/eventSender'; +import { parseResourceIdentifier, ConnectedCDAConfiguration } from '..'; +import { ICallFrame, ScriptOrLoadedSource } from './internal/stackTraces/callFrame'; +import { CodeFlowStackTrace } from './internal/stackTraces/stackTrace'; +import { IResourceIdentifier } from './internal/sources/resourceIdentifier'; +import { FormattedExceptionParser } from './internal/formattedExceptionParser'; +import { DeleteMeScriptsRegistry } from './internal/scripts/scriptsRegistry'; +import { ExceptionThrownEventProvider } from './target/ExceptionThrownEventProvider'; +import { ExecutionContextEventsProvider } from './target/executionContextEventsProvider'; +import { IInspectDebugeeState } from './target/inspectDebugeeState'; +import { IUpdateDebugeeState } from './target/updateDebugeeState'; +import { injectable, inject } from 'inversify'; +import { TYPES } from './dependencyInjection.ts/types'; +import { ICDTPDebuggerEventsProvider } from './target/cdtpDebuggerEventsProvider'; + +// export class ChromeDebugAdapter extends ChromeDebugAdapterClass { +// /** These methods are called by the ChromeDebugAdapter subclass in chrome-debug. We need to redirect them like this +// * until we complete the refactor in chrome-debug and we make these methods work in a proper way +// */ +// protected hookConnectionEvents(): void { +// return this.chromeDebugAdapter.hookConnectionEvents(); +// } +// public commonArgs(args: ICommonRequestArgs): void { +// return this.chromeDebugAdapter.commonArgs(args); +// } +// protected onResumed(): void { +// return this.chromeDebugAdapter.onResumed(); +// } +// protected terminateSession(reason: string, restart?: IRestartRequestArgs): Promise { +// return this.chromeDebugAdapter.terminateSession(reason, restart); +// } +// protected globalEvaluate(args: Crdp.Runtime.EvaluateRequest): Promise { +// return this.chromeDebugAdapter.globalEvaluate(args); +// } +// protected get _launchAttachArgs(): ICommonRequestArgs { +// return this.chromeDebugAdapter._launchAttachArgs; +// } +// protected set _expectingStopReason(value: ReasonType) { +// this.chromeDebugAdapter._expectingStopReason = value; +// } +// protected get _domains(): Map { +// return this.chromeDebugAdapter._domains; +// } +// protected get _hasTerminated(): boolean { +// return this.chromeDebugAdapter._hasTerminated; +// } +// protected get _session(): ISession { +// return this.chromeDebugAdapter._session; +// } + +// /** These methods are called by the NodeDebugAdapter subclass in node-debug2. We need to redirect them like this +// * until we complete the refactor in node-debug2 and we make these methods work in a proper way +// */ +// protected get _attachMode(): boolean { +// return this.chromeDebugAdapter._attachMode; +// } +// protected set _promiseRejectExceptionFilterEnabled(value: boolean) { +// this.chromeDebugAdapter._promiseRejectExceptionFilterEnabled = value; +// } +// protected get _pathTransformer(): BasePathTransformer { +// return this.chromeDebugAdapter._pathTransformer; +// } +// protected get _inShutdown(): boolean { +// return this.chromeDebugAdapter._inShutdown; +// } +// protected get _port(): number { +// return this.chromeDebugAdapter._port; +// } + +// protected get _sourceMapTransformer(): BaseSourceMapTransformer { +// return this.chromeDebugAdapter.sourceMapTransformer; +// } + +// protected static get EVAL_NAME_PREFIX(): string { +// return ChromeDebugLogic.EVAL_NAME_PREFIX; +// } + +// protected onConsoleAPICalled(event: ConsoleAPICalledEvent): void { +// return this.chromeDebugAdapter.onConsoleAPICalled(event); +// } +// // DIEGO START +// } + let localize = nls.loadMessageBundle(); interface IPropCount { @@ -51,25 +136,13 @@ interface IPropCount { */ export interface ISourceContainer { /** The runtime-side scriptId of this script */ - scriptId?: Crdp.Runtime.ScriptId; + scriptId?: IScript; /** The contents of this script, if they are inlined in the sourcemap */ contents?: string; /** The authored path to this script (only set if the contents are inlined) */ mappedPath?: string; } -export interface IPendingBreakpoint { - args: ISetBreakpointsArgs; - ids: number[]; - requestSeq: number; - setWithPath: string; -} - -interface IHitConditionBreakpoint { - numHits: number; - shouldPause: (numHits: number) => boolean; -} - export type VariableContext = 'variables' | 'watch' | 'repl' | 'hover'; export type CrdpScript = Crdp.Debugger.ScriptParsedEvent; @@ -78,138 +151,91 @@ export type CrdpDomain = string; export type LoadedSourceEventReason = 'new' | 'changed' | 'removed'; -export interface BreakpointSetResult { - isSet: boolean; - breakpoint: DebugProtocol.Breakpoint; -} - -export interface IOnPausedResult { - didPause: boolean; -} - -export abstract class ChromeDebugAdapter implements IDebugAdapter { +@injectable() +export class ChromeDebugLogic { public static EVAL_NAME_PREFIX = ChromeUtils.EVAL_NAME_PREFIX; public static EVAL_ROOT = ''; - private static SCRIPTS_COMMAND = '.scripts'; - private static THREAD_ID = 1; - private static SET_BREAKPOINTS_TIMEOUT = 5000; - private static HITCONDITION_MATCHER = /^(>|>=|=|<|<=|%)?\s*([0-9]+)$/; - private static ASYNC_CALL_STACK_DEPTH = 4; + public static THREAD_ID = 1; - protected _session: ChromeDebugSession; - protected _domains = new Map(); + public _session: ISession; + public _domains = new Map(); private _clientAttached: boolean; - private _currentPauseNotification: Crdp.Debugger.PausedEvent; - - // when working with _committedBreakpointsByUrl, we want to keep the url keys canonicalized for consistency - // use methods getValueFromCommittedBreakpointsByUrl and setValueForCommittedBreakpointsByUrl - private _committedBreakpointsByUrl: Map; - private _exception: Crdp.Runtime.RemoteObject; - private _setBreakpointsRequestQ: Promise; + private _exception: Crdp.Runtime.RemoteObject | undefined; private _expectingResumedEvent: boolean; - protected _expectingStopReason: ReasonType; + public _expectingStopReason: ReasonType | undefined; private _waitAfterStep = Promise.resolve(); - private _frameHandles: Handles; private _variableHandles: variables.VariableHandles; - private _breakpointIdHandles: utils.ReverseHandles; - private _sourceHandles: utils.ReverseHandles; - - private _scriptsById: Map; - private _scriptsByUrl: Map; - private _pendingBreakpointsByUrl: Map; - private _hitConditionBreakpointsById: Map; private _lineColTransformer: LineColTransformer; - protected _chromeConnection: ChromeConnection; - protected _sourceMapTransformer: BaseSourceMapTransformer; - protected _pathTransformer: BasePathTransformer; - - protected _clientRequestedSessionEnd: boolean; - protected _hasTerminated: boolean; - protected _inShutdown: boolean; - protected _attachMode: boolean; - protected _launchAttachArgs: ICommonRequestArgs; - protected _port: number; - private _blackboxedRegexes: RegExp[] = []; - private _skipFileStatuses = new Map(); + protected _chromeConmer: BaseSourceMapTransformer; + public _pathTransformer: BasePathTransformer; + + public _hasTerminated: boolean; + public _inShutdown: boolean; + public _attachMode: boolean; + public readonly _launchAttachArgs: ICommonRequestArgs = this._configuration.args; + public _port: number; private _currentStep = Promise.resolve(); private _currentLogMessage = Promise.resolve(); - private _nextUnboundBreakpointId = 0; - private _pauseOnPromiseRejections = true; - protected _promiseRejectExceptionFilterEnabled = false; - - private _columnBreakpointsEnabled: boolean; - - private _smartStepEnabled: boolean; - private _smartStepCount = 0; - private _earlyScripts: Crdp.Debugger.ScriptParsedEvent[] = []; - - private _initialSourceMapsP = Promise.resolve(); - - private _lastPauseState: { expecting: ReasonType; event: Crdp.Debugger.PausedEvent }; - - protected _breakOnLoadHelper: BreakOnLoadHelper | null; - - // Queue to synchronize new source loaded and source removed events so that 'remove' script events - // won't be send before the corresponding 'new' event has been sent - private _sourceLoadedQueue: Promise = Promise.resolve(null); - - // Promises so ScriptPaused events can wait for ScriptParsed events to finish resolving breakpoints - private _scriptIdToBreakpointsAreResolvedDefer = new Map>(); + privaRejectExceptionFilterEnabled = false; private _batchTelemetryReporter: BatchTelemetryReporter; public readonly events: StepProgressEventsEmitter; - private _loadedSourcesByScriptId = new Map(); - - protected _isVSClient: boolean; + protected _breakOnLoadHelper: BreakOnLoadHelper | null; - public constructor({ chromeConnection, lineColTransformer, sourceMapTransformer, pathTransformer, targetFilter }: IChromeDebugAdapterOpts, - session: ChromeDebugSession) { + private readonly _chromeDiagnostics: CDTPDiagnostics; + + private readonly _chromeConnection: ChromeConnection; + private readonly _sourceMapTransformer: BaseSourceMapTransformer; + public _promiseRejectExceptionFilterEnabled = false; + public _pauseOnPromiseRejections = true; + static HITCONDITION_MATCHER: any; + + public constructor( + @inject(TYPES.LineColTransformer) lineColTransformer: LineColTransformer, + @inject(TYPES.BaseSourceMapTransformer) sourceMapTransformer: BaseSourceMapTransformer, + @inject(TYPES.BasePathTransformer) pathTransformer: BasePathTransformer, + @inject(TYPES.ISession) session: ISession, + @inject(TYPES.ChromeConnection) chromeConnection: ChromeConnection, + @inject(TYPES.CDTPDiagnostics) chromeDiagnostics: CDTPDiagnostics, + @inject(TYPES.DeleteMeScriptsRegistry) private readonly _scriptsLogic: DeleteMeScriptsRegistry, + @inject(TYPES.EventSender) private readonly _eventSender: EventSender, + @inject(TYPES.ExceptionThrownEventProvider) private readonly _exceptionThrownEventProvider: ExceptionThrownEventProvider, + @inject(TYPES.ExecutionContextEventsProvider) private readonly _executionContextEventsProvider: ExecutionContextEventsProvider, + @inject(TYPES.IInspectDebugeeState) private readonly _inspectDebugeeState: IInspectDebugeeState, + @inject(TYPES.IUpdateDebugeeState) private readonly _updateDebugeeState: IUpdateDebugeeState, + @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration, + @inject(TYPES.ICDTPDebuggerEventsProvider) private readonly _debuggerEvents: ICDTPDebuggerEventsProvider, + ) { telemetry.setupEventHandler(e => session.sendEvent(e)); this._batchTelemetryReporter = new BatchTelemetryReporter(telemetry); this._session = session; - this._chromeConnection = new (chromeConnection || ChromeConnection)(undefined, targetFilter); + this._chromeConnection = chromeConnection; + this._chromeDiagnostics = chromeDiagnostics; this.events = new StepProgressEventsEmitter(this._chromeConnection.events ? [this._chromeConnection.events] : []); - this._frameHandles = new Handles(); this._variableHandles = new variables.VariableHandles(); - this._breakpointIdHandles = new utils.ReverseHandles(); - this._sourceHandles = new utils.ReverseHandles(); - this._pendingBreakpointsByUrl = new Map(); - this._hitConditionBreakpointsById = new Map(); - this._lineColTransformer = new (lineColTransformer || LineColTransformer)(this._session); - this._sourceMapTransformer = new (sourceMapTransformer || EagerSourceMapTransformer)(this._sourceHandles); - this._pathTransformer = new (pathTransformer || RemotePathTransformer)(); + this._lineColTransformer = lineColTransformer; + this._sourceMapTransformer = sourceMapTransformer; + this._pathTransformer = pathTransformer; this.clearTargetContext(); } - public get chrome(): Crdp.ProtocolApi { - return this._chromeConnection.api; - } - - public get scriptsById(): Map { - return this._scriptsById; + public get chrome(): CDTPDiagnostics { + return this._chromeDiagnostics; } public get pathTransformer(): BasePathTransformer { return this._pathTransformer; } - public get pendingBreakpointsByUrl(): Map { - return this._pendingBreakpointsByUrl; - } - - public get committedBreakpointsByUrl(): Map { - return this._committedBreakpointsByUrl; - } - public get sourceMapTransformer(): BaseSourceMapTransformer { return this._sourceMapTransformer; } @@ -219,86 +245,9 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { */ protected clearTargetContext(): void { this._sourceMapTransformer.clearTargetContext(); - - this._scriptsById = new Map(); - this._scriptsByUrl = new Map(); - - this._committedBreakpointsByUrl = new Map(); - this._setBreakpointsRequestQ = Promise.resolve(); - this._pathTransformer.clearTargetContext(); } - /* __GDPR__ - "ClientRequest/initialize" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public initialize(args: IInitializeRequestArgs): DebugProtocol.Capabilities { - if (args.supportsMapURLToFilePathRequest) { - this._pathTransformer = new FallbackToClientPathTransformer(this._session); - } - - this._isVSClient = args.clientID === 'visualstudio'; - utils.setCaseSensitivePaths(!this._isVSClient); - this._sourceMapTransformer.isVSClient = this._isVSClient; - - if (args.pathFormat !== 'path') { - throw errors.pathFormat(); - } - - if (args.locale) { - localize = nls.config({ locale: args.locale })(); - } - - // because session bypasses dispatchRequest - if (typeof args.linesStartAt1 === 'boolean') { - (this)._clientLinesStartAt1 = args.linesStartAt1; - } - if (typeof args.columnsStartAt1 === 'boolean') { - (this)._clientColumnsStartAt1 = args.columnsStartAt1; - } - - const exceptionBreakpointFilters = [ - { - label: localize('exceptions.all', 'All Exceptions'), - filter: 'all', - default: false - }, - { - label: localize('exceptions.uncaught', 'Uncaught Exceptions'), - filter: 'uncaught', - default: false - } - ]; - if (this._promiseRejectExceptionFilterEnabled) { - exceptionBreakpointFilters.push({ - label: localize('exceptions.promise_rejects', 'Promise Rejects'), - filter: 'promise_reject', - default: false - }); - } - - // This debug adapter supports two exception breakpoint filters - return { - exceptionBreakpointFilters, - supportsConfigurationDoneRequest: true, - supportsSetVariable: true, - supportsConditionalBreakpoints: true, - supportsCompletionsRequest: true, - supportsHitConditionalBreakpoints: true, - supportsRestartFrame: true, - supportsExceptionInfoRequest: true, - supportsDelayedStackTraceLoading: true, - supportsValueFormattingOptions: true, - supportsEvaluateForHovers: true, - supportsLoadedSourcesRequest: true - }; - } - /* __GDPR__ "ClientRequest/configurationDone" : { "${include}": [ @@ -315,112 +264,13 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { return !!this._breakOnLoadHelper; } - /* __GDPR__ - "ClientRequest/launch" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public async launch(args: ILaunchRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector): Promise { - this.commonArgs(args); - - if (args.pathMapping) { - for (const urlToMap in args.pathMapping) { - args.pathMapping[urlToMap] = utils.canonicalizeUrl(args.pathMapping[urlToMap]); - } - } - - this._sourceMapTransformer.launch(args); - await this._pathTransformer.launch(args); - - if (!args.__restart) { - /* __GDPR__ - "debugStarted" : { - "request" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "args" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "${include}": [ "${DebugCommonProperties}" ] - } - */ - telemetry.reportEvent('debugStarted', { request: 'launch', args: Object.keys(args) }); - } - } - - /* __GDPR__ - "ClientRequest/attach" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public async attach(args: IAttachRequestArgs): Promise { - this._attachMode = true; - this.commonArgs(args); - this._sourceMapTransformer.attach(args); - await this._pathTransformer.attach(args); - - if (!args.port) { - args.port = 9229; - } - - /* __GDPR__ - "debugStarted" : { - "request" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "args" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "${include}": [ "${DebugCommonProperties}" ] - } - */ - telemetry.reportEvent('debugStarted', { request: 'attach', args: Object.keys(args) }); - await this.doAttach(args.port, args.url, args.address, args.timeout, args.websocketUrl, args.extraCRDPChannelPort); - } - - protected commonArgs(args: ICommonRequestArgs): void { - let logToFile = false; - let logLevel: Logger.LogLevel; - if (args.trace === 'verbose') { - logLevel = Logger.LogLevel.Verbose; - logToFile = true; - } else if (args.trace) { - logLevel = Logger.LogLevel.Warn; - logToFile = true; - } else { - logLevel = Logger.LogLevel.Warn; - } - - let logTimestamps = args.logTimestamps; - - // The debug configuration provider should have set logFilePath on the launch config. If not, default to 'true' to use the - // "legacy" log file path from the CDA subclass - const logFilePath = args.logFilePath || logToFile; - logger.setup(logLevel, logFilePath, logTimestamps); - - this._launchAttachArgs = args; - - // Enable sourcemaps and async callstacks by default - args.sourceMaps = typeof args.sourceMaps === 'undefined' || args.sourceMaps; - args.showAsyncStacks = typeof args.showAsyncStacks === 'undefined' || args.showAsyncStacks; - - this._smartStepEnabled = this._launchAttachArgs.smartStep; - - if (args.breakOnLoadStrategy && args.breakOnLoadStrategy !== 'off') { - this._breakOnLoadHelper = new BreakOnLoadHelper(this, args.breakOnLoadStrategy); - } - - // Use hasOwnProperty to explicitly permit setting a falsy targetFilter. - if (args.hasOwnProperty('targetFilter')) { - this._chromeConnection.setTargetFilter(args.targetFilter); - } - } - public shutdown(): void { this._batchTelemetryReporter.finalize(); this._inShutdown = true; this._session.shutdown(); } - protected async terminateSession(reason: string, disconnectArgs?: DebugProtocol.DisconnectArguments, restart?: IRestartRequestArgs): Promise { + public async terminateSession(reason: string, restart?: IRestartRequestArgs): Promise { logger.log(`Terminated: ${reason}`); if (!this._hasTerminated) { @@ -450,1321 +300,185 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { /** * Hook up all connection events */ - protected hookConnectionEvents(): void { - this.chrome.Debugger.on('paused', params => { - /* __GDPR__ - "target/notification/onPaused" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - this.runAndMeasureProcessingTime('target/notification/onPaused', async () => { - await this.onPaused(params); - }); - }); - this.chrome.Debugger.on('resumed', () => this.onResumed()); - this.chrome.Debugger.on('scriptParsed', params => { - /* __GDPR__ - "target/notification/onScriptParsed" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - this.runAndMeasureProcessingTime('target/notification/onScriptParsed', () => { - return this.onScriptParsed(params); - }); - }); - this.chrome.Debugger.on('breakpointResolved', params => this.onBreakpointResolved(params)); - this.chrome.Console.on('messageAdded', params => this.onMessageAdded(params)); - this.chrome.Runtime.on('consoleAPICalled', params => this.onConsoleAPICalled(params)); - this.chrome.Runtime.on('exceptionThrown', params => this.onExceptionThrown(params)); - this.chrome.Runtime.on('executionContextsCleared', () => this.onExecutionContextsCleared()); - this.chrome.Log.on('entryAdded', params => this.onLogEntryAdded(params)); + public install(): ChromeDebugLogic { + this._debuggerEvents.onResumed(() => this.onResumed()); + this._debuggerEvents.onPaused(paused => this.onPaused(paused)); + this.chrome.Console.onMessageAdded(params => this.onMessageAdded(params)); + this.chrome.Console.enable(); + this.chrome.Runtime.onConsoleAPICalled(params => this.onConsoleAPICalled(params)); + this._exceptionThrownEventProvider.onExceptionThrown(params => this.onExceptionThrown(params)); + this._executionContextEventsProvider.onExecutionContextsCleared(() => this.clearTargetContext()); + this.chrome.Log.onEntryAdded(entry => this.onLogEntryAdded(entry)); this._chromeConnection.onClose(() => this.terminateSession('websocket closed')); - } - private async runAndMeasureProcessingTime(notificationName: string, procedure: () => Promise): Promise { - const startTime = Date.now(); - const startTimeMark = process.hrtime(); - let properties: IExecutionResultTelemetryProperties = { - startTime: startTime.toString() - }; + return this; + } + + // private async runAndMeasureProcessingTime(notificationName: string, procedure: () => Promise): Promise { + // const startTime = Date.now(); + // const startTimeMark = process.hrtime(); + // let properties: IExecutionResultTelemetryProperties = { + // startTime: startTime.toString() + // }; + + // try { + // return await procedure(); + // properties.successful = 'true'; + // } catch (e) { + // properties.successful = 'false'; + // properties.exceptionType = 'firstChance'; + // utils.fillErrorDetails(properties, e); + // throw e; + // } finally { + // const elapsedTime = utils.calculateElapsedTime(startTimeMark); + // properties.timeTakenInMilliseconds = elapsedTime.toString(); + + // // Callers set GDPR annotation + // this._batchTelemetryReporter.reportEvent(notificationName, properties); + // } + // } + + public onResumed(): void { + if (this._expectingResumedEvent) { + this._expectingResumedEvent = false; - try { - await procedure(); - properties.successful = 'true'; - } catch (e) { - properties.successful = 'false'; - properties.exceptionType = 'firstChance'; - utils.fillErrorDetails(properties, e); + // Need to wait to eval just a little after each step, because of #148 + this._waitAfterStep = utils.promiseTimeout(null, 50); + } else { + let resumedEvent = new ContinuedEvent(ChromeDebugLogic.THREAD_ID); + this._session.sendEvent(resumedEvent); } - - const elapsedTime = utils.calculateElapsedTime(startTimeMark); - properties.timeTakenInMilliseconds = elapsedTime.toString(); - - // Callers set GDPR annotation - this._batchTelemetryReporter.reportEvent(notificationName, properties); - } - - /** - * Enable clients and run connection - */ - protected runConnection(): Promise[] { - return [ - this.chrome.Console.enable() - .catch(e => { /* Specifically ignore a fail here since it's only for backcompat */ }), - utils.toVoidP(this.chrome.Debugger.enable()), - this.chrome.Runtime.enable(), - this.chrome.Log.enable() - .catch(e => { }), // Not supported by all runtimes - this._chromeConnection.run(), - ]; } - protected async doAttach(port: number, targetUrl?: string, address?: string, timeout?: number, websocketUrl?: string, extraCRDPChannelPort?: number): Promise { - /* __GDPR__FRAGMENT__ - "StepNames" : { - "Attach" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.events.emitStepStarted('Attach'); - // Client is attaching - if not attached to the chrome target, create a connection and attach - this._clientAttached = true; - if (!this._chromeConnection.isAttached) { - if (websocketUrl) { - await this._chromeConnection.attachToWebsocketUrl(websocketUrl, extraCRDPChannelPort); - } else { - await this._chromeConnection.attach(address, port, targetUrl, timeout, extraCRDPChannelPort); - } - - /* __GDPR__FRAGMENT__ - "StepNames" : { - "Attach.ConfigureDebuggingSession.Internal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.events.emitStepStarted('Attach.ConfigureDebuggingSession.Internal'); - - this._port = port; - - this.hookConnectionEvents(); - let patterns: string[] = []; - - if (this._launchAttachArgs.skipFiles) { - const skipFilesArgs = this._launchAttachArgs.skipFiles.filter(glob => { - if (glob.startsWith('!')) { - logger.warn(`Warning: skipFiles entries starting with '!' aren't supported and will be ignored. ("${glob}")`); - return false; - } - - return true; - }); - - patterns = skipFilesArgs.map(glob => utils.pathGlobToBlackboxedRegex(glob)); - } - - if (this._launchAttachArgs.skipFileRegExps) { - patterns = patterns.concat(this._launchAttachArgs.skipFileRegExps); - } - - /* __GDPR__FRAGMENT__ - "StepNames" : { - "Attach.ConfigureDebuggingSession.Target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.events.emitStepStarted('Attach.ConfigureDebuggingSession.Target'); - - // Make sure debugging domain is enabled before calling refreshBlackboxPatterns() below - await Promise.all(this.runConnection()); - - if (patterns.length) { - this._blackboxedRegexes = patterns.map(pattern => new RegExp(pattern, 'i')); - this.refreshBlackboxPatterns(); - } - - await this.initSupportedDomains(); - const maxDepth = this._launchAttachArgs.showAsyncStacks ? ChromeDebugAdapter.ASYNC_CALL_STACK_DEPTH : 0; - try { - await this.chrome.Debugger.setAsyncCallStackDepth({ maxDepth }); - } catch (e) { - // Not supported by older runtimes, ignore it. - } - - if (this._breakOnLoadHelper) { - this._breakOnLoadHelper.setBrowserVersion((await this._chromeConnection.version).browser); - } + public onConsoleAPICalled(event: ConsoleAPICalledEvent): void { + if (this._launchAttachArgs._suppressConsoleOutput) { + return; } - } - private async initSupportedDomains(): Promise { - try { - const domainResponse = await this.chrome.Schema.getDomains(); - domainResponse.domains.forEach(domain => this._domains.set(domain.name, domain)); - } catch (e) { - // If getDomains isn't supported for some reason, skip this + const result = formatConsoleArguments(event.type, event.args, event.stackTrace); + const stack = stackTraceWithoutLogpointFrame(event.stackTrace); + if (result) { + this.logObjects(result.args, result.isError, stack); } } - /** - * This event tells the client to begin sending setBP requests, etc. Some consumers need to override this - * to send it at a later time of their choosing. - */ - protected async sendInitializedEvent(): Promise { - // Wait to finish loading sourcemaps from the initial scriptParsed events - if (this._initialSourceMapsP) { - const initialSourceMapsP = this._initialSourceMapsP; - this._initialSourceMapsP = null; - - await initialSourceMapsP; - - this._session.sendEvent(new InitializedEvent()); - this.events.emitStepCompleted('NotifyInitialized'); - await Promise.all(this._earlyScripts.map(script => this.sendLoadedSourceEvent(script))); - this._earlyScripts = null; + private onLogEntryAdded(entry: LogEntry): void { + // The Debug Console doesn't give the user a way to filter by level, just ignore 'verbose' logs + if (entry.level === 'verbose') { + return; } - } - public doAfterProcessingSourceEvents(action: () => void): Promise { - return this._sourceLoadedQueue = this._sourceLoadedQueue.then(action); - } + const args = entry.args || []; - /** - * e.g. the target navigated - */ - protected onExecutionContextsCleared(): Promise { - const cachedScriptParsedEvents = Array.from(this._scriptsById.values()); - this.clearTargetContext(); - return this.doAfterProcessingSourceEvents(async () => { // This will not execute until all the on-flight 'new' source events have been processed - for (let scriptedParseEvent of cachedScriptParsedEvents) { - this.sendLoadedSourceEvent(scriptedParseEvent, 'removed'); + let text = entry.text || ''; + if (entry.url && !entry.stackTrace) { + if (text) { + text += ' '; } - }); - } - - protected async onPaused(notification: Crdp.Debugger.PausedEvent, expectingStopReason = this._expectingStopReason): Promise { - if (notification.asyncCallStackTraceId) { - await this.chrome.Debugger.pauseOnAsyncCall({ parentStackTraceId: notification.asyncCallStackTraceId }); - await this.chrome.Debugger.resume(); - return { didPause: false }; - } - this._variableHandles.onPaused(); - this._frameHandles.reset(); - this._exception = undefined; - this._lastPauseState = { event: notification, expecting: expectingStopReason }; - this._currentPauseNotification = notification; - - // If break on load is active, we pass the notification object to breakonload helper - // If it returns true, we continue and return - if (this.breakOnLoadActive) { - let shouldContinue = await this._breakOnLoadHelper.handleOnPaused(notification); - if (shouldContinue) { - this.chrome.Debugger.resume() - .catch(e => { - logger.error('Failed to resume due to exception: ' + e.message); - }); - return { didPause: false }; - } + text += `[${entry.url}]`; } - // We can tell when we've broken on an exception. Otherwise if hitBreakpoints is set, assume we hit a - // breakpoint. If not set, assume it was a step. We can't tell the difference between step and 'break on anything'. - let reason: ReasonType; - let shouldSmartStep = false; - if (notification.reason === 'exception') { - reason = 'exception'; - this._exception = notification.data; - } else if (notification.reason === 'promiseRejection') { - reason = 'promise_rejection'; - - // After processing smartStep and so on, check whether we are paused on a promise rejection, and should continue past it - if (this._promiseRejectExceptionFilterEnabled && !this._pauseOnPromiseRejections) { - this.chrome.Debugger.resume() - .catch(e => { /* ignore failures */ }); - return { didPause: false }; - } - - this._exception = notification.data; - } else if (notification.hitBreakpoints && notification.hitBreakpoints.length) { - reason = 'breakpoint'; - - // Did we hit a hit condition breakpoint? - for (let hitBp of notification.hitBreakpoints) { - if (this._hitConditionBreakpointsById.has(hitBp)) { - // Increment the hit count and check whether to pause - const hitConditionBp = this._hitConditionBreakpointsById.get(hitBp); - hitConditionBp.numHits++; - // Only resume if we didn't break for some user action (step, pause button) - if (!expectingStopReason && !hitConditionBp.shouldPause(hitConditionBp.numHits)) { - this.chrome.Debugger.resume() - .catch(e => { /* ignore failures */ }); - return { didPause: false }; - } - } - } - } else if (expectingStopReason) { - // If this was a step, check whether to smart step - reason = expectingStopReason; - shouldSmartStep = await this.shouldSmartStepCallFrame(this._currentPauseNotification.callFrames[0]); - } else { - reason = 'debugger_statement'; + if (text) { + args.unshift({ + type: 'string', + value: text + }); } - this._expectingStopReason = undefined; - - if (shouldSmartStep) { - this._smartStepCount++; - await this.stepIn(false); - return { didPause: false }; - } else { - if (this._smartStepCount > 0) { - logger.log(`SmartStep: Skipped ${this._smartStepCount} steps`); - this._smartStepCount = 0; - } - - // Enforce that the stopped event is not fired until we've sent the response to the step that induced it. - // Also with a timeout just to ensure things keep moving - const sendStoppedEvent = () => { - return this._session.sendEvent(new StoppedEvent2(reason, /*threadId=*/ChromeDebugAdapter.THREAD_ID, this._exception)); - }; - await utils.promiseTimeout(this._currentStep, /*timeoutMs=*/300) - .then(sendStoppedEvent, sendStoppedEvent); - - return { didPause: true }; + const type = entry.level === 'error' ? 'error' : + entry.level === 'warning' ? 'warning' : + 'log'; + const result = formatConsoleArguments(type, args, entry.stackTrace); + const stack = entry.stackTrace; + if (result) { + this.logObjects(result.args, result.isError, stack); } } - /* __GDPR__ - "ClientRequest/exceptionInfo" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public async exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): Promise { - if (args.threadId !== ChromeDebugAdapter.THREAD_ID) { - throw errors.invalidThread(args.threadId); - } + private async logObjects(objs: Crdp.Runtime.RemoteObject[], isError = false, stackTrace?: CodeFlowStackTrace): Promise { + // This is an asynchronous method, so ensure that we handle one at a time so that they are sent out in the same order that they came in. + this._currentLogMessage = this._currentLogMessage + .then(async () => { + const category = isError ? 'stderr' : 'stdout'; - if (this._exception) { - const isError = this._exception.subtype === 'error'; - const message = isError ? utils.firstLine(this._exception.description) : (this._exception.description || this._exception.value); - const formattedMessage = message && message.replace(/\*/g, '\\*'); - const response: IExceptionInfoResponseBody = { - exceptionId: this._exception.className || this._exception.type || 'Error', - breakMode: 'unhandled', - details: { - stackTrace: this._exception.description && await this.mapFormattedException(this._exception.description), - message, - formattedDescription: formattedMessage, // VS workaround - see https://github.com/Microsoft/vscode/issues/34259 - typeName: this._exception.subtype || this._exception.type + let location: LocationInLoadedSource = null; + if (stackTrace && stackTrace.codeFlowFrames.length) { + location = stackTrace.codeFlowFrames[0].location.mappedToSource(); } - }; - return response; - } else { - throw errors.noStoredException(); - } - } - - private async shouldSmartStepCallFrame(frame: Crdp.Debugger.CallFrame): Promise { - if (!this._smartStepEnabled) return Promise.resolve(false); - - const stackFrame = this.callFrameToStackFrame(frame); - return this.shouldSmartStep(stackFrame); - } - - private async shouldSmartStep(stackFrame: DebugProtocol.StackFrame): Promise { - const clientPath = this._pathTransformer.getClientPathFromTargetPath(stackFrame.source.path) || stackFrame.source.path; - const mapping = await this._sourceMapTransformer.mapToAuthored(clientPath, stackFrame.line, stackFrame.column); - if (mapping) { - return false; - } - - if ((await this.sourceMapTransformer.allSources(clientPath)).length) { - return true; - } - - return false; - } - - protected onResumed(): void { - this._currentPauseNotification = null; - - if (this._expectingResumedEvent) { - this._expectingResumedEvent = false; + // Shortcut the common log case to reduce unnecessary back and forth + if (objs.length === 1 && objs[0].type === 'string') { + let msg: string = objs[0].value; + if (isError) { + const stackTrace = await new FormattedExceptionParser(this._scriptsLogic, msg).parse(); + this._eventSender.sendExceptionThrown({ exceptionStackTrace: stackTrace, category, location }); + } else { + if (!msg.endsWith(clearConsoleCode)) { + // If this string will clear the console, don't append a \n + msg += '\n'; + } + this._eventSender.sendOutput({ output: msg, category, location }); + } + } else { + const variablesReference = this._variableHandles.create(new variables.LoggedObjects(objs), 'repl'); + this._eventSender.sendOutput({ output: 'output', category, variablesReference, location }); + } - // Need to wait to eval just a little after each step, because of #148 - this._waitAfterStep = utils.promiseTimeout(null, 50); - } else { - let resumedEvent = new ContinuedEvent(ChromeDebugAdapter.THREAD_ID); - this._session.sendEvent(resumedEvent); - } + }) + .catch(err => logger.error(err.toString())); } - private async detectColumnBreakpointSupport(scriptId: Crdp.Runtime.ScriptId): Promise { - this._columnBreakpointsEnabled = false; // So it isn't requested multiple times - try { - await this.chrome.Debugger.getPossibleBreakpoints({ - start: { scriptId, lineNumber: 0, columnNumber: 0 }, - end: { scriptId, lineNumber: 1, columnNumber: 0 }, - restrictToFunction: false - }); - this._columnBreakpointsEnabled = true; - } catch (e) { - this._columnBreakpointsEnabled = false; + protected async onExceptionThrown(params: ExceptionThrownEvent): Promise { + if (this._launchAttachArgs._suppressConsoleOutput) { + return; } - this._lineColTransformer.columnBreakpointsEnabled = this._columnBreakpointsEnabled; - } - - public getBreakpointsResolvedDefer(scriptId: string): PromiseDefer { - const existingValue = this._scriptIdToBreakpointsAreResolvedDefer.get(scriptId); - if (existingValue) { - return existingValue; - } else { - const newValue = promiseDefer(); - this._scriptIdToBreakpointsAreResolvedDefer.set(scriptId, newValue); - return newValue; - } - } + return this._currentLogMessage = this._currentLogMessage.then(async () => { + const formattedException = formatExceptionDetails(params.exceptionDetails); + const exceptionStackTrace = await new FormattedExceptionParser(this._scriptsLogic, formattedException).parse(); - protected async onScriptParsed(script: Crdp.Debugger.ScriptParsedEvent): Promise { - // The stack trace and hash can be large and the DA doesn't need it. - delete script.stackTrace; - delete script.hash; - - const breakpointsAreResolvedDefer = this.getBreakpointsResolvedDefer(script.scriptId); - try { - this.doAfterProcessingSourceEvents(async () => { // This will block future 'removed' source events, until this processing has been completed - if (typeof this._columnBreakpointsEnabled === 'undefined') { - await this.detectColumnBreakpointSupport(script.scriptId); - await this.sendInitializedEvent(); - } + let location: LocationInLoadedSource = null; + const stackTrace = params.exceptionDetails.stackTrace; + if (stackTrace && stackTrace.codeFlowFrames.length) { + location = stackTrace.codeFlowFrames[0].location.mappedToSource(); + } - if (this._earlyScripts) { - this._earlyScripts.push(script); - } else { - await this.sendLoadedSourceEvent(script); - } - }); - - if (script.url) { - script.url = utils.fixDriveLetter(script.url); - } else { - script.url = ChromeDebugAdapter.EVAL_NAME_PREFIX + script.scriptId; - } - - this._scriptsById.set(script.scriptId, script); - this._scriptsByUrl.set(utils.canonicalizeUrl(script.url), script); - - const mappedUrl = await this._pathTransformer.scriptParsed(script.url); - - const resolvePendingBPs = async (source: string) => { - source = source && utils.canonicalizeUrl(source); - const pendingBP = this._pendingBreakpointsByUrl.get(source); - if (pendingBP && (!pendingBP.setWithPath || utils.canonicalizeUrl(pendingBP.setWithPath) === source)) { - logger.log(`OnScriptParsed.resolvePendingBPs: Resolving pending breakpoints: ${JSON.stringify(pendingBP)}`); - await this.resolvePendingBreakpoint(pendingBP); - this._pendingBreakpointsByUrl.delete(source); - } else if (source) { - const sourceFileName = path.basename(source).toLowerCase(); - if (Array.from(this._pendingBreakpointsByUrl.keys()).find(key => key.toLowerCase().indexOf(sourceFileName) > -1)) { - logger.log(`OnScriptParsed.resolvePendingBPs: The following pending breakpoints won't be resolved: ${JSON.stringify(pendingBP)} pendingBreakpointsByUrl = ${JSON.stringify([...this._pendingBreakpointsByUrl])} source = ${source}`); - } - } - }; - - const sourceMapsP = this._sourceMapTransformer.scriptParsed(mappedUrl, script.sourceMapURL).then(async sources => { - if (this._hasTerminated) { - return undefined; - } - - if (sources) { - const filteredSources = sources.filter(source => source !== mappedUrl); // Tools like babel-register will produce sources with the same path as the generated script - for (const filteredSource of filteredSources) { - await resolvePendingBPs(filteredSource); - } - } - - if (script.url === mappedUrl && this._pendingBreakpointsByUrl.has(mappedUrl) && this._pendingBreakpointsByUrl.get(mappedUrl).setWithPath === mappedUrl) { - // If the pathTransformer had no effect, and we attempted to set the BPs with that path earlier, then assume that they are about - // to be resolved in this loaded script, and remove the pendingBP. - this._pendingBreakpointsByUrl.delete(mappedUrl); - } else { - await resolvePendingBPs(mappedUrl); - } - - await this.resolveSkipFiles(script, mappedUrl, sources); - }); - - if (this._initialSourceMapsP) { - this._initialSourceMapsP = >Promise.all([this._initialSourceMapsP, sourceMapsP]); - } - await sourceMapsP; - - breakpointsAreResolvedDefer.resolve(); // By now no matter which code path we choose, resolving pending breakpoints should be finished, so trigger the defer - } catch (exception) { - breakpointsAreResolvedDefer.reject(exception); - } - } - - protected async sendLoadedSourceEvent(script: Crdp.Debugger.ScriptParsedEvent, loadedSourceEventReason: LoadedSourceEventReason = 'new'): Promise { - const source = await this.scriptToSource(script); - - // This is a workaround for an edge bug, see https://github.com/Microsoft/vscode-chrome-debug-core/pull/329 - switch (loadedSourceEventReason) { - case 'new': - case 'changed': - if (this._loadedSourcesByScriptId.get(script.scriptId)) { - if (source.sourceReference) { - // We only need to send changed events for dynamic scripts. The client tracks files on storage on it's own, so this notification is not needed - loadedSourceEventReason = 'changed'; - } else { - return; // VS is strict about the changed notifications, and it will fail if we send a changed notification for a file on storage, so we omit it on purpose - } - } else { - loadedSourceEventReason = 'new'; - } - this._loadedSourcesByScriptId.set(script.scriptId, script); - break; - case 'removed': - if (!this._loadedSourcesByScriptId.delete(script.scriptId)) { - telemetry.reportEvent('LoadedSourceEventError', { issue: 'Tried to remove non-existent script', scriptId: script.scriptId }); - return; - } - break; - default: - telemetry.reportEvent('LoadedSourceEventError', { issue: 'Unknown reason', reason: loadedSourceEventReason }); - } - - const scriptEvent = new LoadedSourceEvent(loadedSourceEventReason, source as any); - - this._session.sendEvent(scriptEvent); - } - - private async resolveSkipFiles(script: CrdpScript, mappedUrl: string, sources: string[], toggling?: boolean): Promise { - if (sources && sources.length) { - const parentIsSkipped = this.shouldSkipSource(script.url); - const libPositions: Crdp.Debugger.ScriptPosition[] = []; - - // Figure out skip/noskip transitions within script - let inLibRange = parentIsSkipped; - for (let s of sources) { - let isSkippedFile = this.shouldSkipSource(s); - if (typeof isSkippedFile !== 'boolean') { - // Inherit the parent's status - isSkippedFile = parentIsSkipped; - } - - this._skipFileStatuses.set(s, isSkippedFile); - - if ((isSkippedFile && !inLibRange) || (!isSkippedFile && inLibRange)) { - const details = await this.sourceMapTransformer.allSourcePathDetails(mappedUrl); - const detail = details.find(d => d.inferredPath === s); - libPositions.push({ - lineNumber: detail.startPosition.line, - columnNumber: detail.startPosition.column - }); - inLibRange = !inLibRange; - } - } - - // If there's any change from the default, set proper blackboxed ranges - if (libPositions.length || toggling) { - if (parentIsSkipped) { - libPositions.splice(0, 0, { lineNumber: 0, columnNumber: 0}); - } - - if (libPositions[0].lineNumber !== 0 || libPositions[0].columnNumber !== 0) { - // The list of blackboxed ranges must start with 0,0 for some reason. - // https://github.com/Microsoft/vscode-chrome-debug/issues/667 - libPositions[0] = { - lineNumber: 0, - columnNumber: 0 - }; - } - - await this.chrome.Debugger.setBlackboxedRanges({ - scriptId: script.scriptId, - positions: [] - }).catch(() => this.warnNoSkipFiles()); - - if (libPositions.length) { - this.chrome.Debugger.setBlackboxedRanges({ - scriptId: script.scriptId, - positions: libPositions - }).catch(() => this.warnNoSkipFiles()); - } - } - } else { - const status = await this.getSkipStatus(mappedUrl); - const skippedByPattern = this.matchesSkipFilesPatterns(mappedUrl); - if (typeof status === 'boolean' && status !== skippedByPattern) { - const positions = status ? [{ lineNumber: 0, columnNumber: 0 }] : []; - this.chrome.Debugger.setBlackboxedRanges({ - scriptId: script.scriptId, - positions - }).catch(() => this.warnNoSkipFiles()); - } - } - } - - private warnNoSkipFiles(): void { - logger.log('Warning: this runtime does not support skipFiles'); - } - - /** - * If the source has a saved skip status, return that, whether true or false. - * If not, check it against the patterns list. - */ - private shouldSkipSource(sourcePath: string): boolean|undefined { - const status = this.getSkipStatus(sourcePath); - if (typeof status === 'boolean') { - return status; - } - - if (this.matchesSkipFilesPatterns(sourcePath)) { - return true; - } - - return undefined; - } - - /** - * Returns true if this path matches one of the static skip patterns - */ - private matchesSkipFilesPatterns(sourcePath: string): boolean { - return this._blackboxedRegexes.some(regex => { - return regex.test(sourcePath); - }); - } - - /** - * Returns the current skip status for this path, which is either an authored or generated script. - */ - private getSkipStatus(sourcePath: string): boolean|undefined { - if (this._skipFileStatuses.has(sourcePath)) { - return this._skipFileStatuses.get(sourcePath); - } - - return undefined; - } - - /* __GDPR__ - "ClientRequest/toggleSmartStep" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public async toggleSmartStep(): Promise { - this._smartStepEnabled = !this._smartStepEnabled; - this.onPaused(this._lastPauseState.event, this._lastPauseState.expecting); - } - - /* __GDPR__ - "ClientRequest/toggleSkipFileStatus" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public async toggleSkipFileStatus(args: IToggleSkipFileStatusArgs): Promise { - if (args.path) { - args.path = utils.fileUrlToPath(args.path); - } - - if (!await this.isInCurrentStack(args)) { - // Only valid for files that are in the current stack - const logName = args.path || this.displayNameForSourceReference(args.sourceReference); - logger.log(`Can't toggle the skipFile status for ${logName} - it's not in the current stack.`); - return; - } - - // e.g. strip / - if (args.path) { - args.path = this.displayPathToRealPath(args.path); - } - - const aPath = args.path || this.fakeUrlForSourceReference(args.sourceReference); - const generatedPath = await this._sourceMapTransformer.getGeneratedPathFromAuthoredPath(aPath); - if (!generatedPath) { - logger.log(`Can't toggle the skipFile status for: ${aPath} - haven't seen it yet.`); - return; - } - - const sources = await this._sourceMapTransformer.allSources(generatedPath); - if (generatedPath === aPath && sources.length) { - // Ignore toggling skip status for generated scripts with sources - logger.log(`Can't toggle skipFile status for ${aPath} - it's a script with a sourcemap`); - return; - } - - const newStatus = !this.shouldSkipSource(aPath); - logger.log(`Setting the skip file status for: ${aPath} to ${newStatus}`); - this._skipFileStatuses.set(aPath, newStatus); - - const targetPath = this._pathTransformer.getTargetPathFromClientPath(generatedPath) || generatedPath; - const script = this.getScriptByUrl(targetPath); - - await this.resolveSkipFiles(script, generatedPath, sources, /*toggling=*/true); - - if (newStatus) { - this.makeRegexesSkip(script.url); - } else { - this.makeRegexesNotSkip(script.url); - } - - this.onPaused(this._lastPauseState.event, this._lastPauseState.expecting); - } - - private async isInCurrentStack(args: IToggleSkipFileStatusArgs): Promise { - const currentStack = await this.stackTrace({ threadId: undefined }); - - if (args.path) { - return currentStack.stackFrames.some(frame => frame.source && frame.source.path === args.path); - } else { - return currentStack.stackFrames.some(frame => frame.source && frame.source.sourceReference === args.sourceReference); - } - } - - private makeRegexesNotSkip(noSkipPath: string): void { - let somethingChanged = false; - this._blackboxedRegexes = this._blackboxedRegexes.map(regex => { - const result = utils.makeRegexNotMatchPath(regex, noSkipPath); - somethingChanged = somethingChanged || (result !== regex); - return result; - }); - - if (somethingChanged) { - this.refreshBlackboxPatterns(); - } - } - - private makeRegexesSkip(skipPath: string): void { - let somethingChanged = false; - this._blackboxedRegexes = this._blackboxedRegexes.map(regex => { - const result = utils.makeRegexMatchPath(regex, skipPath); - somethingChanged = somethingChanged || (result !== regex); - return result; - }); - - if (!somethingChanged) { - this._blackboxedRegexes.push(new RegExp(utils.pathToRegex(skipPath), 'i')); - } - - this.refreshBlackboxPatterns(); - } - - private refreshBlackboxPatterns(): void { - this.chrome.Debugger.setBlackboxPatterns({ - patterns: this._blackboxedRegexes.map(regex => regex.source) - }).catch(() => this.warnNoSkipFiles()); - } - - /* __GDPR__ - "ClientRequest/loadedSources" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public async loadedSources(args: DebugProtocol.LoadedSourcesArguments): Promise { - const sources = await Promise.all(Array.from(this._scriptsByUrl.values()) - .map(script => this.scriptToSource(script))); - - return { sources: sources.sort((a, b) => a.path.localeCompare(b.path)) }; - } - - public resolvePendingBreakpoint(pendingBP: IPendingBreakpoint): Promise { - return this.setBreakpoints(pendingBP.args, null, pendingBP.requestSeq, pendingBP.ids).then(response => { - response.breakpoints.forEach((bp, i) => { - bp.id = pendingBP.ids[i]; - this._session.sendEvent(new BreakpointEvent('changed', bp)); - }); - }); - } - - protected onBreakpointResolved(params: Crdp.Debugger.BreakpointResolvedEvent): void { - const script = this._scriptsById.get(params.location.scriptId); - const breakpointId = this._breakpointIdHandles.lookup(params.breakpointId); - if (!script || !breakpointId) { - // Breakpoint resolved for a script we don't know about or a breakpoint we don't know about - return; - } - - // If the breakpoint resolved is a stopOnEntry breakpoint, we just return since we don't need to send it to client - if (this.breakOnLoadActive && this._breakOnLoadHelper.stopOnEntryBreakpointIdToRequestedFileName.has(params.breakpointId)) { - return; - } - - // committed breakpoints (this._committedBreakpointsByUrl) should always have url keys in canonicalized form - const committedBps = this.getValueFromCommittedBreakpointsByUrl(script.url) || []; - - if (!committedBps.find(committedBp => committedBp.breakpointId === params.breakpointId)) { - committedBps.push({breakpointId: params.breakpointId, actualLocation: params.location}); - } - this.setValueForCommittedBreakpointsByUrl(script.url, committedBps); - - const bp = { - id: breakpointId, - verified: true, - line: params.location.lineNumber, - column: params.location.columnNumber - }; - - // need to canonicalize this path because the following maps use paths canonicalized - const scriptPath = utils.canonicalizeUrl(this._pathTransformer.breakpointResolved(bp, script.url)); - - if (this._pendingBreakpointsByUrl.has(scriptPath)) { - // If we set these BPs before the script was loaded, remove from the pending list - this._pendingBreakpointsByUrl.delete(scriptPath); - } - this._sourceMapTransformer.breakpointResolved(bp, scriptPath); - this._lineColTransformer.breakpointResolved(bp); - this._session.sendEvent(new BreakpointEvent('changed', bp)); - } - - protected onConsoleAPICalled(event: Crdp.Runtime.ConsoleAPICalledEvent): void { - if (this._launchAttachArgs._suppressConsoleOutput) { - return; - } - - const result = formatConsoleArguments(event.type, event.args, event.stackTrace); - const stack = stackTraceWithoutLogpointFrame(event.stackTrace); - if (result) { - this.logObjects(result.args, result.isError, stack); - } - } - - private onLogEntryAdded(event: Crdp.Log.EntryAddedEvent): void { - // The Debug Console doesn't give the user a way to filter by level, just ignore 'verbose' logs - if (event.entry.level === 'verbose') { - return; - } - - const args = event.entry.args || []; - - let text = event.entry.text || ''; - if (event.entry.url && !event.entry.stackTrace) { - if (text) { - text += ' '; - } - - text += `[${event.entry.url}]`; - } - - if (text) { - args.unshift({ - type: 'string', - value: text - }); - } - - const type = event.entry.level === 'error' ? 'error' : - event.entry.level === 'warning' ? 'warning' : - 'log'; - const result = formatConsoleArguments(type, args, event.entry.stackTrace); - const stack = event.entry.stackTrace; - if (result) { - this.logObjects(result.args, result.isError, stack); - } - } - - private async logObjects(objs: Crdp.Runtime.RemoteObject[], isError = false, stackTrace?: Crdp.Runtime.StackTrace): Promise { - // This is an asynchronous method, so ensure that we handle one at a time so that they are sent out in the same order that they came in. - this._currentLogMessage = this._currentLogMessage - .then(async () => { - const category = isError ? 'stderr' : 'stdout'; - - // Shortcut the common log case to reduce unnecessary back and forth - let e: DebugProtocol.OutputEvent; - if (objs.length === 1 && objs[0].type === 'string') { - let msg: string = objs[0].value; - if (isError) { - msg = await this.mapFormattedException(msg); - } - - if (!msg.endsWith(clearConsoleCode)) { - // If this string will clear the console, don't append a \n - msg += '\n'; - } - - e = new OutputEvent(msg, category); - } else { - e = new OutputEvent('output', category); - e.body.variablesReference = this._variableHandles.create(new variables.LoggedObjects(objs), 'repl'); - } - - if (stackTrace && stackTrace.callFrames.length) { - const stackFrame = await this.mapCallFrame(stackTrace.callFrames[0]); - e.body.source = stackFrame.source; - e.body.line = stackFrame.line; - e.body.column = stackFrame.column; - } - - this._session.sendEvent(e); - }) - .catch(err => logger.error(err.toString())); - } - - protected async onExceptionThrown(params: Crdp.Runtime.ExceptionThrownEvent): Promise { - if (this._launchAttachArgs._suppressConsoleOutput) { - return; - } - - return this._currentLogMessage = this._currentLogMessage.then(async () => { - const formattedException = formatExceptionDetails(params.exceptionDetails); - const exceptionStr = await this.mapFormattedException(formattedException); - - const e: DebugProtocol.OutputEvent = new OutputEvent(exceptionStr + '\n', 'stderr'); - const stackTrace = params.exceptionDetails.stackTrace; - if (stackTrace && stackTrace.callFrames.length) { - const stackFrame = await this.mapCallFrame(stackTrace.callFrames[0]); - e.body.source = stackFrame.source; - e.body.line = stackFrame.line; - e.body.column = stackFrame.column; - } - - this._session.sendEvent(e); + this._eventSender.sendExceptionThrown({ exceptionStackTrace: exceptionStackTrace, category: 'stderr', location }); }) - .catch(err => logger.error(err.toString())); - } - - private async mapCallFrame(frame: Crdp.Runtime.CallFrame): Promise { - const debuggerCF = this.runtimeCFToDebuggerCF(frame); - const stackFrame = this.callFrameToStackFrame(debuggerCF); - await this._pathTransformer.fixSource(stackFrame.source); - await this._sourceMapTransformer.fixSourceLocation(stackFrame); - this._lineColTransformer.convertDebuggerLocationToClient(stackFrame); - return stackFrame; - } - - // We parse stack trace from `formattedException`, source map it and return a new string - protected async mapFormattedException(formattedException: string): Promise { - const exceptionLines = formattedException.split(/\r?\n/); - - for (let i = 0, len = exceptionLines.length; i < len; ++i) { - const line = exceptionLines[i]; - const matches = line.match(/^\s+at (.*?)\s*\(?([^ ]+):(\d+):(\d+)\)?$/); - - if (!matches) continue; - const linePath = matches[2]; - const lineNum = parseInt(matches[3], 10); - const adjustedLineNum = lineNum - 1; - const columnNum = parseInt(matches[4], 10); - const clientPath = this._pathTransformer.getClientPathFromTargetPath(linePath); - const mapped = await this._sourceMapTransformer.mapToAuthored(clientPath || linePath, adjustedLineNum, columnNum); - - if (mapped && mapped.source && utils.isNumber(mapped.line) && utils.isNumber(mapped.column) && utils.existsSync(mapped.source)) { - this._lineColTransformer.mappedExceptionStack(mapped); - exceptionLines[i] = exceptionLines[i].replace( - `${linePath}:${lineNum}:${columnNum}`, - `${mapped.source}:${mapped.line}:${mapped.column}`); - } else if (clientPath && clientPath !== linePath) { - const location = { line: adjustedLineNum, column: columnNum }; - this._lineColTransformer.mappedExceptionStack(location); - exceptionLines[i] = exceptionLines[i].replace( - `${linePath}:${lineNum}:${columnNum}`, - `${clientPath}:${location.line}:${location.column}`); - } - } - - return exceptionLines.join('\n'); - } - - /** - * For backcompat, also listen to Console.messageAdded, only if it looks like the old format. - */ - protected onMessageAdded(params: any): void { - // message.type is undefined when Runtime.consoleAPICalled is being sent - if (params && params.message && params.message.type) { - const onConsoleAPICalledParams: Crdp.Runtime.ConsoleAPICalledEvent = { - type: params.message.type, - timestamp: params.message.timestamp, - args: params.message.parameters || [{ type: 'string', value: params.message.text }], - stackTrace: params.message.stack, - executionContextId: 1 - }; - this.onConsoleAPICalled(onConsoleAPICalledParams); - } - } - - /* __GDPR__ - "ClientRequest/disconnect" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public disconnect(args: DebugProtocol.DisconnectArguments): void { - telemetry.reportEvent('FullSessionStatistics/SourceMaps/Overrides', { aspNetClientAppFallbackCount: sourceMapUtils.getAspNetFallbackCount() }); - this._clientRequestedSessionEnd = true; - this.shutdown(); - this.terminateSession('Got disconnect request', args); - } - - /* __GDPR__ - "ClientRequest/setBreakpoints" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public setBreakpoints(args: ISetBreakpointsArgs, _: ITelemetryPropertyCollector, requestSeq: number, ids?: number[]): Promise { - this.reportBpTelemetry(args); - if (args.source.path) { - args.source.path = this.displayPathToRealPath(args.source.path); - args.source.path = utils.canonicalizeUrl(args.source.path); - } - - return this.validateBreakpointsPath(args) - .then(() => { - // Deep copy the args that we are going to modify, and keep the original values in originalArgs - const originalArgs = args; - args = JSON.parse(JSON.stringify(args)); - args = this._lineColTransformer.setBreakpoints(args); - const sourceMapTransformerResponse = this._sourceMapTransformer.setBreakpoints(args, requestSeq, ids); - if (sourceMapTransformerResponse && sourceMapTransformerResponse.args) { - args = sourceMapTransformerResponse.args; - } - if (sourceMapTransformerResponse && sourceMapTransformerResponse.ids) { - ids = sourceMapTransformerResponse.ids; - } - args = this._pathTransformer.setBreakpoints(args); - - // Get the target url of the script - let targetScriptUrl: string; - if (args.source.sourceReference) { - const handle = this._sourceHandles.get(args.source.sourceReference); - if ((!handle || !handle.scriptId) && args.source.path) { - // A sourcemapped script with inline sources won't have a scriptId here, but the - // source.path has been fixed. - targetScriptUrl = args.source.path; - } else { - const targetScript = this._scriptsById.get(handle.scriptId); - if (targetScript) { - targetScriptUrl = targetScript.url; - } - } - } else if (args.source.path) { - targetScriptUrl = args.source.path; - } - - if (targetScriptUrl) { - // DebugProtocol sends all current breakpoints for the script. Clear all breakpoints for the script then add all of them - const internalBPs = args.breakpoints.map(bp => new InternalSourceBreakpoint(bp)); - const setBreakpointsPFailOnError = this._setBreakpointsRequestQ - .then(() => this.clearAllBreakpoints(targetScriptUrl)) - .then(() => this.addBreakpoints(targetScriptUrl, internalBPs)) - .then(responses => ({ breakpoints: this.targetBreakpointResponsesToBreakpointSetResults(targetScriptUrl, responses, internalBPs, ids) })); - - const setBreakpointsPTimeout = utils.promiseTimeout(setBreakpointsPFailOnError, ChromeDebugAdapter.SET_BREAKPOINTS_TIMEOUT, localize('setBPTimedOut', 'Set breakpoints request timed out')); - - // Do just one setBreakpointsRequest at a time to avoid interleaving breakpoint removed/breakpoint added requests to Crdp, which causes issues. - // Swallow errors in the promise queue chain so it doesn't get blocked, but return the failing promise for error handling. - this._setBreakpointsRequestQ = setBreakpointsPTimeout.catch(e => { - // Log the timeout, but any other error will be logged elsewhere - if (e.message && e.message.indexOf('timed out') >= 0) { - logger.error(e.stack); - } - }); - - // Return the setBP request, no matter how long it takes. It may take awhile in Node 7.5 - 7.7, see https://github.com/nodejs/node/issues/11589 - return setBreakpointsPFailOnError.then(setBpResultBody => { - const body = { breakpoints: setBpResultBody.breakpoints.map(setBpResult => setBpResult.breakpoint) }; - if (body.breakpoints.every(bp => !bp.verified)) { - // If all breakpoints are set, we mark them as set. If not, we mark them as un-set so they'll be set - const areAllSet = setBpResultBody.breakpoints.every(setBpResult => setBpResult.isSet); - // We need to send the original args to avoid adjusting the line and column numbers twice here - return this.unverifiedBpResponseForBreakpoints(originalArgs, requestSeq, targetScriptUrl, body.breakpoints, localize('bp.fail.unbound', 'Breakpoint set but not yet bound'), areAllSet); - } - this._sourceMapTransformer.setBreakpointsResponse(body, requestSeq); - this._lineColTransformer.setBreakpointsResponse(body); - return body; - }); - } else { - return Promise.resolve(this.unverifiedBpResponse(args, requestSeq, undefined, localize('bp.fail.noscript', "Can't find script for breakpoint request"))); - } - }, - e => this.unverifiedBpResponse(args, requestSeq, undefined, e.message)); - } - - private reportBpTelemetry(args: ISetBreakpointsArgs): void { - let fileExt = ''; - if (args.source.path) { - fileExt = path.extname(args.source.path); - } - - /* __GDPR__ - "setBreakpointsRequest" : { - "fileExt" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, - "${include}": [ "${DebugCommonProperties}" ] - } - */ - telemetry.reportEvent('setBreakpointsRequest', { fileExt }); - } - - protected validateBreakpointsPath(args: ISetBreakpointsArgs): Promise { - if (!args.source.path || args.source.sourceReference) return Promise.resolve(); - - // When break on load is active, we don't need to validate the path, so return - if (this.breakOnLoadActive) { - return Promise.resolve(); - } - - return this._sourceMapTransformer.getGeneratedPathFromAuthoredPath(args.source.path).then(mappedPath => { - - if (!mappedPath) { - return utils.errP(localize('validateBP.sourcemapFail', 'Breakpoint ignored because generated code not found (source map problem?).')); - } - - const targetPath = this._pathTransformer.getTargetPathFromClientPath(mappedPath); - if (!targetPath) { - return utils.errP(localize('validateBP.notFound', 'Breakpoint ignored because target path not found')); - } - - return undefined; - }); - } - - private generateNextUnboundBreakpointId(): string { - const unboundBreakpointUniquePrefix = '__::[vscode_chrome_debug_adapter_unbound_breakpoint]::'; - return `${unboundBreakpointUniquePrefix}${this._nextUnboundBreakpointId++}`; - } - - private unverifiedBpResponse(args: ISetBreakpointsArgs, requestSeq: number, targetScriptUrl: string, message?: string, bpsSet = false): ISetBreakpointsResponseBody { - const breakpoints = args.breakpoints.map(bp => { - return { - verified: false, - line: bp.line, - column: bp.column, - message, - id: this._breakpointIdHandles.create(this.generateNextUnboundBreakpointId()) - }; - }); - - return this.unverifiedBpResponseForBreakpoints(args, requestSeq, targetScriptUrl, breakpoints, message, bpsSet); - } - - private unverifiedBpResponseForBreakpoints(args: ISetBreakpointsArgs, requestSeq: number, targetScriptUrl: string, breakpoints: DebugProtocol.Breakpoint[], defaultMessage?: string, bpsSet = false): ISetBreakpointsResponseBody { - breakpoints.forEach(bp => { - if (!bp.message) { - bp.message = defaultMessage; - } - }); - - if (args.source.path) { - const ids = breakpoints.map(bp => bp.id); - - // setWithPath: record whether we attempted to set the breakpoint, and if so, with which path. - // We can use this to tell when the script is loaded whether we guessed correctly, and predict whether the BP will bind. - this._pendingBreakpointsByUrl.set( - utils.canonicalizeUrl(args.source.path), - { args, ids, requestSeq, setWithPath: this.breakOnLoadActive ? '' : targetScriptUrl }); // Breakpoints need to be re-set when break-on-load is enabled - } - - return { breakpoints }; - } - - private clearAllBreakpoints(url: string): Promise { - // We want to canonicalize this url because this._committedBreakpointsByUrl keeps url keys in canonicalized form - url = utils.canonicalizeUrl(url); - if (!this._committedBreakpointsByUrl.has(url)) { - return Promise.resolve(); - } - - // Remove breakpoints one at a time. Seems like it would be ok to send the removes all at once, - // but there is a chrome bug where when removing 5+ or so breakpoints at once, it gets into a weird - // state where later adds on the same line will fail with 'breakpoint already exists' even though it - // does not break there. - return this._committedBreakpointsByUrl.get(url).reduce((p, bp) => { - return p.then(() => this.chrome.Debugger.removeBreakpoint({ breakpointId: bp.breakpointId })).then(() => { }); - }, Promise.resolve()).then(() => { - this._committedBreakpointsByUrl.delete(url); - }); - } - - /** - * Makes the actual call to either Debugger.setBreakpoint or Debugger.setBreakpointByUrl, and returns the response. - * Responses from setBreakpointByUrl are transformed to look like the response from setBreakpoint, so they can be - * handled the same. - */ - protected async addBreakpoints(url: string, breakpoints: InternalSourceBreakpoint[]): Promise { - let responsePs: Promise[]; - if (ChromeUtils.isEvalScript(url)) { - // eval script with no real url - use debugger_setBreakpoint - const scriptId: Crdp.Runtime.ScriptId = utils.lstrip(url, ChromeDebugAdapter.EVAL_NAME_PREFIX); - responsePs = breakpoints.map(({ line, column = 0, condition }, i) => this.chrome.Debugger.setBreakpoint({ location: { scriptId, lineNumber: line, columnNumber: column }, condition })); - } else { - // script that has a url - use debugger_setBreakpointByUrl so that Chrome will rebind the breakpoint immediately - // after refreshing the page. This is the only way to allow hitting breakpoints in code that runs immediately when - // the page loads. - const script = this.getScriptByUrl(url); - - // If script has been parsed, script object won't be undefined and we would have the mapping file on the disk and we can directly set breakpoint using that - if (!this.breakOnLoadActive || script) { - const urlRegex = utils.pathToRegex(url); - responsePs = breakpoints.map(({ line, column = 0, condition }, i) => { - return this.addOneBreakpointByUrl(script && script.scriptId, urlRegex, line, column, condition); - }); - } else { // Else if script hasn't been parsed and break on load is active, we need to do extra processing - if (this.breakOnLoadActive) { - return await this._breakOnLoadHelper.handleAddBreakpoints(url, breakpoints); - } - } - } - - // Join all setBreakpoint requests to a single promise - return Promise.all(responsePs); - } - - private async addOneBreakpointByUrl(scriptId: Crdp.Runtime.ScriptId | undefined, urlRegex: string, lineNumber: number, columnNumber: number, condition: string): Promise { - let bpLocation = { lineNumber, columnNumber }; - if (this._columnBreakpointsEnabled && scriptId) { // scriptId undefined when script not yet loaded, can't fix up column BP :( - try { - const possibleBpResponse = await this.chrome.Debugger.getPossibleBreakpoints({ - start: { scriptId, lineNumber, columnNumber: 0 }, - end: { scriptId, lineNumber: lineNumber + 1, columnNumber: 0 }, - restrictToFunction: false }); - if (possibleBpResponse.locations.length) { - const selectedLocation = ChromeUtils.selectBreakpointLocation(lineNumber, columnNumber, possibleBpResponse.locations); - bpLocation = { lineNumber: selectedLocation.lineNumber, columnNumber: selectedLocation.columnNumber || 0 }; - } - } catch (e) { - // getPossibleBPs not supported - } - } - - let result; - try { - result = await this.chrome.Debugger.setBreakpointByUrl({ urlRegex, lineNumber: bpLocation.lineNumber, columnNumber: bpLocation.columnNumber, condition }); - } catch (e) { - if (e.message === 'Breakpoint at specified location already exists.') { - return { - actualLocation: { lineNumber: bpLocation.lineNumber, columnNumber: bpLocation.columnNumber, scriptId } - }; - } else { - throw e; - } - } - - // Now convert the response to a SetBreakpointResponse so both response types can be handled the same - const locations = result.locations; - return { - breakpointId: result.breakpointId, - actualLocation: locations[0] && { - lineNumber: locations[0].lineNumber, - columnNumber: locations[0].columnNumber, - scriptId - } - }; - } - - private targetBreakpointResponsesToBreakpointSetResults(url: string, responses: ISetBreakpointResult[], requestBps: InternalSourceBreakpoint[], ids?: number[]): BreakpointSetResult[] { - // Don't cache errored responses - const committedBps = responses - .filter(response => response && response.breakpointId); - - // Cache successfully set breakpoint ids from chrome in committedBreakpoints set - this.setValueForCommittedBreakpointsByUrl(url, committedBps); - - // Map committed breakpoints to DebugProtocol response breakpoints - return responses - .map((response, i) => { - // The output list needs to be the same length as the input list, so map errors to - // unverified breakpoints. - if (!response) { - return { - isSet: false, - breakpoint: { - verified: false - } - }; - } - - // response.breakpointId is undefined when no target BP is backing this BP, e.g. it's at the same location - // as another BP - const responseBpId = response.breakpointId || this.generateNextUnboundBreakpointId(); - - let bpId: number; - if (ids && ids[i]) { - // IDs passed in for previously unverified BPs - bpId = ids[i]; - this._breakpointIdHandles.set(bpId, responseBpId); - } else { - bpId = this._breakpointIdHandles.lookup(responseBpId) || - this._breakpointIdHandles.create(responseBpId); - } - - if (!response.actualLocation) { - // If we don't have an actualLocation nor a breakpointId this is a pseudo-breakpoint because we are using break-on-load - // so we mark the breakpoint as not set, so i'll be set after we load the actual script that has the breakpoint - return { - isSet: response.breakpointId !== undefined, - breakpoint: { - id: bpId, - verified: false - } - }; - } - - const thisBpRequest = requestBps[i]; - if (thisBpRequest.hitCondition) { - if (!this.addHitConditionBreakpoint(thisBpRequest, response)) { - return { - isSet: true, - breakpoint: { - id: bpId, - message: localize('invalidHitCondition', 'Invalid hit condition: {0}', thisBpRequest.hitCondition), - verified: false - } - }; - } - } + .catch(err => logger.error(err.toString())); + } - return { - isSet: true, - breakpoint: { - id: bpId, - verified: true, - line: response.actualLocation.lineNumber, - column: response.actualLocation.columnNumber - } - }; - }); + /** + * For backcompat, also listen to Console.messageAdded, only if it looks like the old format. + */ + protected onMessageAdded(params: any): void { + // message.type is undefined when Runtime.consoleAPICalled is being sent + if (params && params.message && params.message.type) { + const onConsoleAPICalledParams: ConsoleAPICalledEvent = { + type: params.message.type, + timestamp: params.message.timestamp, + args: params.message.parameters || [{ type: 'string', value: params.message.text }], + stackTrace: params.message.stack, + executionContextId: 1 + }; + this.onConsoleAPICalled(onConsoleAPICalledParams); + } } - private addHitConditionBreakpoint(requestBp: InternalSourceBreakpoint, response: ISetBreakpointResult): boolean { - const result = ChromeDebugAdapter.HITCONDITION_MATCHER.exec(requestBp.hitCondition.trim()); - if (result && result.length >= 3) { - let op = result[1] || '>='; - if (op === '=') op = '=='; - const value = result[2]; - const expr = op === '%' - ? `return (numHits % ${value}) === 0;` - : `return numHits ${op} ${value};`; - - // eval safe because of the regex, and this is only a string that the current user will type in - /* tslint:disable:no-function-constructor-with-string-args */ - const shouldPause: (numHits: number) => boolean = new Function('numHits', expr); - /* tslint:enable:no-function-constructor-with-string-args */ - this._hitConditionBreakpointsById.set(response.breakpointId, { numHits: 0, shouldPause }); - return true; - } else { - return false; + /* __GDPR__ + "ClientRequest/disconnect" : { + "${include}": [ + "${IExecutionResultTelemetryProperties}", + "${DebugCommonProperties}" + ] } + */ + public disconnect(): void { + telemetry.reportEvent('FullSessionStatistics/SourceMaps/Overrides', { aspNetClientAppFallbackCount: sourceMapUtils.getAspNetFallbackCount() }); + this.shutdown(); + this.terminateSession('Got disconnect request'); } /* __GDPR__ @@ -1795,127 +509,10 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { .then(() => { }); } - /* __GDPR__ - "ClientRequest/continue" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - /** - * internal -> suppress telemetry - */ - public continue(internal = false): Promise { - /* __GDPR__ - "continueRequest" : { - "${include}": [ "${DebugCommonProperties}" ] - } - */ - if (!internal) telemetry.reportEvent('continueRequest'); - if (!this.chrome) { - return utils.errP(errors.runtimeNotConnectedMsg); - } - - this._expectingResumedEvent = true; - return this._currentStep = this.chrome.Debugger.resume() - .then(() => { /* make void */ }, - e => { /* ignore failures - client can send the request when the target is no longer paused */ }); - } - - /* __GDPR__ - "ClientRequest/next" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public next(): Promise { - if (!this.chrome) { - return utils.errP(errors.runtimeNotConnectedMsg); - } - - /* __GDPR__ - "nextRequest" : { - "${include}": [ "${DebugCommonProperties}" ] - } - */ - telemetry.reportEvent('nextRequest'); - this._expectingStopReason = 'step'; - this._expectingResumedEvent = true; - return this._currentStep = this.chrome.Debugger.stepOver() - .then(() => { /* make void */ }, - e => { /* ignore failures - client can send the request when the target is no longer paused */ }); - } - - /* __GDPR__ - "ClientRequest/stepIn" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public stepIn(userInitiated = true): Promise { - if (!this.chrome) { - return utils.errP(errors.runtimeNotConnectedMsg); - } - - if (userInitiated) { - /* __GDPR__ - "stepInRequest" : { - "${include}": [ "${DebugCommonProperties}" ] - } - */ - telemetry.reportEvent('stepInRequest'); - } - - this._expectingStopReason = 'step'; - this._expectingResumedEvent = true; - return this._currentStep = this.chrome.Debugger.stepInto({ breakOnAsyncCall: true }) - .then(() => { /* make void */ }, - e => { /* ignore failures - client can send the request when the target is no longer paused */ }); - } - - /* __GDPR__ - "ClientRequest/stepOut" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public stepOut(): Promise { - if (!this.chrome) { - return utils.errP(errors.runtimeNotConnectedMsg); - } - - /* __GDPR__ - "stepOutRequest" : { - "${include}": [ "${DebugCommonProperties}" ] - } - */ - telemetry.reportEvent('stepOutRequest'); - this._expectingStopReason = 'step'; - this._expectingResumedEvent = true; - return this._currentStep = this.chrome.Debugger.stepOut() - .then(() => { /* make void */ }, - e => { /* ignore failures - client can send the request when the target is no longer paused */ }); - } - - /* __GDPR__ - "ClientRequest/stepBack" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ public stepBack(): Promise { - return (this.chrome).TimeTravel.stepBack() + return (this._chromeConnection.api).TimeTravel.stepBack() .then(() => { /* make void */ }, - e => { /* ignore failures - client can send the request when the target is no longer paused */ }); + () => { }); } /* __GDPR__ @@ -1927,215 +524,12 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { } */ public reverseContinue(): Promise { - return (this.chrome).TimeTravel.reverse() + return (this._chromeConnection.api).TimeTravel.reverse() .then(() => { /* make void */ }, - e => { /* ignore failures - client can send the request when the target is no longer paused */ }); - } - - /* __GDPR__ - "ClientRequest/pause" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public pause(): Promise { - if (!this.chrome) { - return utils.errP(errors.runtimeNotConnectedMsg); - } - - /* __GDPR__ - "pauseRequest" : { - "${include}": [ "${DebugCommonProperties}" ] - } - */ - telemetry.reportEvent('pauseRequest'); - this._expectingStopReason = 'pause'; - return this._currentStep = this.chrome.Debugger.pause() - .then(() => { }); - } - - /* __GDPR__ - "ClientRequest/stackTrace" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public async stackTrace(args: DebugProtocol.StackTraceArguments): Promise { - if (!this._currentPauseNotification) { - return Promise.reject(errors.noCallStackAvailable()); - } - - let stackFrames = this._currentPauseNotification.callFrames.map(frame => this.callFrameToStackFrame(frame)) - .concat(this.asyncFrames(this._currentPauseNotification.asyncStackTrace)); - - const totalFrames = stackFrames.length; - if (typeof args.startFrame === 'number') { - stackFrames = stackFrames.slice(args.startFrame); - } - - if (typeof args.levels === 'number') { - stackFrames = stackFrames.slice(0, args.levels); - } - - const stackTraceResponse: IInternalStackTraceResponseBody = { - stackFrames, - totalFrames - }; - this._pathTransformer.stackTraceResponse(stackTraceResponse); - await this._sourceMapTransformer.stackTraceResponse(stackTraceResponse); - this._lineColTransformer.stackTraceResponse(stackTraceResponse); - - await Promise.all(stackTraceResponse.stackFrames.map(async (frame, i) => { - // Remove isSourceMapped to convert back to DebugProtocol.StackFrame - delete frame.isSourceMapped; - - if (!frame.source) { - return; - } - - // Apply hints to skipped frames - const getSkipReason = reason => localize('skipReason', "(skipped by '{0}')", reason); - if (frame.source.path && this.shouldSkipSource(frame.source.path)) { - frame.source.origin = (frame.source.origin ? frame.source.origin + ' ' : '') + getSkipReason('skipFiles'); - frame.source.presentationHint = 'deemphasize'; - } else if (await this.shouldSmartStep(frame)) { - frame.source.origin = (frame.source.origin ? frame.source.origin + ' ' : '') + getSkipReason('smartStep'); - frame.source.presentationHint = 'deemphasize'; - } - - // Allow consumer to adjust final path - if (frame.source.path && frame.source.sourceReference) { - frame.source.path = this.realPathToDisplayPath(frame.source.path); - } - - // And finally, remove the fake eval path and fix the name, if it was never resolved to a real path - if (frame.source.path && ChromeUtils.isEvalScript(frame.source.path)) { - frame.source.path = undefined; - frame.source.name = this.displayNameForSourceReference(frame.source.sourceReference); - } - - // Format stackframe name - frame.name = this.formatStackFrameName(frame, args.format); - })); - - return stackTraceResponse; - } - - private asyncFrames(stackTrace: Crdp.Runtime.StackTrace): DebugProtocol.StackFrame[] { - if (stackTrace) { - const frames = stackTrace.callFrames - .map(frame => this.runtimeCFToDebuggerCF(frame)) - .map(frame => this.callFrameToStackFrame(frame)); - - frames.unshift({ - id: this._frameHandles.create(null), - name: `[ ${stackTrace.description} ]`, - source: undefined, - line: undefined, - column: undefined, - presentationHint: 'label' - }); - - return frames.concat(this.asyncFrames(stackTrace.parent)); - } else { - return []; - } - } - - private runtimeCFToDebuggerCF(frame: Crdp.Runtime.CallFrame): Crdp.Debugger.CallFrame { - return { - callFrameId: undefined, - scopeChain: undefined, - this: undefined, - location: { - lineNumber: frame.lineNumber, - columnNumber: frame.columnNumber, - scriptId: frame.scriptId - }, - url: frame.url, - functionName: frame.functionName - }; - } - - private async scriptToSource(script: Crdp.Debugger.ScriptParsedEvent): Promise { - const sourceReference = this.getSourceReferenceForScriptId(script.scriptId); - const origin = this.getReadonlyOrigin(script.url); - - const properlyCasedScriptUrl = utils.canonicalizeUrl(script.url); - const displayPath = this.realPathToDisplayPath(properlyCasedScriptUrl); - - const exists = await utils.existsAsync(properlyCasedScriptUrl); // script.url can start with file:/// so we use the canonicalized version - return { - name: path.basename(displayPath), - path: displayPath, - // if the path exists, do not send the sourceReference - sourceReference: exists ? undefined : sourceReference, - origin - }; - } - - private formatStackFrameName(frame: DebugProtocol.StackFrame, formatArgs?: DebugProtocol.StackFrameFormat): string { - let formattedName = frame.name; - if (formatArgs) { - if (formatArgs.module) { - formattedName += ` [${frame.source.name}]`; - } - - if (formatArgs.line) { - formattedName += ` Line ${frame.line}`; - } - } - - return formattedName; - } - - private callFrameToStackFrame(frame: Crdp.Debugger.CallFrame): DebugProtocol.StackFrame { - const { location, functionName } = frame; - const line = location.lineNumber; - const column = location.columnNumber; - const script = this._scriptsById.get(location.scriptId); - - try { - // When the script has a url and isn't one we're ignoring, send the name and path fields. PathTransformer will - // attempt to resolve it to a script in the workspace. Otherwise, send the name and sourceReference fields. - const sourceReference = this.getSourceReferenceForScriptId(script.scriptId); - const origin = this.getReadonlyOrigin(script.url); - const source: DebugProtocol.Source = { - name: path.basename(script.url), - path: script.url, - sourceReference, - origin - }; - - // If the frame doesn't have a function name, it's either an anonymous function - // or eval script. If its source has a name, it's probably an anonymous function. - const frameName = functionName || (script.url ? '(anonymous function)' : '(eval code)'); - return { - id: this._frameHandles.create(frame), - name: frameName, - source, - line, - column - }; - } catch (e) { - // Some targets such as the iOS simulator behave badly and return nonsense callFrames. - // In these cases, return a dummy stack frame - const evalUnknown = `${ChromeDebugAdapter.EVAL_NAME_PREFIX}_Unknown`; - return { - id: this._frameHandles.create({ }), - name: evalUnknown, - source: { name: evalUnknown, path: evalUnknown }, - line, - column - }; - } + () => { }); } - protected getReadonlyOrigin(url: string): string { + public getReadonlyOrigin(): string { // To override return undefined; } @@ -2144,30 +538,14 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { * Called when returning a stack trace, for the path for Sources that have a sourceReference, so consumers can * tweak it, since it's only for display. */ - protected realPathToDisplayPath(realPath: string): string { + protected realPathToDisplayPath(realPath: IResourceIdentifier): IResourceIdentifier { if (ChromeUtils.isEvalScript(realPath)) { - return `${ChromeDebugAdapter.EVAL_ROOT}/${realPath}`; + return parseResourceIdentifier(`${ChromeDebugLogic.EVAL_ROOT}/${realPath}`); } return realPath; } - protected displayPathToRealPath(displayPath: string): string { - if (displayPath.startsWith(ChromeDebugAdapter.EVAL_ROOT)) { - return displayPath.substr(ChromeDebugAdapter.EVAL_ROOT.length + 1); // Trim "/" - } - - return displayPath; - } - - /** - * Get the existing handle for this script, identified by runtime scriptId, or create a new one - */ - private getSourceReferenceForScriptId(scriptId: Crdp.Runtime.ScriptId): number { - return this._sourceHandles.lookupF(container => container.scriptId === scriptId) || - this._sourceHandles.create({ scriptId }); - } - /* __GDPR__ "ClientRequest/scopes" : { "${include}": [ @@ -2176,26 +554,23 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { ] } */ - public scopes(args: DebugProtocol.ScopesArguments): IScopesResponseBody { - const currentFrame = this._frameHandles.get(args.frameId); - if (!currentFrame || !currentFrame.location || !currentFrame.callFrameId) { + public scopes(currentFrame: ICallFrame): IScopesResponseBody { + if (!currentFrame || !currentFrame.location) { throw errors.stackFrameNotValid(); } - if (!currentFrame.callFrameId) { - return { scopes: [] }; - } + const scriptCallFrame = currentFrame.unmappedCallFrame; - const currentScript = this._scriptsById.get(currentFrame.location.scriptId); - const currentScriptUrl = currentScript && currentScript.url; - const currentScriptPath = (currentScriptUrl && this._pathTransformer.getClientPathFromTargetPath(currentScriptUrl)) || currentScriptUrl; + const currentScript = scriptCallFrame.location.script; + const currentScriptUrl = currentScript.runtimeSource.identifier.textRepresentation; + const currentScriptPath = currentScriptUrl; - const scopes = currentFrame.scopeChain.map((scope: Crdp.Debugger.Scope, i: number) => { + const scopes = currentFrame.scopeChain.map((scope, i) => { // The first scope should include 'this'. Keep the RemoteObject reference for use by the variables request - const thisObj = i === 0 && currentFrame.this; + const thisObj = i === 0 && currentFrame.frameThis; const returnValue = i === 0 && currentFrame.returnValue; const variablesReference = this._variableHandles.create( - new ScopeContainer(currentFrame.callFrameId, i, scope.object.objectId, thisObj, returnValue)); + new ScopeContainer(currentFrame, i, scope.object.objectId, thisObj, returnValue)); const resultScope = { name: scope.type.substr(0, 1).toUpperCase() + scope.type.substr(1), // Take Chrome's scope, uppercase the first letter @@ -2213,7 +588,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { return resultScope; }); - if (this._exception && this.lookupFrameIndex(args.frameId) === 0) { + if (this._exception && currentFrame.index === 0) { scopes.unshift({ name: localize('scope.exception', 'Exception'), variablesReference: this._variableHandles.create(ExceptionContainer.create(this._exception)) @@ -2229,18 +604,6 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { return scopesResponse; } - /** - * Try to lookup the index of the frame with given ID. Returns -1 for async frames and unknown frames. - */ - private lookupFrameIndex(frameId: number): number { - const currentFrame = this._frameHandles.get(frameId); - if (!currentFrame || !currentFrame.callFrameId || !this._currentPauseNotification) { - return -1; - } - - return this._currentPauseNotification.callFrames.findIndex(frame => frame.callFrameId === currentFrame.callFrameId); - } - /* __GDPR__ "ClientRequest/variables" : { "${include}": [ @@ -2275,7 +638,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { let response: Crdp.Runtime.CallFunctionOnResponse; try { - response = await this.chrome.Runtime.callFunctionOn({ + response = await this._inspectDebugeeState.callFunctionOn({ objectId: owningObjectId, functionDeclaration: grabGetterValue, arguments: [{ value: propDesc.name }] @@ -2352,10 +715,10 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { } private getRuntimeProperties(params: Crdp.Runtime.GetPropertiesRequest): Promise { - return this.chrome.Runtime.getProperties(params) + return this._inspectDebugeeState.getProperties(params) .catch(err => { if (err.message.startsWith('Cannot find context with specified id')) { - // Hack to ignore this error until we fix https://github.com/Microsoft/vscode/issues/18001 to not request variables at unexpected times. + // Hack to ignore this error until we fix https://github.com/Microsoft/client/issues/18001 to not request variables at unexpected times. return null; } else { throw err; @@ -2389,7 +752,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { } private getFilteredVariablesForObjectId(objectId: string, evaluateName: string, getVarsFn: string, filter: string, start: number, count: number): Promise { - return this.chrome.Runtime.callFunctionOn({ + return this._inspectDebugeeState.callFunctionOn({ objectId, functionDeclaration: getVarsFn, arguments: [{ value: start }, { value: count }], @@ -2405,60 +768,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { .then(variables => variables.filter(variable => isIndexedPropName(variable.name))); } }, - error => Promise.reject(errors.errorFromEvaluate(error.message))); - } - - /* __GDPR__ - "ClientRequest/source" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public source(args: DebugProtocol.SourceArguments): Promise { - let scriptId: Crdp.Runtime.ScriptId; - if (args.sourceReference) { - const handle = this._sourceHandles.get(args.sourceReference); - if (!handle) { - return Promise.reject(errors.sourceRequestIllegalHandle()); - } - - // Have inlined content? - if (handle.contents) { - return Promise.resolve({ - content: handle.contents - }); - } - - scriptId = handle.scriptId; - } else if (args.source && args.source.path) { - const realPath = this.displayPathToRealPath(args.source.path); - - // Request url has chars unescaped, but they will be escaped in scriptsByUrl - const script = this.getScriptByUrl( - utils.isURL(realPath) ? - encodeURI(realPath) : - realPath); - - if (!script) { - return Promise.reject(errors.sourceRequestCouldNotRetrieveContent()); - } - - scriptId = script.scriptId; - } - - if (!scriptId) { - return Promise.reject(errors.sourceRequestCouldNotRetrieveContent()); - } - - // If not, should have scriptId - return this.chrome.Debugger.getScriptSource({ scriptId }).then(response => { - return { - content: response.scriptSource, - mimeType: 'text/javascript' - }; - }); + error => Promise.reject(errors.errorFromEvaluate(error.message))); } /* __GDPR__ @@ -2473,7 +783,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { return { threads: [ { - id: ChromeDebugAdapter.THREAD_ID, + id: ChromeDebugLogic.THREAD_ID, name: this.threadName() } ] @@ -2481,7 +791,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { } protected threadName(): string { - return 'Thread ' + ChromeDebugAdapter.THREAD_ID; + return 'Thread ' + ChromeDebugLogic.THREAD_ID; } /* __GDPR__ @@ -2492,23 +802,19 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { ] } */ - public async evaluate(args: DebugProtocol.EvaluateArguments): Promise { + public async evaluate(args: EvaluateArguments): Promise { if (!this.chrome) { return utils.errP(errors.runtimeNotConnectedMsg); } - if (args.expression.startsWith(ChromeDebugAdapter.SCRIPTS_COMMAND)) { - return this.handleScriptsCommand(args); - } - - if (args.expression.startsWith('{') && args.expression.endsWith('}')) { - args.expression = `(${args.expression})`; - } + const expression = args.expression.startsWith('{') && args.expression.endsWith('}') + ? `(${args.expression})` + : args.expression; - const evalResponse = await this.waitThenDoEvaluate(args.expression, args.frameId, { generatePreview: true }); + const evalResponse = await this.waitThenDoEvaluate(expression, args.frame, { generatePreview: true }); // Convert to a Variable object then just copy the relevant fields off - const variable = await this.remoteObjectToVariable(args.expression, evalResponse.result, /*parentEvaluateName=*/undefined, /*stringify=*/undefined, args.context); + const variable = await this.remoteObjectToVariable(expression, evalResponse.result, /*parentEvaluateName=*/undefined, /*stringify=*/undefined, args.context); if (evalResponse.exceptionDetails) { let resultValue = variable.value; if (resultValue && (resultValue.startsWith('ReferenceError: ') || resultValue.startsWith('TypeError: ')) && args.context !== 'repl') { @@ -2527,78 +833,22 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { }; } - /** - * Handle the .scripts command, which can be used as `.scripts` to return a list of all script details, - * or `.scripts ` to show the contents of the given script. - */ - private handleScriptsCommand(args: DebugProtocol.EvaluateArguments): Promise { - let outputStringP: Promise; - const scriptsRest = utils.lstrip(args.expression, ChromeDebugAdapter.SCRIPTS_COMMAND).trim(); - if (scriptsRest) { - // `.scripts ` was used, look up the script by url - const requestedScript = this.getScriptByUrl(scriptsRest); - if (requestedScript) { - outputStringP = this.chrome.Debugger.getScriptSource({ scriptId: requestedScript.scriptId }) - .then(result => { - const maxLength = 1e5; - return result.scriptSource.length > maxLength ? - result.scriptSource.substr(0, maxLength) + '[⋯]' : - result.scriptSource; - }); - } else { - outputStringP = Promise.resolve(`No runtime script with url: ${scriptsRest}\n`); - } - } else { - outputStringP = this.getAllScriptsString(); - } - - return outputStringP.then(scriptsStr => { - this._session.sendEvent(new OutputEvent(scriptsStr)); - return { - result: '', - variablesReference: 0 - }; - }); - } - - private getAllScriptsString(): Promise { - const runtimeScripts = Array.from(this._scriptsByUrl.keys()) - .sort(); - return Promise.all(runtimeScripts.map(script => this.getOneScriptString(script))).then(strs => { - return strs.join('\n'); - }); - } - - private getOneScriptString(runtimeScriptPath: string): Promise { - let result = '› ' + runtimeScriptPath; - const clientPath = this._pathTransformer.getClientPathFromTargetPath(runtimeScriptPath); - if (clientPath && clientPath !== runtimeScriptPath) result += ` (${clientPath})`; - - return this._sourceMapTransformer.allSourcePathDetails(clientPath || runtimeScriptPath).then(sourcePathDetails => { - let mappedSourcesStr = sourcePathDetails.map(details => ` - ${details.originalPath} (${details.inferredPath})`).join('\n'); - if (sourcePathDetails.length) mappedSourcesStr = '\n' + mappedSourcesStr; - - return result + mappedSourcesStr; - }); - } - /** * Allow consumers to override just because of https://github.com/nodejs/node/issues/8426 */ - protected globalEvaluate(args: Crdp.Runtime.EvaluateRequest): Promise { - return this.chrome.Runtime.evaluate(args); + public globalEvaluate(args: Crdp.Runtime.EvaluateRequest): Promise { + return this._inspectDebugeeState.evaluate(args); } - private async waitThenDoEvaluate(expression: string, frameId?: number, extraArgs?: Partial): Promise { - const waitThenEval = this._waitAfterStep.then(() => this.doEvaluate(expression, frameId, extraArgs)); + private async waitThenDoEvaluate(expression: string, frame?: ICallFrame, extraArgs?: Partial): Promise { + const waitThenEval = this._waitAfterStep.then(() => this.doEvaluate(expression, frame, extraArgs)); this._waitAfterStep = waitThenEval.then(() => { }, () => { }); // to Promise and handle failed evals return waitThenEval; } - private async doEvaluate(expression: string, frameId?: number, extraArgs?: Partial): Promise { - if (typeof frameId === 'number') { - const frame = this._frameHandles.get(frameId); - if (!frame || !frame.callFrameId) { + private async doEvaluate(expression: string, frame: ICallFrame, extraArgs?: Partial): Promise { + if (frame) { + if (!frame) { return utils.errP(errors.evalNotAvailableMsg); } @@ -2620,10 +870,9 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { } } - protected async evaluateOnCallFrame(expression: string, frame: Crdp.Debugger.CallFrame, extraArgs?: Partial): Promise { - const callFrameId = frame.callFrameId; - let args: Crdp.Debugger.EvaluateOnCallFrameRequest = { - callFrameId, + public async evaluateOnCallFrame(expression: string, frame: ICallFrame, extraArgs?: Partial): Promise { + let args: EvaluateOnCallFrameRequest = { + frame, expression, // silent because of an issue where node will sometimes hang when breaking on exceptions in console messages. Fixed somewhere between 8 and 8.4 silent: true, @@ -2634,7 +883,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { args = Object.assign(args, extraArgs); } - return this.chrome.Debugger.evaluateOnCallFrame(args); + return this._inspectDebugeeState.evaluateOnCallFrame(args); } /* __GDPR__ @@ -2655,26 +904,26 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { .then(value => ({ value })); } - public setVariableValue(callFrameId: string, scopeNumber: number, variableName: string, value: string): Promise { + public setVariableValue(frame: ICallFrame, scopeNumber: number, variableName: string, value: string): Promise { let evalResultObject: Crdp.Runtime.RemoteObject; - return this.chrome.Debugger.evaluateOnCallFrame({ callFrameId, expression: value, silent: true }).then(evalResponse => { + return this._inspectDebugeeState.evaluateOnCallFrame({ frame, expression: value, silent: true }).then(evalResponse => { if (evalResponse.exceptionDetails) { const errMsg = ChromeUtils.errorMessageFromExceptionDetails(evalResponse.exceptionDetails); return Promise.reject(errors.errorFromEvaluate(errMsg)); } else { evalResultObject = evalResponse.result; const newValue = ChromeUtils.remoteObjectToCallArgument(evalResultObject); - return this.chrome.Debugger.setVariableValue({ callFrameId, scopeNumber, variableName, newValue }); + return this._updateDebugeeState.setVariableValue({ frame, scopeNumber, variableName, newValue }); } }, - error => Promise.reject(errors.errorFromEvaluate(error.message))) - // Temporary, Microsoft/vscode#12019 - .then(setVarResponse => ChromeUtils.remoteObjectToValue(evalResultObject).value); + error => Promise.reject(errors.errorFromEvaluate(error.message))) + // Temporary, Microsoft/vscode#12019 + .then(() => ChromeUtils.remoteObjectToValue(evalResultObject).value); } public setPropertyValue(objectId: string, propName: string, value: string): Promise { const setPropertyValueFn = `function() { return this["${propName}"] = ${value} }`; - return this.chrome.Runtime.callFunctionOn({ + return this._inspectDebugeeState.callFunctionOn({ objectId, functionDeclaration: setPropertyValueFn, silent: true }).then(response => { @@ -2686,7 +935,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { return ChromeUtils.remoteObjectToValue(response.result).value; } }, - error => Promise.reject(errors.errorFromEvaluate(error.message))); + error => Promise.reject(errors.errorFromEvaluate(error.message))); } public async remoteObjectToVariable(name: string, object: Crdp.Runtime.RemoteObject, parentEvaluateName?: string, stringify = true, context: VariableContext = 'variables'): Promise { @@ -2755,7 +1004,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { propCountP = Promise.resolve({ indexedVariables: undefined, namedVariables: undefined - }); + }); } const evaluateName = ChromeUtils.getEvaluateName(parentEvaluateName, name); @@ -2792,25 +1041,6 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { }; } - /* __GDPR__ - "ClientRequest/restartFrame" : { - "${include}": [ - "${IExecutionResultTelemetryProperties}", - "${DebugCommonProperties}" - ] - } - */ - public async restartFrame(args: DebugProtocol.RestartFrameArguments): Promise { - const callFrame = this._frameHandles.get(args.frameId); - if (!callFrame || !callFrame.callFrameId) { - return utils.errP(errors.noRestartFrame); - } - - await this.chrome.Debugger.restartFrame({ callFrameId: callFrame.callFrameId }); - this._expectingStopReason = 'frame_entry'; - return this.chrome.Debugger.stepInto({ }); - } - /* __GDPR__ "ClientRequest/completions" : { "${include}": [ @@ -2819,7 +1049,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { ] } */ - public async completions(args: DebugProtocol.CompletionsArguments): Promise { + public async completions(args: CompletionsArguments): Promise { const text = args.text; const column = args.column; @@ -2832,22 +1062,22 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { expression = prefix.substr(0, dot); } - if (typeof args.frameId === 'number' && !expression) { + if (args.frame && !expression) { logger.verbose(`Completions: Returning global completions`); // If no expression was passed, we must be getting global completions at a breakpoint - if (!this._frameHandles.get(args.frameId)) { + if (!args.frame) { return Promise.reject(errors.stackFrameNotValid()); } - const callFrame = this._frameHandles.get(args.frameId); - if (!callFrame || !callFrame.callFrameId) { + const callFrame = args.frame; + if (!callFrame) { // Async frame or label return { targets: [] }; } const scopeExpandPs = callFrame.scopeChain - .map(scope => new ScopeContainer(callFrame.callFrameId, undefined, scope.object.objectId).expand(this)); + .map(scope => new ScopeContainer(callFrame, undefined, scope.object.objectId).expand(this)); return Promise.all(scopeExpandPs) .then((variableArrs: DebugProtocol.Variable[][]) => { const targets = this.getFlatAndUniqueCompletionItems( @@ -2859,7 +1089,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { logger.verbose(`Completions: Returning for expression '${expression}'`); const getCompletionsFn = `(function(x){var a=[];for(var o=x;o!==null&&typeof o !== 'undefined';o=o.__proto__){a.push(Object.getOwnPropertyNames(o))};return a})(${expression})`; - const response = await this.waitThenDoEvaluate(getCompletionsFn, args.frameId, { returnByValue: true }); + const response = await this.waitThenDoEvaluate(getCompletionsFn, args.frame, { returnByValue: true }); if (response.exceptionDetails) { return { targets: [] }; } else { @@ -2926,7 +1156,7 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { } private getNumPropsByEval(objectId: string, getNumPropsFn: string): Promise { - return this.chrome.Runtime.callFunctionOn({ + return this._inspectDebugeeState.callFunctionOn({ objectId, functionDeclaration: getNumPropsFn, silent: true, @@ -2944,35 +1174,10 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { return { indexedVariables: resultProps[0], namedVariables: resultProps[1] }; } }, - error => Promise.reject(errors.errorFromEvaluate(error.message))); - } - - private fakeUrlForSourceReference(sourceReference: number): string { - const handle = this._sourceHandles.get(sourceReference); - return `${ChromeDebugAdapter.EVAL_NAME_PREFIX}${handle.scriptId}`; - } - - private displayNameForSourceReference(sourceReference: number): string { - const handle = this._sourceHandles.get(sourceReference); - return (handle && this.displayNameForScriptId(handle.scriptId)) || sourceReference + ''; - } - - private displayNameForScriptId(scriptId: number|string): string { - return `${ChromeDebugAdapter.EVAL_NAME_PREFIX}${scriptId}`; - } - - private getScriptByUrl(url: string): Crdp.Debugger.ScriptParsedEvent { - url = utils.canonicalizeUrl(url); - return this._scriptsByUrl.get(url) || this._scriptsByUrl.get(utils.fixDriveLetter(url)); - } - - private getValueFromCommittedBreakpointsByUrl(url: string): ISetBreakpointResult[] { - let canonicalizedUrl = utils.canonicalizeUrl(url); - return this._committedBreakpointsByUrl.get(canonicalizedUrl); + error => Promise.reject(errors.errorFromEvaluate(error.message))); } - private setValueForCommittedBreakpointsByUrl(url: string, value: ISetBreakpointResult[]): void { - let canonicalizedUrl = utils.canonicalizeUrl(url); - this._committedBreakpointsByUrl.set(canonicalizedUrl, value); + public async onPaused(_notification: PausedEvent): Promise { + this._variableHandles.onPaused(); } } diff --git a/src/chrome/chromeDebugSession.ts b/src/chrome/chromeDebugSession.ts index 93366f1a6..009084bc2 100644 --- a/src/chrome/chromeDebugSession.ts +++ b/src/chrome/chromeDebugSession.ts @@ -4,9 +4,8 @@ import * as os from 'os'; import { DebugProtocol } from 'vscode-debugprotocol'; -import { LoggingDebugSession, ErrorDestination, Response, logger } from 'vscode-debugadapter'; +import { LoggingDebugSession, ErrorDestination, Response, logger, DebugSession } from 'vscode-debugadapter'; -import { ChromeDebugAdapter } from './chromeDebugAdapter'; import { ITargetFilter, ChromeConnection, IChromeError } from './chromeConnection'; import { BasePathTransformer } from '../transformers/basePathTransformer'; import { BaseSourceMapTransformer } from '../transformers/baseSourceMapTransformer'; @@ -16,15 +15,32 @@ import { IDebugAdapter } from '../debugAdapterInterfaces'; import { telemetry, ExceptionType, IExecutionResultTelemetryProperties, TelemetryPropertyCollector, ITelemetryPropertyCollector } from '../telemetry'; import * as utils from '../utils'; import { ExecutionTimingsReporter, StepProgressEventsEmitter, IObservableEvents, IStepStartedEventsEmitter, IFinishedStartingUpEventsEmitter } from '../executionTimingsReporter'; +import { ChromeDebugAdapter } from './client/chromeDebugAdapter/chromeDebugAdapterV2'; +import { AvailableCommands, CommandText } from './client/requests'; +import { IExtensibilityPoints } from './extensibility/extensibilityPoints'; +import { ConnectedCDAConfiguration } from './client/chromeDebugAdapter/cdaConfiguration'; export interface IChromeDebugAdapterOpts { targetFilter?: ITargetFilter; + + extensibilityPoints: IExtensibilityPoints; + + // Override services + chromeConnection?: typeof ChromeConnection; + pathTransformer?: { new(configuration: ConnectedCDAConfiguration): BasePathTransformer }; + sourceMapTransformer?: { new(configuration: ConnectedCDAConfiguration): BaseSourceMapTransformer }; + lineColTransformer?: { new(configuration: ConnectedCDAConfiguration): LineColTransformer }; +} + +export interface INewChromeDebugAdapterOpts { + targetFilter?: ITargetFilter; logFilePath?: string; // obsolete, vscode log dir should be used + enableSourceMapCaching?: boolean; // Override services chromeConnection?: typeof ChromeConnection; - pathTransformer?: { new(): BasePathTransformer }; - sourceMapTransformer?: { new(sourceHandles: any): BaseSourceMapTransformer }; + pathTransformer?: BasePathTransformer; + sourceMapTransformer: BaseSourceMapTransformer; lineColTransformer?: { new(session: any): LineColTransformer }; } @@ -32,6 +48,8 @@ export interface IChromeDebugSessionOpts extends IChromeDebugAdapterOpts { /** The class of the adapter, which is instantiated for each session */ adapter: typeof ChromeDebugAdapter; extensionName: string; + logFilePath: string; + extensibilityPoints: IExtensibilityPoints; } export const ErrorTelemetryEventName = 'error'; @@ -65,17 +83,17 @@ export class ChromeDebugSession extends LoggingDebugSession implements IObservab * DebugSession.run with the result. Alternatively they could subclass ChromeDebugSession and pass * their options to the super constructor, but I think this is easier to follow. */ - public static getSession(opts: IChromeDebugSessionOpts): typeof ChromeDebugSession { + public static getSession(opts: IChromeDebugSessionOpts): typeof DebugSession { // class expression! return class extends ChromeDebugSession { constructor(debuggerLinesAndColumnsStartAt1?: boolean, isServer?: boolean) { - super(debuggerLinesAndColumnsStartAt1, isServer, opts); + super(!!debuggerLinesAndColumnsStartAt1, !!isServer, opts); } }; } - public constructor(obsolete_debuggerLinesAndColumnsStartAt1?: boolean, obsolete_isServer?: boolean, opts?: IChromeDebugSessionOpts) { - super(opts.logFilePath, obsolete_debuggerLinesAndColumnsStartAt1, obsolete_isServer); + public constructor(obsolete_debuggerLinesAndColumnsStartAt1: boolean, obsolete_isServer: boolean, opts: IChromeDebugSessionOpts) { + super(undefined, obsolete_debuggerLinesAndColumnsStartAt1, obsolete_isServer); logVersionInfo(); this._extensionName = opts.extensionName; @@ -83,7 +101,7 @@ export class ChromeDebugSession extends LoggingDebugSession implements IObservab this.events = new StepProgressEventsEmitter([this._debugAdapter.events]); this.configureExecutionTimingsReporting(); - const safeGetErrDetails = err => { + const safeGetErrDetails = (err: any) => { let errMsg; try { errMsg = (err && (err).stack) ? (err).stack : JSON.stringify(err); @@ -94,7 +112,7 @@ export class ChromeDebugSession extends LoggingDebugSession implements IObservab return errMsg; }; - const reportErrorTelemetry = (err, exceptionType: ExceptionType) => { + const reportErrorTelemetry = (err: any, exceptionType: ExceptionType) => { let properties: IExecutionResultTelemetryProperties = {}; properties.successful = 'false'; properties.exceptionType = exceptionType; @@ -129,9 +147,12 @@ export class ChromeDebugSession extends LoggingDebugSession implements IObservab /** * Overload dispatchRequest to the debug adapters' Promise-based methods instead of DebugSession's callback-based methods */ - protected dispatchRequest(request: DebugProtocol.Request): void { + public dispatchRequest(request: DebugProtocol.Request): Promise { + if (AvailableCommands.has(request.command)) { + const command = request.command as CommandText; + // We want the request to be non-blocking, so we won't await for reportTelemetry - this.reportTelemetry(`ClientRequest/${request.command}`, async (reportFailure, telemetryPropertyCollector) => { + return this.reportTelemetry(`ClientRequest/${request.command}`, async (reportFailure, telemetryPropertyCollector) => { const response: DebugProtocol.Response = new Response(request); try { logger.verbose(`From client: ${request.command}(${JSON.stringify(request.arguments) })`); @@ -141,7 +162,12 @@ export class ChromeDebugSession extends LoggingDebugSession implements IObservab this.sendUnknownCommandResponse(response, request.command); } else { telemetryPropertyCollector.addTelemetryProperty('requestType', request.type); - response.body = await this._debugAdapter[request.command](request.arguments, telemetryPropertyCollector, request.seq); + const requestHandler = (this._debugAdapter as any) [command] as Function; + if (requestHandler instanceof Function) { + response.body = await requestHandler.call(this._debugAdapter, request.arguments, telemetryPropertyCollector, request.seq); + } else { + throw new Error(`Couldn't find a handler for request ${command}`); + } this.sendResponse(response); } } catch (e) { @@ -151,6 +177,9 @@ export class ChromeDebugSession extends LoggingDebugSession implements IObservab this.failedRequest(request.command, response, e); } }); + } else { + throw new Error(`The client requested ${request.command} which is not a recognized command`); + } } // { command: request.command, type: request.type }; @@ -182,7 +211,7 @@ export class ChromeDebugSession extends LoggingDebugSession implements IObservab telemetry.reportEvent(eventName, properties); }; - const reportFailure = e => { + const reportFailure = (e: any) => { failed = true; properties.successful = 'false'; properties.exceptionType = 'firstChance'; @@ -303,6 +332,25 @@ export class ChromeDebugSession extends LoggingDebugSession implements IObservab } } + public convertClientLineToDebugger(line: number): number { + // LineColTransformer uses this protected method from the session + return super.convertClientLineToDebugger(line); + } + + public convertClientColumnToDebugger(column: number): number { + // LineColTransformer uses this protected method from the session + return super.convertClientColumnToDebugger(column); + } + + public convertDebuggerLineToClient(line: number): number { + // LineColTransformer uses this protected method from the session + return super.convertDebuggerLineToClient(line); + } + + public convertDebuggerColumnToClient(column: number): number { + // LineColTransformer uses this protected method from the session + return super.convertDebuggerColumnToClient(column); + } } function logVersionInfo(): void { diff --git a/src/chrome/chromeUtils.ts b/src/chrome/chromeUtils.ts index c425e0f9c..0a2c75005 100644 --- a/src/chrome/chromeUtils.ts +++ b/src/chrome/chromeUtils.ts @@ -11,6 +11,8 @@ import * as utils from '../utils'; import { ITarget } from './chromeConnection'; import { IPathMapping } from '../debugAdapterInterfaces'; import { pathToRegex } from '../utils'; +import { LocationInScript } from './internal/locations/location'; +import { IResourceIdentifier } from './internal/sources/resourceIdentifier'; /** * Takes the path component of a target url (starting with '/') and applies pathMapping @@ -284,7 +286,7 @@ export function getEvaluateName(parentEvaluateName: string, name: string): strin return parentEvaluateName + nameAccessor; } -export function selectBreakpointLocation(lineNumber: number, columnNumber: number, locations: Crdp.Debugger.BreakLocation[]): Crdp.Debugger.BreakLocation { +export function selectBreakpointLocation(_lineNumber: number, columnNumber: number, locations: LocationInScript[]): LocationInScript { for (let i = locations.length - 1; i >= 0; i--) { if (locations[i].columnNumber <= columnNumber) { return locations[i]; @@ -296,15 +298,15 @@ export function selectBreakpointLocation(lineNumber: number, columnNumber: numbe export const EVAL_NAME_PREFIX = 'VM'; -export function isEvalScript(scriptPath: string): boolean { - return scriptPath.startsWith(EVAL_NAME_PREFIX); +export function isEvalScript(scriptPath: IResourceIdentifier): boolean { + return scriptPath.canonicalized.startsWith(EVAL_NAME_PREFIX); } /* Constructs the regex for files to enable break on load For example, for a file index.js the regex will match urls containing index.js, index.ts, abc/index.ts, index.bin.js etc It won't match index100.js, indexabc.ts etc */ -export function getUrlRegexForBreakOnLoad(url: string): string { - const fileNameWithoutFullPath = path.parse(url).base; +export function getUrlRegexForBreakOnLoad(url: IResourceIdentifier): string { + const fileNameWithoutFullPath = path.parse(url.canonicalized).base; const fileNameWithoutExtension = path.parse(fileNameWithoutFullPath).name; const escapedFileName = pathToRegex(fileNameWithoutExtension); return '.*[\\\\\\/]' + escapedFileName + '([^A-z^0-9].*)?$'; diff --git a/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts b/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts new file mode 100644 index 000000000..5a502ba43 --- /dev/null +++ b/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts @@ -0,0 +1,42 @@ +import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; +import { IClientCapabilities, ILaunchRequestArgs, IAttachRequestArgs } from '../../../debugAdapterInterfaces'; +import { ChromeConnection } from '../../chromeConnection'; +import { LoggingConfiguration } from '../../internal/services/logging'; +import { ScenarioType } from './unconnectedCDA'; +import { injectable } from 'inversify'; +import { ISession } from '../session'; +import * as utils from '../../../utils'; + +export interface IConnectedCDAConfiguration { + args: ILaunchRequestArgs | IAttachRequestArgs; + isVSClient: boolean; + _extensibilityPoints: IExtensibilityPoints; + loggingConfiguration: LoggingConfiguration; + _session: ISession; + _clientCapabilities: IClientCapabilities; + _chromeConnectionClass: typeof ChromeConnection; + scenarioType: ScenarioType; +} + +@injectable() +export class ConnectedCDAConfiguration implements IConnectedCDAConfiguration { + public readonly args: ILaunchRequestArgs | IAttachRequestArgs; + + public readonly isVSClient = this._clientCapabilities.clientID === 'visualstudio'; + + constructor(public readonly _extensibilityPoints: IExtensibilityPoints, + public readonly loggingConfiguration: LoggingConfiguration, + public readonly _session: ISession, + public readonly _clientCapabilities: IClientCapabilities, + public readonly _chromeConnectionClass: typeof ChromeConnection, + public readonly scenarioType: ScenarioType, + private readonly originalArgs: ILaunchRequestArgs | IAttachRequestArgs) { + this.args = this._extensibilityPoints.updateArguments(this.originalArgs); + + if (this.args.pathMapping) { + for (const urlToMap in this.args.pathMapping) { + this.args.pathMapping[urlToMap] = utils.canonicalizeUrl(this.args.pathMapping[urlToMap]); + } + } + } +} diff --git a/src/chrome/client/chromeDebugAdapter/cdaState.ts b/src/chrome/client/chromeDebugAdapter/cdaState.ts new file mode 100644 index 000000000..e10d02998 --- /dev/null +++ b/src/chrome/client/chromeDebugAdapter/cdaState.ts @@ -0,0 +1,111 @@ +import { ITelemetryPropertyCollector, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IEvaluateResponseBody, IGetLoadedSourcesResponseBody, IDebugAdapterState, ILaunchRequestArgs, IAttachRequestArgs, IExceptionInfoResponseBody } from '../../../debugAdapterInterfaces'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { PromiseOrNot } from '../../utils/promises'; +import { ChromeDebugLogic } from '../../chromeDebugAdapter'; + +export abstract class UnconnectedCDACommonLogic implements IDebugAdapterState { + public abstract chromeDebugAdapter(): ChromeDebugLogic; + + public initialize(_args: DebugProtocol.InitializeRequestArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise<{capabilities: DebugProtocol.Capabilities, newState: IDebugAdapterState}> { + return this.throwNotConnectedError(); + } + + public launch(_args: ILaunchRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { + return this.throwNotConnectedError(); + } + + public attach(_args: IAttachRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { + return this.throwNotConnectedError(); + } + + public restartFrame(_args: DebugProtocol.RestartFrameRequest): Promise { + return this.throwNotConnectedError(); + } + + public exceptionInfo(_args: DebugProtocol.ExceptionInfoArguments): Promise { + return this.throwNotConnectedError(); + } + + public shutdown(): void { + return this.throwNotConnectedError(); + } + + public disconnect(_args: DebugProtocol.DisconnectArguments): Promise { + return this.throwNotConnectedError(); + } + + public setBreakpoints(_args: DebugProtocol.SetBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public setExceptionBreakpoints(_args: DebugProtocol.SetExceptionBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public configurationDone(): Promise { + return this.throwNotConnectedError(); + } + + public continue(): Promise { + + return this.throwNotConnectedError(); + } + + public next(): Promise { + + return this.throwNotConnectedError(); + } + + public stepIn(): Promise { + + return this.throwNotConnectedError(); + } + + public stepOut(): Promise { + return this.throwNotConnectedError(); + } + + public pause(): Promise { + return this.throwNotConnectedError(); + } + + public stackTrace(_args: DebugProtocol.StackTraceArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public scopes(_args: DebugProtocol.ScopesArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public variables(_args: DebugProtocol.VariablesArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public source(_args: DebugProtocol.SourceArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public threads(): Promise<{ threads: DebugProtocol.Thread[]; }> { + return this.throwNotConnectedError(); + } + + public evaluate(_args: DebugProtocol.EvaluateArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public loadedSources(_args: DebugProtocol.LoadedSourcesArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public setFunctionBreakpoints(_args: DebugProtocol.SetFunctionBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public setVariable(_args: DebugProtocol.SetVariableArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + private throwNotConnectedError(): never { + throw new Error("Can't execute this request when the debug adapter is not connected to the target"); + } +} \ No newline at end of file diff --git a/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts b/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts new file mode 100644 index 000000000..0278a6b1e --- /dev/null +++ b/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts @@ -0,0 +1,126 @@ +import { + IDebugAdapter, ITelemetryPropertyCollector, PromiseOrNot, ILaunchRequestArgs, IAttachRequestArgs, IThreadsResponseBody, + ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, + IEvaluateResponseBody, IExceptionInfoResponseBody, IGetLoadedSourcesResponseBody, IDebugAdapterState +} from '../../..'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { ChromeDebugSession, IChromeDebugSessionOpts } from '../../chromeDebugSession'; +import { ChromeConnection } from '../../chromeConnection'; +import { StepProgressEventsEmitter } from '../../../executionTimingsReporter'; +import { UninitializedCDA } from './uninitializedCDA'; + +export class ChromeDebugAdapter implements IDebugAdapter { + private _state: IDebugAdapterState; + + public events = new StepProgressEventsEmitter(); + + constructor(args: IChromeDebugSessionOpts, originalSession: ChromeDebugSession) { + // Copy the arguments to keep backwards compatibility. TODO DIEGO remove this + args.extensibilityPoints.chromeConnection = args.extensibilityPoints.chromeConnection || args.chromeConnection; + args.extensibilityPoints.pathTransformer = args.extensibilityPoints.pathTransformer || args.pathTransformer; + args.extensibilityPoints.sourceMapTransformer = args.extensibilityPoints.sourceMapTransformer || args.sourceMapTransformer; + args.extensibilityPoints.lineColTransformer = args.extensibilityPoints.lineColTransformer || args.lineColTransformer; + args.extensibilityPoints.targetFilter = args.extensibilityPoints.targetFilter || args.targetFilter; + args.extensibilityPoints.logFilePath = args.logFilePath; + + this._state = new UninitializedCDA(args.extensibilityPoints, originalSession, args.chromeConnection || ChromeConnection); + } + + public shutdown(): void { + return this._state.shutdown(); + } + + public async initialize(args: DebugProtocol.InitializeRequestArguments, _?: ITelemetryPropertyCollector, _2?: number): Promise { + const { capabilities, newState } = await this._state.initialize(args); + this._state = newState; + return capabilities; + } + + public async launch(args: ILaunchRequestArgs, _?: ITelemetryPropertyCollector, _2?: number): Promise { + this._state = await this._state.launch(args); + } + + public async attach(args: IAttachRequestArgs, _?: ITelemetryPropertyCollector, _2?: number): Promise { + this._state = await this._state.attach(args); + } + + public disconnect(args: DebugProtocol.DisconnectArguments): PromiseOrNot { + return this._state.disconnect(args); + } + + public async setBreakpoints(args: DebugProtocol.SetBreakpointsArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector): Promise { + return this._state.setBreakpoints(args, telemetryPropertyCollector); + } + + public async setExceptionBreakpoints(args: DebugProtocol.SetExceptionBreakpointsArguments, _?: ITelemetryPropertyCollector, _2?: number): Promise { + return this._state.setExceptionBreakpoints(args); + } + + public configurationDone(): PromiseOrNot { + return this._state.configurationDone(); + } + + public continue(): PromiseOrNot { + return this._state.continue(); + } + + public next(): PromiseOrNot { + return this._state.next(); + } + + public stepIn(): PromiseOrNot { + return this._state.stepIn(); + } + + public stepOut(): PromiseOrNot { + return this._state.stepOut(); + } + + public pause(): PromiseOrNot { + return this._state.pause(); + } + + public async restartFrame(args: DebugProtocol.RestartFrameRequest): Promise { + return this._state.restartFrame(args); + } + + public async stackTrace(args: DebugProtocol.StackTraceArguments, _?: ITelemetryPropertyCollector, _2?: number): Promise { + return this._state.stackTrace(args); + } + + public scopes(args: DebugProtocol.ScopesArguments, _?: ITelemetryPropertyCollector, _2?: number): PromiseOrNot { + return this._state.scopes(args); + } + + public variables(args: DebugProtocol.VariablesArguments, _?: ITelemetryPropertyCollector, _2?: number): PromiseOrNot { + return this._state.variables(args); + } + + public async source(args: DebugProtocol.SourceArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this._state.source(args, _telemetryPropertyCollector); + } + + public threads(): PromiseOrNot { + return this._state.threads(); + } + + public async evaluate(args: DebugProtocol.EvaluateArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this._state.evaluate(args, _telemetryPropertyCollector); + } + + public async loadedSources(args: DebugProtocol.LoadedSourcesArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): Promise { + return this._state.loadedSources(args, telemetryPropertyCollector, requestSeq); + } + + public setFunctionBreakpoints(_args: DebugProtocol.SetFunctionBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { + throw new Error('Method not implemented.'); + } + + public setVariable(_args: DebugProtocol.SetVariableArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { + throw new Error('Method not implemented.'); + } + + public async exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): Promise { + return this._state.exceptionInfo(args); + } +} \ No newline at end of file diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts new file mode 100644 index 000000000..7b9e5610b --- /dev/null +++ b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts @@ -0,0 +1,223 @@ +import * as errors from '../../../errors'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { ChromeDebugLogic } from '../../chromeDebugAdapter'; +import { CDTPDiagnostics } from '../../target/cdtpDiagnostics'; +import { ClientToInternal } from '../clientToInternal'; +import { InternalToClient } from '../internalToClient'; +import { IGetLoadedSourcesResponseBody, IDebugAdapterState, PromiseOrNot, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IThreadsResponseBody, IEvaluateResponseBody, IExceptionInfoResponseBody, ILaunchRequestArgs, IAttachRequestArgs } from '../../../debugAdapterInterfaces'; +import { StackTracesLogic } from '../../internal/stackTraces/stackTracesLogic'; +import { SourcesLogic } from '../../internal/sources/sourcesLogic'; +import { BreakpointsLogic } from '../../internal/breakpoints/breakpointsLogic'; +import { CDTPScriptsRegistry } from '../../target/cdtpScriptsRegistry'; +import { PauseOnExceptionOrRejection } from '../../internal/exceptions/pauseOnException'; +import { Stepping } from '../../internal/stepping/stepping'; +import { DotScriptCommand } from '../../internal/sources/features/dotScriptsCommand'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { SkipFilesLogic } from '../../internal/features/skipFiles'; +import { TakeProperActionOnPausedEvent } from '../../internal/features/takeProperActionOnPausedEvent'; +import { SmartStepLogic } from '../../internal/features/smartStep'; +import { NotifyClientOfLoadedSources } from '../../internal/sources/features/notifyClientOfLoadedSources'; +import { CDTPOnScriptParsedEventProvider } from '../../target/cdtpOnScriptParsedEventProvider'; +import { Target } from '../../communication/targetChannels'; +import { IDebuggeeRunner } from '../../debugee/debugeeLauncher'; +import { StepProgressEventsEmitter } from '../../../executionTimingsReporter'; +import { TelemetryPropertyCollector, ITelemetryPropertyCollector } from '../../../telemetry'; +import { ICommunicator, utils } from '../../..'; + +// TODO DIEGO: Remember to call here and only here this._lineColTransformer.convertDebuggerLocationToClient(stackFrame); for all responses +@injectable() +export class ConnectedCDA implements IDebugAdapterState { + private readonly events = new StepProgressEventsEmitter(); + + public static SCRIPTS_COMMAND = '.scripts'; + + constructor( + @inject(TYPES.ChromeDebugLogic) protected readonly _chromeDebugAdapter: ChromeDebugLogic, + @inject(TYPES.SourcesLogic) private readonly _sourcesLogic: SourcesLogic, + @inject(TYPES.CDTPScriptsRegistry) protected _scriptsLogic: CDTPScriptsRegistry, + @inject(TYPES.ClientToInternal) protected readonly _clientToInternal: ClientToInternal, + @inject(TYPES.InternalToClient) private readonly _internalToVsCode: InternalToClient, + @inject(TYPES.StackTracesLogic) private readonly _stackTraceLogic: StackTracesLogic, + @inject(TYPES.BreakpointsLogic) protected readonly _breakpointsLogic: BreakpointsLogic, + @inject(TYPES.PauseOnExceptionOrRejection) public readonly _pauseOnException: PauseOnExceptionOrRejection, + @inject(TYPES.Stepping) private readonly _stepping: Stepping, + @inject(TYPES.DotScriptCommand) public readonly _dotScriptCommand: DotScriptCommand, + @inject(SkipFilesLogic) public readonly _skipFilesLogic: SkipFilesLogic, + @inject(SmartStepLogic) public readonly _smartStepLogic: SmartStepLogic, + @inject(TakeProperActionOnPausedEvent) public readonly _takeProperActionOnPausedEvent: TakeProperActionOnPausedEvent, + @inject(NotifyClientOfLoadedSources) public readonly _notifyClientOfLoadedSources: NotifyClientOfLoadedSources, + @inject(TYPES.IScriptParsedProvider) public readonly _cdtpOnScriptParsedEventProvider: CDTPOnScriptParsedEventProvider, + @inject(TYPES.communicator) public readonly _communicator: ICommunicator, + @inject(TYPES.IDebugeeRunner) public readonly _debugeeRunner: IDebuggeeRunner, + ) { } + + public async install(): Promise { + await this.chrome.install(); + await this._chromeDebugAdapter.install(); + await this._sourcesLogic.install(); + await this._stackTraceLogic.install(); + await this._breakpointsLogic.install(); + await this._pauseOnException.install(); + await this._stepping.install(); + // await this._dotScriptCommand.install(configuration); + await this._skipFilesLogic.install(); + await this._smartStepLogic.install(); + await this._takeProperActionOnPausedEvent.install(); + await this._notifyClientOfLoadedSources.install(); + + const publishScriptParsed = this._communicator.getPublisher(Target.Debugger.OnScriptParsed); + this._cdtpOnScriptParsedEventProvider.onScriptParsed(publishScriptParsed); + return this; + } + + public get chrome(): CDTPDiagnostics { + return this._chromeDebugAdapter.chrome; + } + + public shutdown(): void { + return this._chromeDebugAdapter.shutdown(); + } + + public disconnect(_: DebugProtocol.DisconnectArguments): PromiseOrNot { + return this._chromeDebugAdapter.disconnect(); + } + + public async setBreakpoints(args: DebugProtocol.SetBreakpointsArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector): Promise { + if (args.breakpoints) { + const desiredBPRecipies = this._clientToInternal.toBPRecipies(args); + const bpRecipiesStatus = await this._breakpointsLogic.updateBreakpointsForFile(desiredBPRecipies, telemetryPropertyCollector); + return { breakpoints: await this._internalToVsCode.toBPRecipiesStatus(bpRecipiesStatus) }; + } else { + throw new Error(`Expected the set breakpoints arguments to have a list of breakpoints yet it was ${args.breakpoints}`); + } + } + + public async setExceptionBreakpoints(args: DebugProtocol.SetExceptionBreakpointsArguments, _?: ITelemetryPropertyCollector, _2?: number): Promise { + const exceptionsStrategy = this._clientToInternal.toPauseOnExceptionsStrategy(args.filters); + const promiseRejectionsStrategy = this._clientToInternal.toPauseOnPromiseRejectionsStrategy(args.filters); + await this._pauseOnException.setExceptionsStrategy(exceptionsStrategy); + this._pauseOnException.setPromiseRejectionStrategy(promiseRejectionsStrategy); + } + + public async configurationDone(): Promise { + await this._debugeeRunner.run(new TelemetryPropertyCollector()); + this.events.emitMilestoneReached('RequestedNavigateToUserPage'); // TODO DIEGO: Make sure this is reported + } + + public continue(): PromiseOrNot { + return this._stepping.continue(); + } + + public next(): PromiseOrNot { + return this._stepping.next(); + } + + public stepIn(): PromiseOrNot { + return this._stepping.stepIn(); + } + + public stepOut(): PromiseOrNot { + return this._stepping.stepOut(); + } + + public pause(): PromiseOrNot { + return this._stepping.pause(); + } + + public async restartFrame(args: DebugProtocol.RestartFrameRequest): Promise { + const callFrame = this._clientToInternal.getCallFrameById(args.arguments.frameId); + if (callFrame.hasCallFrame()) { + return this._stepping.restartFrame(callFrame.callFrame.unmappedCallFrame); + } else { + throw new Error(`Cannot restart to a frame that doesn't have state information`); + } + } + + public async stackTrace(args: DebugProtocol.StackTraceArguments, _?: ITelemetryPropertyCollector, _2?: number): Promise { + const stackTracePresentation = await this._stackTraceLogic.stackTrace(args); + const clientStackTracePresentation = { + stackFrames: await this._internalToVsCode.toStackFrames(stackTracePresentation.stackFrames), + totalFrames: stackTracePresentation.totalFrames + }; + return clientStackTracePresentation; + } + + public scopes(args: DebugProtocol.ScopesArguments, _?: ITelemetryPropertyCollector, _2?: number): PromiseOrNot { + const frame = this._clientToInternal.getCallFrameById(args.frameId); + if (frame.hasCallFrame()) { + return this._chromeDebugAdapter.scopes(frame.callFrame); + } else { + const reason = frame.hasCodeFlow() + ? 'a code flow frame only has code flow information' + : 'a label frame is only a description of the different sections of the call stack'; + throw new Error(`Can't get scopes for the frame because ${reason}`); + } + } + + public variables(args: DebugProtocol.VariablesArguments, _?: ITelemetryPropertyCollector, _2?: number): PromiseOrNot { + return this._chromeDebugAdapter.variables(args); + } + + public async source(args: DebugProtocol.SourceArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + if (args.source) { + const source = this._clientToInternal.toSource(args.source); + const sourceText = await this._sourcesLogic.getText(source); + return { + content: sourceText, + mimeType: 'text/javascript' + }; + } else { + throw new Error(`Expected the source request to have a source argument yet it was ${args.source}`); + } + } + + public threads(): PromiseOrNot { + return this._chromeDebugAdapter.threads(); + } + + public async evaluate(args: DebugProtocol.EvaluateArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + if (args.expression.startsWith(ConnectedCDA.SCRIPTS_COMMAND)) { + const scriptsRest = utils.lstrip(args.expression, ConnectedCDA.SCRIPTS_COMMAND).trim(); + await this._dotScriptCommand.handleScriptsCommand(scriptsRest); + return { + result: '', + variablesReference: 0 + }; + } else { + return this._chromeDebugAdapter.evaluate(args); + } + } + + public async loadedSources(): Promise { + return { sources: await this._internalToVsCode.toSourceTrees(await this._sourcesLogic.getLoadedSourcesTrees()) }; + } + + public setFunctionBreakpoints(_args: DebugProtocol.SetFunctionBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { + throw new Error('Method not implemented.'); + } + + public setVariable(_args: DebugProtocol.SetVariableArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { + throw new Error('Method not implemented.'); + } + + public async exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): Promise { + if (args.threadId !== ChromeDebugLogic.THREAD_ID) { + throw errors.invalidThread(args.threadId); + } + + return this._internalToVsCode.toExceptionInfo(await this._pauseOnException.latestExceptionInfo()); + } + + public launch(_args: ILaunchRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): never { + throw new Error("Can't launch to a new target while connected to a previous target"); + } + + public attach(_args: IAttachRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): never { + throw new Error("Can't attach to a new target while connected to a previous target"); + } + + public initialize(_args: DebugProtocol.InitializeRequestArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot<{ capabilities: DebugProtocol.Capabilities; newState: IDebugAdapterState; }> { + throw new Error('The debug adapter is already initialized. Calling initialize again is not supported.'); + } +} diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts b/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts new file mode 100644 index 000000000..317b281cd --- /dev/null +++ b/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts @@ -0,0 +1,49 @@ +import { EventsConsumedByStackTrace } from '../../internal/stackTraces/stackTracesLogic'; +import { EventsConsumedBySkipFilesLogic } from '../../internal/features/skipFiles'; +import { EventsConsumedByBreakpointsLogic } from '../../internal/breakpoints/breakpointsLogic'; +import { ICommunicator } from '../../communication/communicator'; +import { Internal } from '../../communication/internalChannels'; +import { Target } from '../../communication/targetChannels'; +import { ILoadedSource } from '../../internal/sources/loadedSource'; +import { asyncMap } from '../../collections/async'; +import { EventsConsumedByPauseOnException } from '../../internal/exceptions/pauseOnException'; +import { EventsConsumedByTakeProperActionOnPausedEvent } from '../../internal/features/takeProperActionOnPausedEvent'; +import { EventsConsumedBySourceResolver } from '../../internal/sources/sourceResolver'; +import { EventsConsumedBySmartStepLogic } from '../../internal/features/smartStep'; +import { EventsConsumedByReAddBPsWhenSourceIsLoaded } from '../../internal/breakpoints/features/reAddBPsWhenSourceIsLoaded'; +import { EventsConsumedByAsyncStepping } from '../../internal/stepping/features/asyncStepping'; +// import { EventsConsumedBySyncStepping } from '../../internal/stepping/features/syncStepping'; + +export interface EventsConsumedByConnectedCDA extends EventsConsumedByBreakpointsLogic, EventsConsumedByPauseOnException, + EventsConsumedByStackTrace, EventsConsumedByTakeProperActionOnPausedEvent, EventsConsumedBySkipFilesLogic, + EventsConsumedBySourceResolver, EventsConsumedBySmartStepLogic, + EventsConsumedByReAddBPsWhenSourceIsLoaded, EventsConsumedByAsyncStepping { } + +export class ConnectedCDAEventsCreator { + constructor(private readonly communicator: ICommunicator) { } + + public create(): EventsConsumedByConnectedCDA { + const onLoadedSourceIsAvailable = (listener: (source: ILoadedSource) => void) => { + this.communicator.subscribe(Target.Debugger.OnScriptParsed, async scriptParsed => { + await asyncMap(scriptParsed.script.allSources, listener); + }); + }; + + return { + onLoadedSourceIsAvailable: onLoadedSourceIsAvailable, + + notifyNoPendingBPs: this.communicator.getPublisher(Internal.Breakpoints.OnNoPendingBreakpoints), + onNoPendingBreakpoints: this.communicator.getSubscriber(Internal.Breakpoints.OnNoPendingBreakpoints), + + onResumed: this.communicator.getSubscriber(Target.Debugger.OnResumed), + // onPaused: this.communicator.getSubscriber(Target.Debugger.OnPaused), + onAsyncBreakpointResolved: this.communicator.getSubscriber(Target.Debugger.OnAsyncBreakpointResolved), + + onScriptParsed: this.communicator.getSubscriber(Target.Debugger.OnScriptParsed), + + subscriberForAskForInformationAboutPaused: this.communicator.getSubscriber(Internal.Breakpoints.OnPausedOnBreakpoint), + askForInformationAboutPause: this.communicator.getPublisher(Internal.Breakpoints.OnPausedOnBreakpoint), + publishGoingToPauseClient: this.communicator.getPublisher(Internal.Breakpoints.OnGoingToPauseClient) + }; + } +} diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts new file mode 100644 index 000000000..8825a169c --- /dev/null +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts @@ -0,0 +1,128 @@ +import { InitializedEvent, Logger } from 'vscode-debugadapter'; +import { ChromeDebugLogic, ChromeDebugSession, IAttachRequestArgs, IDebugAdapterState, ILaunchRequestArgs, ITelemetryPropertyCollector, LineColTransformer, utils, BaseSourceMapTransformer, BasePathTransformer } from '../../..'; +import { IClientCapabilities } from '../../../debugAdapterInterfaces'; +import * as errors from '../../../errors'; +import { EagerSourceMapTransformer } from '../../../transformers/eagerSourceMapTransformer'; +import { FallbackToClientPathTransformer } from '../../../transformers/fallbackToClientPathTransformer'; +import { RemotePathTransformer } from '../../../transformers/remotePathTransformer'; +import { ChromeConnection } from '../../chromeConnection'; +import { Communicator, LoggingCommunicator } from '../../communication/communicator'; +import { DependencyInjection } from '../../dependencyInjection.ts/di'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; +import { Logging, LoggingConfiguration } from '../../internal/services/logging'; +import { ExecutionLogger } from '../../logging/executionLogger'; +import { DelayMessagesUntilInitializedSession } from '../delayMessagesUntilInitializedSession'; +import { DoNotPauseWhileSteppingSession } from '../doNotPauseWhileSteppingSession'; +import { ConnectedCDAConfiguration } from './cdaConfiguration'; +import { ConnectedCDA } from './connectedCDA'; +import { ConnectedCDAEventsCreator } from './connectedCDAEvents'; +import { UnconnectedCDACommonLogic } from './unconnectedCDACommonLogic'; +import { IDebuggeeLauncher } from '../../debugee/debugeeLauncher'; + +export enum ScenarioType { + Launch, + Attach +} + +export class UnconnectedCDA extends UnconnectedCDACommonLogic implements IDebugAdapterState { + private readonly _session = new DelayMessagesUntilInitializedSession(new DoNotPauseWhileSteppingSession(this._basicSession)); + + private configuration: ConnectedCDAConfiguration; + + public chromeDebugAdapter(): ChromeDebugLogic { + throw new Error('The chrome debug adapter can only be used when the debug adapter is connected'); + } + + public async launch(args: ILaunchRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.createConnection(ScenarioType.Launch, args, telemetryPropertyCollector); + } + + public async attach(args: IAttachRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + const updatedArgs = Object.assign({}, { port: 9229 }, args); + return this.createConnection(ScenarioType.Attach, updatedArgs, telemetryPropertyCollector); + } + + private parseLoggingConfiguration(args: ILaunchRequestArgs | IAttachRequestArgs): LoggingConfiguration { + const traceMapping: { [key: string]: Logger.LogLevel | undefined } = { true: Logger.LogLevel.Warn, verbose: Logger.LogLevel.Verbose }; + const traceValue = args.trace && traceMapping[args.trace.toString().toLowerCase()]; + return { logLevel: traceValue, logFilePath: args.logFilePath, shouldLogTimestamps: args.logTimestamps }; + } + + private async createConnection(scenarioType: ScenarioType, args: ILaunchRequestArgs | IAttachRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector): Promise { + if (this._clientCapabilities.pathFormat !== 'path') { + throw errors.pathFormat(); + } + + utils.setCaseSensitivePaths(this._clientCapabilities.clientID !== 'visualstudio'); // TODO DIEGO: Find a way to remove this + const di = new DependencyInjection(); + + const pathTransformerClass = this._clientCapabilities.supportsMapURLToFilePathRequest + ? FallbackToClientPathTransformer + : this._extensibilityPoints.pathTransformer || RemotePathTransformer; + const sourceMapTransformerClass = this._extensibilityPoints.sourceMapTransformer || EagerSourceMapTransformer; + const lineColTransformerClass = this._extensibilityPoints.lineColTransformer || LineColTransformer; + const logging = new Logging().install(this._extensibilityPoints, this.parseLoggingConfiguration(args)); + + const chromeConnection = new (this._chromeConnectionClass)(undefined, args.targetFilter || this._extensibilityPoints.targetFilter); + const communicator = new LoggingCommunicator(new Communicator(), new ExecutionLogger(logging)); + + const diContainer = this.getDIContainer(di, lineColTransformerClass, communicator, chromeConnection, pathTransformerClass, sourceMapTransformerClass, args, scenarioType); + + const debugeeLauncher = diContainer.createComponent(TYPES.IDebuggeeLauncher); + + diContainer.unconfigure(TYPES.IDebuggeeLauncher); // TODO DIEGO: Remove this line and do this properly + diContainer.configureValue(TYPES.IDebuggeeLauncher, debugeeLauncher); // TODO DIEGO: Remove this line and do this properly + + const result = await debugeeLauncher.launch(args, telemetryPropertyCollector); + await chromeConnection.attach(result.address, result.port, result.url, args.timeout, args.extraCRDPChannelPort); + + if (chromeConnection.api === undefined) { + throw new Error('Expected the Chrome API object to be properly initialized by now'); + } + + diContainer.configureValue(TYPES.CDTPClient, chromeConnection.api); + + const newState = di.createClassWithDI(ConnectedCDA); + await newState.install(); + + await chromeConnection.api.Runtime.enable(); + + this._session.sendEvent(new InitializedEvent()); + + return newState; + } + + constructor( + private readonly _extensibilityPoints: IExtensibilityPoints, + private readonly _basicSession: ChromeDebugSession, + private readonly _clientCapabilities: IClientCapabilities, + private readonly _chromeConnectionClass: typeof ChromeConnection + ) { + super(); + } + + private getDIContainer(di: DependencyInjection, lineColTransformerClass: typeof LineColTransformer, communicator: LoggingCommunicator, chromeConnection: ChromeConnection, pathTransformerClass: (new (configuration: ConnectedCDAConfiguration) => BasePathTransformer), sourceMapTransformerClass: new (configuration: ConnectedCDAConfiguration) => BaseSourceMapTransformer, args: ILaunchRequestArgs | IAttachRequestArgs, scenarioType: ScenarioType): DependencyInjection { + const configuration = this.createConfiguration(args, scenarioType); + return di + .bindAll() + .configureClass(LineColTransformer, lineColTransformerClass) + .configureClass(TYPES.IDebugeeRunner, this._extensibilityPoints.debugeeRunner) + .configureClass(TYPES.IDebuggeeLauncher, this._extensibilityPoints.debugeeLauncher) + // .configureClass(TYPES.IDebugeeLauncher, debugeeLauncher) + .configureValue(TYPES.communicator, communicator) + .configureValue(TYPES.EventsConsumedByConnectedCDA, new ConnectedCDAEventsCreator(communicator).create()) + .configureValue(TYPES.ISession, this._session) + .configureValue(TYPES.BasePathTransformer, new pathTransformerClass(configuration)) + .configureValue(TYPES.BaseSourceMapTransformer, new sourceMapTransformerClass(configuration)) + .configureValue(TYPES.ChromeConnection, chromeConnection) + .configureValue(TYPES.ConnectedCDAConfiguration, configuration); + } + + private createConfiguration(args: ILaunchRequestArgs | IAttachRequestArgs, scenarioType: ScenarioType): ConnectedCDAConfiguration { + if (this.configuration === undefined) { + this.configuration = new ConnectedCDAConfiguration(this._extensibilityPoints, this.parseLoggingConfiguration(args), this._session, this._clientCapabilities, this._chromeConnectionClass, scenarioType, args); + } + return this.configuration; + } +} \ No newline at end of file diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts new file mode 100644 index 000000000..3cf7de75f --- /dev/null +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts @@ -0,0 +1,111 @@ +import { ITelemetryPropertyCollector, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IEvaluateResponseBody, IGetLoadedSourcesResponseBody } from '../../../debugAdapterInterfaces'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { ChromeDebugLogic, ILaunchRequestArgs, IAttachRequestArgs, IExceptionInfoResponseBody, IDebugAdapterState } from '../../..'; +import { PromiseOrNot } from '../../utils/promises'; + +export abstract class UnconnectedCDACommonLogic implements IDebugAdapterState { + public abstract chromeDebugAdapter(): ChromeDebugLogic; + + public initialize(_args: DebugProtocol.InitializeRequestArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise<{capabilities: DebugProtocol.Capabilities, newState: IDebugAdapterState}> { + return this.throwNotConnectedError(); + } + + public launch(_args: ILaunchRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { + return this.throwNotConnectedError(); + } + + public attach(_args: IAttachRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { + return this.throwNotConnectedError(); + } + + public restartFrame(_args: DebugProtocol.RestartFrameRequest): Promise { + return this.throwNotConnectedError(); + } + + public exceptionInfo(_args: DebugProtocol.ExceptionInfoArguments): Promise { + return this.throwNotConnectedError(); + } + + public shutdown(): void { + return this.throwNotConnectedError(); + } + + public disconnect(_args: DebugProtocol.DisconnectArguments): Promise { + return this.throwNotConnectedError(); + } + + public setBreakpoints(_args: DebugProtocol.SetBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public setExceptionBreakpoints(_args: DebugProtocol.SetExceptionBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public configurationDone(): Promise { + return this.throwNotConnectedError(); + } + + public continue(): Promise { + + return this.throwNotConnectedError(); + } + + public next(): Promise { + + return this.throwNotConnectedError(); + } + + public stepIn(): Promise { + + return this.throwNotConnectedError(); + } + + public stepOut(): Promise { + return this.throwNotConnectedError(); + } + + public pause(): Promise { + return this.throwNotConnectedError(); + } + + public stackTrace(_args: DebugProtocol.StackTraceArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public scopes(_args: DebugProtocol.ScopesArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public variables(_args: DebugProtocol.VariablesArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public source(_args: DebugProtocol.SourceArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public threads(): Promise<{ threads: DebugProtocol.Thread[]; }> { + return this.throwNotConnectedError(); + } + + public evaluate(_args: DebugProtocol.EvaluateArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public loadedSources(_args: DebugProtocol.LoadedSourcesArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public setFunctionBreakpoints(_args: DebugProtocol.SetFunctionBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + public setVariable(_args: DebugProtocol.SetVariableArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { + return this.throwNotConnectedError(); + } + + private throwNotConnectedError(): never { + throw new Error("Can't execute this request when the debug adapter is not connected to the target"); + } +} \ No newline at end of file diff --git a/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts b/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts new file mode 100644 index 000000000..9fbb6e6be --- /dev/null +++ b/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts @@ -0,0 +1,68 @@ +import { UnconnectedCDACommonLogic } from './unconnectedCDACommonLogic'; +import { ChromeConnection } from '../../chromeConnection'; +import { IDebugAdapterState, ChromeDebugLogic, ITelemetryPropertyCollector, IInitializeRequestArgs, ChromeDebugSession } from '../../..'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { UnconnectedCDA } from './unconnectedCDA'; +import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; +import * as nls from 'vscode-nls'; +let localize = nls.loadMessageBundle(); // Initialize to an unlocalized version until we know which locale to use + +export class UninitializedCDA extends UnconnectedCDACommonLogic implements IDebugAdapterState { + public chromeDebugAdapter(): ChromeDebugLogic { + throw new Error('Method not implemented.'); + } + + public async initialize(args: IInitializeRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise<{ capabilities: DebugProtocol.Capabilities, newState: IDebugAdapterState }> { + if (args.locale) { + localize = nls.config({ locale: args.locale })(); // Replace with the proper locale + } + + const exceptionBreakpointFilters = [ + { + label: localize('exceptions.all', 'All Exceptions'), + filter: 'all', + default: false + }, + { + label: localize('exceptions.uncaught', 'Uncaught Exceptions'), + filter: 'uncaught', + default: false + } + ]; + + if (this._extensibilityPoints.isPromiseRejectExceptionFilterEnabled) { + exceptionBreakpointFilters.push({ + label: localize('exceptions.promise_rejects', 'Promise Rejects'), + filter: 'promise_reject', + default: false + }); + } + + // This debug adapter supports two exception breakpoint filters + const capabilities = { + exceptionBreakpointFilters, + supportsConfigurationDoneRequest: true, + supportsSetVariable: true, + supportsConditionalBreakpoints: true, + supportsCompletionsRequest: true, + supportsHitConditionalBreakpoints: true, + supportsRestartFrame: true, + supportsExceptionInfoRequest: true, + supportsDelayedStackTraceLoading: true, + supportsValueFormattingOptions: true, + supportsEvaluateForHovers: true, + supportsLoadedSourcesRequest: true + }; + + const newState = new UnconnectedCDA(this._extensibilityPoints, this._session, args, this._chromeConnectionClass); + return { capabilities, newState }; + } + + constructor( + private readonly _extensibilityPoints: IExtensibilityPoints, + private readonly _session: ChromeDebugSession, + private readonly _chromeConnectionClass: typeof ChromeConnection + ) { + super(); + } +} \ No newline at end of file diff --git a/src/chrome/client/clientToInternal.ts b/src/chrome/client/clientToInternal.ts new file mode 100644 index 000000000..e26914109 --- /dev/null +++ b/src/chrome/client/clientToInternal.ts @@ -0,0 +1,103 @@ +import { ILoadedSource } from '../internal/sources/loadedSource'; +import { BPRecipieInUnresolvedSource } from '../internal/breakpoints/bpRecipie'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { SourcesLogic } from '../internal/sources/sourcesLogic'; +import { Coordinates, LocationInSource } from '../internal/locations/location'; +import { LineColTransformer } from '../../transformers/lineNumberTransformer'; +import { BPRecipiesInUnresolvedSource } from '../internal/breakpoints/bpRecipies'; +import { IBPActionWhenHit, AlwaysBreak, ConditionalBreak } from '../internal/breakpoints/bpActionWhenHit'; +import { HandlesRegistry } from './handlesRegistry'; +import { FramePresentationOrLabel } from '../internal/stackTraces/stackTracePresentation'; +import { createLineNumber, createColumnNumber } from '../internal/locations/subtypes'; +import { parseResourceIdentifier } from '../internal/sources/resourceIdentifier'; +import { PauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions, PauseOnAllRejections, DoNotPauseOnAnyRejections, PauseOnPromiseRejectionsStrategy } from '../internal/exceptions/strategies'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; +import { ISource, SourceAlreadyResolvedToLoadedSource } from '../internal/sources/source'; + +@injectable() +export class ClientToInternal { + public toPauseOnExceptionsStrategy(exceptionFilters: string[]): PauseOnExceptionsStrategy { + if (exceptionFilters.indexOf('all') >= 0) { + return new PauseOnAllExceptions(); + } else if (exceptionFilters.indexOf('uncaught') >= 0) { + return new PauseOnUnhandledExceptions(); + } else { + return new DoNotPauseOnAnyExceptions(); + } + } + + public toPauseOnPromiseRejectionsStrategy(exceptionFilters: string[]): PauseOnPromiseRejectionsStrategy { + if (exceptionFilters.indexOf('promise_reject') >= 0) { + return new PauseOnAllRejections(); + } else { + return new DoNotPauseOnAnyRejections(); + } + } + + // V1 reseted the frames on an onPaused event. Figure out if that is the right thing to do + public getCallFrameById(frameId: number): FramePresentationOrLabel { + return this._handlesRegistry.frames.getObjectById(frameId); + } + + public getSourceFromId(handle: number): ILoadedSource { + return this._handlesRegistry.sources.getObjectById(handle); + } + + public toSource(clientSource: DebugProtocol.Source): ISource { + if (clientSource.path && !clientSource.sourceReference) { + const identifier = parseResourceIdentifier(clientSource.path); + return this._sourcesLogic.createSourceResolver(identifier); + } else if (clientSource.sourceReference) { + const source = this.getSourceFromId(clientSource.sourceReference); + return new SourceAlreadyResolvedToLoadedSource(source); + } else { + throw new Error(`Expected the source to have a path (${clientSource.path}) either-or a source reference (${clientSource.sourceReference})`); + } + } + + public toBPRecipies(args: DebugProtocol.SetBreakpointsArguments): BPRecipiesInUnresolvedSource { + const source = this.toSource(args.source); + const breakpoints = args.breakpoints.map(breakpoint => this.toBPRecipie(source, breakpoint)); + return new BPRecipiesInUnresolvedSource(source, breakpoints); + } + + public toBPRecipie(source: ISource, clientBreakpoint: DebugProtocol.SourceBreakpoint): BPRecipieInUnresolvedSource { + return new BPRecipieInUnresolvedSource( + new LocationInSource(source, this.toLocation(clientBreakpoint)), + this.toBPActionWhenHit(clientBreakpoint)); + } + + public toLocation(location: { line: number; column?: number; }): Coordinates { + const lineNumber = createLineNumber(this._lineColTransformer.convertClientLineToDebugger(location.line)); + const columnNumber = location.column !== undefined ? createColumnNumber(this._lineColTransformer.convertClientColumnToDebugger(location.column)) : undefined; + return new Coordinates(lineNumber, columnNumber); + } + + public toBPActionWhenHit(actionWhenHit: { condition?: string; hitCondition?: string; logMessage?: string; }): IBPActionWhenHit { + let howManyDefined = 0; + howManyDefined += actionWhenHit.condition ? 1 : 0; + howManyDefined += actionWhenHit.hitCondition ? 1 : 0; + howManyDefined += actionWhenHit.logMessage ? 1 : 0; + if (howManyDefined === 0) { + return new AlwaysBreak(); + } else if (howManyDefined === 1) { + if (actionWhenHit.condition) { + return new ConditionalBreak(actionWhenHit.condition); + } else if (actionWhenHit.hitCondition) { + return new ConditionalBreak(actionWhenHit.hitCondition); + } else if (actionWhenHit.logMessage) { + return new ConditionalBreak(actionWhenHit.logMessage); + } else { + throw new Error(`Couldn't parse the desired action when hit for the breakpoint: 'condition' (${actionWhenHit.condition}), 'hitCondition' (${actionWhenHit.hitCondition}) or 'logMessage' (${actionWhenHit.logMessage})`); + } + } else { // howManyDefined >= 2 + throw new Error(`Expected a single one of 'condition' (${actionWhenHit.condition}), 'hitCondition' (${actionWhenHit.hitCondition}) and 'logMessage' (${actionWhenHit.logMessage}) to be defined, yet multiple were defined.`); + } + } + + constructor( + @inject(HandlesRegistry) private readonly _handlesRegistry: HandlesRegistry, + @inject(TYPES.LineColTransformer) private readonly _lineColTransformer: LineColTransformer, + private readonly _sourcesLogic: SourcesLogic) { } +} \ No newline at end of file diff --git a/src/chrome/client/delayMessagesUntilInitializedSession.ts b/src/chrome/client/delayMessagesUntilInitializedSession.ts new file mode 100644 index 000000000..b5990c513 --- /dev/null +++ b/src/chrome/client/delayMessagesUntilInitializedSession.ts @@ -0,0 +1,22 @@ +import { DebugProtocol } from 'vscode-debugprotocol'; +import { InitializedEvent } from 'vscode-debugadapter'; +import { WrappedSessionCommonLogic } from './session'; + +export class DelayMessagesUntilInitializedSession extends WrappedSessionCommonLogic { + private _hasSentInitializedMessage = false; + private _eventsWaitingInitialization: DebugProtocol.Event[] = []; + + public sendEvent(event: DebugProtocol.Event): void { + if (this._hasSentInitializedMessage) { + super.sendEvent(event); + } else if (event instanceof InitializedEvent) { + this._wrappedSession.sendEvent(event); + this._hasSentInitializedMessage = true; + this._eventsWaitingInitialization.forEach(storedEvent => + this._wrappedSession.sendEvent(storedEvent)); + this._eventsWaitingInitialization = []; + } else { + this._eventsWaitingInitialization.push(event); + } + } +} \ No newline at end of file diff --git a/src/chrome/client/doNotPauseWhileSteppingSession.ts b/src/chrome/client/doNotPauseWhileSteppingSession.ts new file mode 100644 index 000000000..97c76bcdc --- /dev/null +++ b/src/chrome/client/doNotPauseWhileSteppingSession.ts @@ -0,0 +1,50 @@ +import { WrappedSessionCommonLogic } from './session'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { utils } from '../..'; + +const steppingRequests = { + continue: true, + next: true, + stepIn: true, + stepOut: true, + pause: true, + restartFrame: true, +}; + +export class DoNotPauseWhileSteppingSession extends WrappedSessionCommonLogic { + private readonly _onFlightSteppingRequests = new Set>(); + + public async dispatchRequest(request: DebugProtocol.Request): Promise { + const response = this._wrappedSession.dispatchRequest(request); + if (this.isSteppingRequest(request)) { + // We track the on-flight stepping requests + this._onFlightSteppingRequests.add(response); + const finallyHandler = () => { this._onFlightSteppingRequests.delete(response); }; + return response.then(finallyHandler, finallyHandler); + } else { + return await response; + } + } + + public async sendEvent(event: DebugProtocol.Event): Promise { + if (event.event === 'stopped') { + // If this is a stopped event, we try to wait until there are no stepping requests in flight, or we timeout + await utils.promiseTimeout(this.waitUntilThereAreNoOnFlightSteppingRequests(), /*timeoutMs=*/300); + } + + this._wrappedSession.sendEvent(event); + } + + private isSteppingRequest(request: DebugProtocol.Request): boolean { + return !!(steppingRequests as any)[request.command]; + } + + private async waitUntilThereAreNoOnFlightSteppingRequests(): Promise { + while (this._onFlightSteppingRequests.size > 0) { + const onFlightRequests = Array.from(this._onFlightSteppingRequests.keys()); + const noFailOnFlightRequests = onFlightRequests.map(promise => promise.catch(_ => { })); + await Promise.all(noFailOnFlightRequests); + // After we waited for all the on flight requests, a new request might just have appeared, so we check and wait again if needed + } + } +} \ No newline at end of file diff --git a/src/chrome/client/eventSender.ts b/src/chrome/client/eventSender.ts new file mode 100644 index 000000000..fae86a964 --- /dev/null +++ b/src/chrome/client/eventSender.ts @@ -0,0 +1,96 @@ +import { ILoadedSource } from '../internal/sources/loadedSource'; +import { ISession } from './session'; +import { LoadedSourceEvent, OutputEvent, BreakpointEvent } from 'vscode-debugadapter'; +import { InternalToClient } from './internalToClient'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { LocationInLoadedSource } from '../internal/locations/location'; +import { IBPRecipieStatus } from '../internal/breakpoints/bpRecipieStatus'; +import { IFormattedExceptionLineDescription } from '../internal/formattedExceptionParser'; +import { StoppedEvent2, ReasonType } from '../stoppedEvent'; +import { Crdp, ChromeDebugLogic } from '../..'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; + +export interface OutputParameters { + readonly output: string; + readonly category: string; + readonly variablesReference?: number; + readonly location?: LocationInLoadedSource; +} + +export interface SourceWasLoadedParameters { + readonly reason: 'new' | 'changed' | 'removed'; + readonly source: ILoadedSource; +} + +export interface BPStatusChangedParameters { + readonly reason: string; + readonly bpRecipieStatus: IBPRecipieStatus; +} + +export interface ExceptionThrownParameters { + readonly exceptionStackTrace: IFormattedExceptionLineDescription[]; + readonly category: string; + readonly location?: LocationInLoadedSource; +} + +export interface DebugeeIsStoppedParameters { + reason: ReasonType; + exception?: Crdp.Runtime.RemoteObject; +} + +export interface IEventsToClientReporter { + sendOutput(params: OutputParameters): void; + sendSourceWasLoaded(params: SourceWasLoadedParameters): Promise; + sendBPStatusChanged(params: BPStatusChangedParameters): Promise; + sendExceptionThrown(params: ExceptionThrownParameters): Promise; + sendDebugeeIsStopped(params: DebugeeIsStoppedParameters): Promise; +} + +@injectable() +export class EventSender implements IEventsToClientReporter { + public sendOutput(params: OutputParameters): void { + const event = new OutputEvent(params.output, params.category) as DebugProtocol.OutputEvent; + + if (params.variablesReference) { + event.body.variablesReference = params.variablesReference; + } + + if (params.location) { + this._internalToClient.toLocationInSource(params.location, event.body); + } + + this._session.sendEvent(event); + } + + public async sendSourceWasLoaded(params: SourceWasLoadedParameters): Promise { + // TODO DIEGO: Should we be using the source tree instead of the source here? + const clientSource = await this._internalToClient.toSource(params.source); + const event = new LoadedSourceEvent(params.reason, clientSource); + + this._session.sendEvent(event); + } + + public async sendBPStatusChanged(params: BPStatusChangedParameters): Promise { + const breakpointStatus = await this._internalToClient.toBPRecipieStatus(params.bpRecipieStatus); + const event = new BreakpointEvent(params.reason, breakpointStatus); + + this._session.sendEvent(event); + } + + public async sendExceptionThrown(params: ExceptionThrownParameters): Promise { + return this.sendOutput({ + output: this._internalToClient.toExceptionStackTracePrintted(params.exceptionStackTrace), + category: params.category, + location: params.location + }); + } + + public async sendDebugeeIsStopped(params: DebugeeIsStoppedParameters): Promise { + return this._session.sendEvent(new StoppedEvent2(params.reason, /*threadId=*/ChromeDebugLogic.THREAD_ID, params.exception)); + } + + constructor( + @inject(TYPES.ISession) private readonly _session: ISession, + private readonly _internalToClient: InternalToClient) { } +} diff --git a/src/chrome/client/handlesRegistry.ts b/src/chrome/client/handlesRegistry.ts new file mode 100644 index 000000000..5b216f140 --- /dev/null +++ b/src/chrome/client/handlesRegistry.ts @@ -0,0 +1,48 @@ +import { ILoadedSource } from '../internal/sources/loadedSource'; +import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; +import { BidirectionalMap } from '../collections/bidirectionalMap'; +import { FramePresentationOrLabel } from '../internal/stackTraces/stackTracePresentation'; +import { injectable } from 'inversify'; + +export class BidirectionalHandles { + private readonly _idToObject = new BidirectionalMap(); + + public getObjectById(id: number): T { + return this._idToObject.getByLeft(id); + } + + public getIdByObject(obj: T): number { + const id = this._idToObject.tryGettingByRight(obj); + if (id !== undefined) { + return id; + } else { + const newId = this._nextHandle++; + this._idToObject.set(newId, obj); + return newId; + } + } + + public toString(): string { + return this._idToObject.toString(); + } + + constructor(private _nextHandle: number) { } +} + +const prefixMultiplier = 1000000; + +@injectable() +export class HandlesRegistry { + // TODO DIEGO: V1 reseted the frames on an onPaused event. Figure out if that is the right thing to do + // We use different prefixes so it's easier to identify the IDs in the logs... + public readonly breakpoints = new BidirectionalHandles>>(888 * prefixMultiplier); + public readonly frames = new BidirectionalHandles>(123 * prefixMultiplier); + public readonly sources = new BidirectionalHandles(555 * prefixMultiplier); + + public toString(): string { + return `Handles {\nBPs:\n${this.breakpoints}\nFrames:\n${this.frames}\nSources:\n${this.sources}\n}`; + } + + constructor() { + } +} diff --git a/src/chrome/client/internalToClient.ts b/src/chrome/client/internalToClient.ts new file mode 100644 index 000000000..ac09d6d93 --- /dev/null +++ b/src/chrome/client/internalToClient.ts @@ -0,0 +1,131 @@ +import { DebugProtocol } from 'vscode-debugprotocol'; +import { utils, LineColTransformer, IExceptionInfoResponseBody } from '../..'; +import * as pathModule from 'path'; +import { asyncAdaptToSinglIntoToMulti } from '../../utils'; +import { ILoadedSource, ILoadedSourceTreeNode } from '../internal/sources/loadedSource'; +import { LocationInLoadedSource } from '../internal/locations/location'; +import { Source } from 'vscode-debugadapter'; +import { RemoveProperty } from '../../typeUtils'; +import { IBPRecipieStatus } from '../internal/breakpoints/bpRecipieStatus'; +import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; +import { HandlesRegistry } from './handlesRegistry'; +import { FramePresentationOrLabel, StackTraceLabel } from '../internal/stackTraces/stackTracePresentation'; +import { IExceptionInformation } from '../internal/exceptions/pauseOnException'; +import { IFormattedExceptionLineDescription } from '../internal/formattedExceptionParser'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; + +interface ClientLocationInSource { + source: DebugProtocol.Source; + line: number; + column: number; +} + +@injectable() +export class InternalToClient { + public readonly toStackFrames = asyncAdaptToSinglIntoToMulti(this, this.toStackFrame); + public readonly toSourceTrees = asyncAdaptToSinglIntoToMulti(this, this.toSourceTree); + public readonly toBPRecipiesStatus = asyncAdaptToSinglIntoToMulti(this, this.toBPRecipieStatus); + + public getFrameId(stackFrame: FramePresentationOrLabel): number { + return this._handlesRegistry.frames.getIdByObject(stackFrame); + } + + public async toStackFrame(stackFrame: FramePresentationOrLabel): Promise { + if (stackFrame.hasCodeFlow()) { + const clientStackFrame: RemoveProperty = { + id: this.getFrameId(stackFrame), + name: stackFrame.name, + presentationHint: stackFrame.presentationHint + }; + + const result = await this.toLocationInSource(stackFrame.location, clientStackFrame); + return result; + } else if (stackFrame instanceof StackTraceLabel) { + return { + id: this.getFrameId(stackFrame), + name: `[${stackFrame.description}]`, + presentationHint: 'label' + } as DebugProtocol.StackFrame; + } else { + throw new Error(`Expected stack frames to be either call frame presentations or label frames, yet it was: ${stackFrame}`); + } + } + + private toSourceLeafs(sources: ILoadedSourceTreeNode[]): Promise { + return Promise.all(sources.map(source => this.toSourceTree(source))); + } + + public async toSourceTree(sourceMetadata: ILoadedSourceTreeNode): Promise { + const source = await this.toSource(sourceMetadata.mainSource); + (source as any).sources = await this.toSourceLeafs(sourceMetadata.relatedSources); + return source; + } + + public async toSource(loadedSource: ILoadedSource): Promise { + const exists = await utils.existsAsync(loadedSource.identifier.canonicalized); + + // if the path exists, do not send the sourceReference + const source = new Source( + pathModule.basename(loadedSource.identifier.textRepresentation), + loadedSource.identifier.textRepresentation, + exists ? undefined : this._handlesRegistry.sources.getIdByObject(loadedSource)); + + return source; + } + + public async toLocationInSource(locationInSource: LocationInLoadedSource, objectToUpdate: T): Promise { + const source = await this.toSource(locationInSource.source); + const clientLocationInSource = { source, line: locationInSource.lineNumber, column: locationInSource.columnNumber }; + this._lineColTransformer.convertDebuggerLocationToClient(clientLocationInSource); + return Object.assign(objectToUpdate, clientLocationInSource); + } + + public async toBPRecipieStatus(bpRecipieStatus: IBPRecipieStatus): Promise { + const clientStatus = { + id: this.toBreakpointId(bpRecipieStatus.recipie), + verified: bpRecipieStatus.isVerified(), + message: bpRecipieStatus.statusDescription + }; + + if (bpRecipieStatus.isBinded()) { + await this.toLocationInSource(bpRecipieStatus.actualLocationInSource, clientStatus); + } + + return clientStatus; + } + + public toBreakpointId(recipie: IBPRecipie>): number { + return this._handlesRegistry.breakpoints.getIdByObject(recipie); + } + + public isZeroBased(): boolean { + const objWithLine = { line: 0 }; + this._lineColTransformer.convertDebuggerLocationToClient(objWithLine); + return objWithLine.line === 0; + } + + public toExceptionInfo(info: IExceptionInformation): IExceptionInfoResponseBody { + return { + exceptionId: info.exceptionId, + description: info.description, + breakMode: info.breakMode, + details: { + message: info.details.message, + formattedDescription: info.details.formattedDescription, + stackTrace: this.toExceptionStackTracePrintted(info.details.stackTrace), + typeName: info.details.typeName, + } + }; + } + + public toExceptionStackTracePrintted(formattedExceptionLines: IFormattedExceptionLineDescription[]): string { + const stackTraceLines = formattedExceptionLines.map(line => line.generateDescription(this.isZeroBased())); + const stackTracePrintted = stackTraceLines.join('\n') + '\n'; + return stackTracePrintted; + } + + constructor( + @inject(HandlesRegistry) private readonly _handlesRegistry: HandlesRegistry, + @inject(TYPES.LineColTransformer) private readonly _lineColTransformer: LineColTransformer) { } +} \ No newline at end of file diff --git a/src/chrome/client/requests.ts b/src/chrome/client/requests.ts new file mode 100644 index 000000000..e4a6c92c7 --- /dev/null +++ b/src/chrome/client/requests.ts @@ -0,0 +1,2 @@ +export const AvailableCommands = new Set(['runInTerminal', 'initialize', 'configurationDone', 'launch', 'attach', 'restart', 'disconnect', 'terminate', 'setBreakpoints', 'setFunctionBreakpoints', 'setExceptionBreakpoints', 'continue', 'next', 'stepIn', 'stepOut', 'stepBack', 'reverseContinue', 'restartFrame', 'goto', 'pause', 'stackTrace', 'scopes', 'variables', 'setVariable', 'source', 'threads', 'terminateThreads', 'modules', 'loadedSources', 'evaluate', 'setExpression', 'stepInTargets', 'gotoTargets', 'completions', 'exceptionInfo']); +export type CommandText = 'runInTerminal' | 'initialize' | 'configurationDone' | 'launch' | 'attach' | 'restart' | 'disconnect' | 'terminate' | 'setBreakpoints' | 'setFunctionBreakpoints' | 'setExceptionBreakpoints' | 'continue' | 'next' | 'stepIn' | 'stepOut' | 'stepBack' | 'reverseContinue' | 'restartFrame' | 'goto' | 'pause' | 'stackTrace' | 'scopes' | 'variables' | 'setVariable' | 'source' | 'threads' | 'terminateThreads' | 'modules' | 'loadedSources' | 'evaluate' | 'setExpression' | 'stepInTargets' | 'gotoTargets' | 'completions' | 'exceptionInfo'; diff --git a/src/chrome/client/session.ts b/src/chrome/client/session.ts new file mode 100644 index 000000000..20b53406d --- /dev/null +++ b/src/chrome/client/session.ts @@ -0,0 +1,52 @@ +import { DebugProtocol } from 'vscode-debugprotocol'; + +export interface ISession { + sendEvent(event: DebugProtocol.Event): void; + shutdown(): void; + sendRequest(command: string, args: any, timeout: number, cb: (response: DebugProtocol.Response) => void): void; + convertClientLineToDebugger(line: number): number; + convertDebuggerLineToClient(line: number): number; + convertClientColumnToDebugger(column: number): number; + convertDebuggerColumnToClient(column: number): number; + dispatchRequest(request: DebugProtocol.Request): Promise; +} + +export abstract class WrappedSessionCommonLogic implements ISession { + public dispatchRequest(request: DebugProtocol.Request): Promise { + return this._wrappedSession.dispatchRequest(request); + } + + public sendRequest(command: string, args: any, timeout: number, cb: (response: DebugProtocol.Response) => void): void { + this._wrappedSession.sendRequest(command, args, timeout, cb); + } + + public sendEvent(event: DebugProtocol.Event): void { + this._wrappedSession.sendEvent(event); + } + + public shutdown(): void { + this._wrappedSession.shutdown(); + } + + public convertClientLineToDebugger(line: number): number { + // LineColTransformer uses this protected method from the session + return this._wrappedSession.convertClientLineToDebugger(line); + } + + public convertClientColumnToDebugger(column: number): number { + // LineColTransformer uses this protected method from the session + return this._wrappedSession.convertClientColumnToDebugger(column); + } + + public convertDebuggerLineToClient(line: number): number { + // LineColTransformer uses this protected method from the session + return this._wrappedSession.convertDebuggerLineToClient(line); + } + + public convertDebuggerColumnToClient(column: number): number { + // LineColTransformer uses this protected method from the session + return this._wrappedSession.convertDebuggerColumnToClient(column); + } + + constructor(protected readonly _wrappedSession: ISession) { } +} \ No newline at end of file diff --git a/src/chrome/collections/printting.ts b/src/chrome/collections/printting.ts new file mode 100644 index 000000000..99cd6b0b2 --- /dev/null +++ b/src/chrome/collections/printting.ts @@ -0,0 +1,24 @@ +/** Methods to print the contents of a collection for logging and debugging purposes (This is not intended for the end-user to see) */ +export function printMap(typeDescription: string, map: { entries(): IterableIterator<[K, V]> }): string { + const elementsPrintted = Array.from(map.entries()).map(entry => `${entry[0]}: ${entry[1]}`).join('; '); + return `${typeDescription} { ${elementsPrintted} }`; +} + +export function printSet(typeDescription: string, set: Set): string { + const elementsPrintted = printElements(Array.from(set), '; '); + return `${typeDescription} { ${elementsPrintted} }`; +} + +export function printArray(typeDescription: string, elements: T[]): string { + const elementsPrintted = printElements(elements, ', '); + return typeDescription ? `${typeDescription} [ ${elementsPrintted} ]` : `[ ${elementsPrintted} ]`; +} + +export function printIterable(typeDescription: string, iterable: IterableIterator): string { + const elementsPrintted = printElements(Array.from(iterable), '; '); + return `${typeDescription} { ${elementsPrintted} }`; +} + +function printElements(elements: T[], separator = '; '): string { + return elements.map(element => `${element}`).join(separator); +} \ No newline at end of file diff --git a/src/chrome/collections/validatedMap.ts b/src/chrome/collections/validatedMap.ts index fb0085d6a..73f4bc206 100644 --- a/src/chrome/collections/validatedMap.ts +++ b/src/chrome/collections/validatedMap.ts @@ -64,7 +64,7 @@ export class ValidatedMap implements IValidatedMap { public set(key: K, value: V): this { if (this.has(key)) { - throw new Error(`Cannot set key ${key} because it already exists`); + // throw new Error(`Cannot set key ${key} because it already exists`); } this._wrappedMap.set(key, value); diff --git a/src/chrome/communication/channel.ts b/src/chrome/communication/channel.ts new file mode 100644 index 000000000..87a5e83ee --- /dev/null +++ b/src/chrome/communication/channel.ts @@ -0,0 +1,25 @@ +import { RequestChannelIdentifier } from './requestsCommunicator'; +import { NamespaceReverseLookupCreator, NamespaceTree } from '../utils/namespaceReverseLookupCreator'; +import { NotificationChannelIdentifier } from './notificationsCommunicator'; +import { ChannelIdentifier } from './channelIdentifier'; + +type ChannelIdentifierNamespace = NamespaceTree; + +const registeredChannels: ChannelIdentifierNamespace = {}; +export function registerChannels(channel: ChannelIdentifierNamespace, name: string): void { + registeredChannels[name] = channel; +} + +let channelToNameMapping: Map | null = null; + +function isChannelIdentifier(obj: any): obj is ChannelIdentifier { + return obj instanceof NotificationChannelIdentifier || obj instanceof RequestChannelIdentifier; +} + +export function getChannelName(channel: ChannelIdentifier): string { + if (channelToNameMapping === null) { + channelToNameMapping = new NamespaceReverseLookupCreator(registeredChannels, isChannelIdentifier, '').create(); + } + + return channelToNameMapping.get(channel); +} diff --git a/src/chrome/communication/channelIdentifier.ts b/src/chrome/communication/channelIdentifier.ts new file mode 100644 index 000000000..8d003e477 --- /dev/null +++ b/src/chrome/communication/channelIdentifier.ts @@ -0,0 +1,3 @@ +export interface ChannelIdentifier { + +} \ No newline at end of file diff --git a/src/chrome/communication/collaborativeDecision.ts b/src/chrome/communication/collaborativeDecision.ts new file mode 100644 index 000000000..80b358523 --- /dev/null +++ b/src/chrome/communication/collaborativeDecision.ts @@ -0,0 +1,83 @@ +import { ValidatedMultiMap } from '../collections/validatedMultiMap'; +import { groupByKey } from '../collections/utilities'; +import { PromiseOrNot } from '../utils/promises'; + +export enum VoteRelevance { + OverrideOtherVotes, + NormalVote, + FallbackVote, + Abstained, +} + +export interface Vote { + relevance: VoteRelevance; + isRelevant(): boolean; + + execute(remainingRelevantVotes: Vote[]): Promise; +} + +export abstract class VoteCommonLogic implements Vote { + public abstract execute(): Promise; + public abstract get relevance(): VoteRelevance; + + public isRelevant(): boolean { + return this.relevance !== VoteRelevance.Abstained; + } +} + +export class ReturnValue extends VoteCommonLogic { + public readonly relevance = VoteRelevance.NormalVote; + + public async execute(): Promise { + return this._value; + } + + constructor(private readonly _value: T) { + super(); + } +} + +export class Abstained extends VoteCommonLogic { + public readonly relevance = VoteRelevance.Abstained; + + public async execute(): Promise { + throw new Error(`An abstained vote cannot be executed`); + } + + constructor(public readonly voter: unknown /* Used for debugging purposes only */) { + super(); + } +} + +export class ExecuteDecisionBasedOnVotes { + private readonly _votesByRelevance: ValidatedMultiMap>; + + public async execute(): Promise { + const overrideVotes = this.getVotesWithCertainRelevance(VoteRelevance.OverrideOtherVotes); + const normalVotes = this.getVotesWithCertainRelevance(VoteRelevance.NormalVote); + const fallbackVotes = this.getVotesWithCertainRelevance(VoteRelevance.FallbackVote); + + // If we have override or normal votes use those, if not use the fallback ones + let allRelevatVotes = overrideVotes.concat(normalVotes); + let allVotes = allRelevatVotes.concat(fallbackVotes); + + if (allVotes.length > 0) { + const winningVote = allVotes[0]; // We'd normally expect to have a single piece in this array + return winningVote.execute(allRelevatVotes); + } else { + return await this._actionIfNoOneVoted(); + } + } + + public getCountOfVotesWithCertainRelevance(relevance: VoteRelevance): number { + return this.getVotesWithCertainRelevance(relevance).length; + } + + private getVotesWithCertainRelevance(relevance: VoteRelevance): Vote[] { + return Array.from(this._votesByRelevance.tryGetting(relevance) || []); + } + + constructor(private readonly _actionIfNoOneVoted: () => PromiseOrNot, votes: Vote[]) { + this._votesByRelevance = groupByKey(votes, vote => vote.relevance); + } +} \ No newline at end of file diff --git a/src/chrome/communication/communicator.ts b/src/chrome/communication/communicator.ts new file mode 100644 index 000000000..6f643f41b --- /dev/null +++ b/src/chrome/communication/communicator.ts @@ -0,0 +1,67 @@ +import { NotificationsCommunicator, NotificationChannelIdentifier, PublisherFunction, SubscriberFunction, PublisherWithParamsFunction } from './notificationsCommunicator'; +import { RequestsCommunicator, RequestChannelIdentifier, RequestHandlerCallback } from './requestsCommunicator'; +import { IExecutionLogger } from '../logging/executionLogger'; +import { PromiseOrNot } from '../utils/promises'; + +export interface ICommunicator { + getPublisher(notificationChannelIdentifier: NotificationChannelIdentifier): PublisherFunction; + getSubscriber(notificationChannelIdentifier: NotificationChannelIdentifier): SubscriberFunction; + subscribe(notificationChannelIdentifier: NotificationChannelIdentifier, listener: (notification: Notification) => void): void; + registerHandler(requestChannelIdentifier: RequestChannelIdentifier, handler: (request: Request) => PromiseOrNot): void; + getRequester(requestChannelIdentifier: RequestChannelIdentifier): RequestHandlerCallback; +} + +export class Communicator implements ICommunicator { + private readonly _notificationsCommunicator = new NotificationsCommunicator(); + private readonly _requestsCommunicator = new RequestsCommunicator(); + + public getPublisher(notificationChannelIdentifier: NotificationChannelIdentifier): PublisherFunction { + return this._notificationsCommunicator.getPublisher(notificationChannelIdentifier); + } + + public getSubscriber(notificationChannelIdentifier: NotificationChannelIdentifier): SubscriberFunction { + return this._notificationsCommunicator.getSubscriber(notificationChannelIdentifier); + } + + public subscribe(notificationChannelIdentifier: NotificationChannelIdentifier, listener: (notification: Notification) => void): void { + return this._notificationsCommunicator.subscribe(notificationChannelIdentifier, listener); + } + + public registerHandler(requestChannelIdentifier: RequestChannelIdentifier, handler: (request: Request) => PromiseOrNot): void { + this._requestsCommunicator.registerHandler(requestChannelIdentifier, handler); + } + + public getRequester(requestChannelIdentifier: RequestChannelIdentifier): RequestHandlerCallback { + return this._requestsCommunicator.getRequester(requestChannelIdentifier); + } +} + +export class LoggingCommunicator implements ICommunicator { + public getPublisher(notificationChannelIdentifier: NotificationChannelIdentifier): PublisherFunction { + const publisher = this._wrappedCommunicator.getPublisher(notificationChannelIdentifier) as PublisherWithParamsFunction; + return (notification => { + return this._logger.logAsyncFunctionCall(`Communicator\\Publish: ${notificationChannelIdentifier}`, publisher, notification); + }) as PublisherFunction; + } + + public getRequester(requestChannelIdentifier: RequestChannelIdentifier): RequestHandlerCallback { + const requester = this._wrappedCommunicator.getRequester(requestChannelIdentifier); + return ((request) => { + return this._logger.logAsyncFunctionCall(`Communicator\\Request: ${requestChannelIdentifier}`, requester, request); + }) as RequestHandlerCallback; + } + + public getSubscriber(notificationChannelIdentifier: NotificationChannelIdentifier): SubscriberFunction { + return this._wrappedCommunicator.getSubscriber(notificationChannelIdentifier); + } + + public subscribe(notificationChannelIdentifier: NotificationChannelIdentifier, listener: (notification: Notification) => void): void { + this._wrappedCommunicator.subscribe(notificationChannelIdentifier, listener); + } + + public registerHandler(requestChannelIdentifier: RequestChannelIdentifier, handler: (request: Request) => Response): void { + this._wrappedCommunicator.registerHandler(requestChannelIdentifier, handler); + } + + constructor(private readonly _wrappedCommunicator: ICommunicator, private readonly _logger: IExecutionLogger) { } +} diff --git a/src/chrome/communication/internalChannels.ts b/src/chrome/communication/internalChannels.ts new file mode 100644 index 000000000..418940a8b --- /dev/null +++ b/src/chrome/communication/internalChannels.ts @@ -0,0 +1,24 @@ +import { NotificationChannelIdentifier } from './notificationsCommunicator'; +import { BPRecipie } from '../internal/breakpoints/bpRecipie'; +import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; +import { registerChannels } from './channel'; +import { PausedEvent } from '../target/events'; +import { Vote } from './collaborativeDecision'; + +const _breakpoints = { + // Notifications + OnUnbounBPRecipieIsNowBound: new NotificationChannelIdentifier>(), + OnPausedOnBreakpoint: new NotificationChannelIdentifier>(), + OnNoPendingBreakpoints: new NotificationChannelIdentifier(), + OnGoingToPauseClient: new NotificationChannelIdentifier(), +}; + +const Breakpoints: Readonly = _breakpoints; + +const _Internal = { + Breakpoints, +}; + +export const Internal: Readonly = _Internal; + +registerChannels(Internal, 'Internal'); diff --git a/src/chrome/communication/listeners.ts b/src/chrome/communication/listeners.ts new file mode 100644 index 000000000..f1d787ab6 --- /dev/null +++ b/src/chrome/communication/listeners.ts @@ -0,0 +1,17 @@ +type Callback = (args: Args) => Result; + +export class Listeners { + private readonly _listeners = [] as Callback[]; + + public add(listener: Callback): void { + this._listeners.push(listener); + } + + public call(args: Args): Result[] { + return this._listeners.map(listener => listener(args)); + } + + public hasListeners(): boolean { + return this._listeners.length > 0; + } +} \ No newline at end of file diff --git a/src/chrome/communication/notificationsCommunicator.ts b/src/chrome/communication/notificationsCommunicator.ts new file mode 100644 index 000000000..739cf0711 --- /dev/null +++ b/src/chrome/communication/notificationsCommunicator.ts @@ -0,0 +1,76 @@ +import { ValidatedMap } from '../collections/validatedMap'; +import { ChannelIdentifier } from './channelIdentifier'; +import { getChannelName } from './channel'; +import { Listeners } from './listeners'; +import { PromiseOrNot } from '../utils/promises'; + +type ResponsesArray = T extends void + ? void + : T[]; + +export type NotificationListener = (notification: Notification) => PromiseOrNot; +export type PublisherWithParamsFunction = (notification: Notification) => PromiseOrNot>; +export type PublisherFunction = Notification extends void + ? () => PromiseOrNot> + : PublisherWithParamsFunction; +export type SubscriberFunction = (listener: NotificationListener) => void; + +// We need the template parameter to force the Communicator to be "strongly typed" from the client perspective +export class NotificationChannelIdentifier<_Notification, _Response = void> implements ChannelIdentifier { + [Symbol.toStringTag]: 'NotificationChannelIdentifier' = 'NotificationChannelIdentifier'; + + constructor(public readonly identifierSymbol: Symbol = Symbol()) { } + + public toString(): string { + return getChannelName(this); + } +} + +class NotificationChannel { + public readonly listeners = new Listeners>(); + public readonly publisher: Publisher = new Publisher(this); + + public toString(): string { + return `${this.identifier}`; + } + + constructor(public readonly identifier: NotificationChannelIdentifier) { } +} + +export class Publisher { + public async publish(notification: Notification): Promise { + if (this.notificationChannel.listeners.hasListeners()) { + return await Promise.all(this.notificationChannel.listeners.call(notification)); + } else { + throw new Error(`Can't publish ${this.notificationChannel.identifier} because no listeners are registered`); + } + } + + constructor(private readonly notificationChannel: NotificationChannel) { } + + public toString(): string { + return `${this.notificationChannel} publisher`; + } +} + +export class NotificationsCommunicator { + private readonly _identifierToChannel = new ValidatedMap, NotificationChannel>(); + + public getPublisher(notificationChannelIdentifier: NotificationChannelIdentifier): PublisherFunction { + const publisher = this.getChannel(notificationChannelIdentifier).publisher; + return (notification => publisher.publish(notification)) as PublisherFunction; + } + + public getSubscriber(notificationChannelIdentifier: NotificationChannelIdentifier): SubscriberFunction { + const channelListeners = this.getChannel(notificationChannelIdentifier).listeners; + return listener => channelListeners.add(listener); + } + + public subscribe(notificationChannelIdentifier: NotificationChannelIdentifier, listener: (notification: Notification) => Response): void { + this.getChannel(notificationChannelIdentifier).listeners.add(listener); + } + + private getChannel(notificationChannelIdentifier: NotificationChannelIdentifier): NotificationChannel { + return this._identifierToChannel.getOrAdd(notificationChannelIdentifier, () => new NotificationChannel(notificationChannelIdentifier)); + } +} diff --git a/src/chrome/communication/requestsCommunicator.ts b/src/chrome/communication/requestsCommunicator.ts new file mode 100644 index 000000000..a41acb3f9 --- /dev/null +++ b/src/chrome/communication/requestsCommunicator.ts @@ -0,0 +1,93 @@ +import { ValidatedMap } from '../collections/validatedMap'; +import { ChannelIdentifier } from './channelIdentifier'; +import { getChannelName } from './channel'; +import { PromiseOrNot } from '../utils/promises'; + +export type RequestHandlerCallback = + Request extends void + ? () => Promise : + NonVoidRequestHandler; + +export type NonVoidRequestHandler = (request: Request) => Promise; + +// We need the template parameter to force the Communicator to be "strongly typed" from the client perspective +export class RequestChannelIdentifier<_Request, _Response> implements ChannelIdentifier { + [Symbol.toStringTag]: 'RequestChannelIdentifier' = 'RequestChannelIdentifier'; + + constructor(public readonly identifierSymbol: Symbol = Symbol()) { } + + public toString(): string { + return getChannelName(this); + } +} + +interface RequestHandler { + isRegistered(): boolean; + call(request: Request): Promise; +} + +class NoRegisteredRequestHandler implements RequestHandler { + public isRegistered(): boolean { + return false; + } + + public call(request: Request): Promise { + throw new Error(`Can't execute request <${request}> because no handler has yet registered to handle requests for channel <${this._channel}>`); + } + + constructor(private readonly _channel: RequestChannel) { } +} + +class RegisteredRequestHandler implements RequestHandler { + public isRegistered(): boolean { + return true; + } + + public call(request: Request): Promise { + return (this._callback as NonVoidRequestHandler)(request); + } + + constructor(private readonly _callback: RequestHandlerCallback) { } +} + +class RequestChannel { + public readonly requester: Requester = new Requester(this); + public handler: RequestHandler = new NoRegisteredRequestHandler(this); + + public toString(): string { + return `#${this._identifier}`; + } + + constructor(private readonly _identifier: RequestChannelIdentifier) { } +} + +export class Requester { + constructor(private readonly _requestChannel: RequestChannel) { } + + public request(request: Request): Promise { + return this._requestChannel.handler.call(request); + } +} + +export class RequestsCommunicator { + private readonly _identifierToChannel = new ValidatedMap, RequestChannel>(); + + public registerHandler(requestChannelIdentifier: RequestChannelIdentifier, + handler: (request: Request) => PromiseOrNot): void { + const existingHandler = this.getChannel(requestChannelIdentifier).handler; + if (!existingHandler.isRegistered()) { + this.getChannel(requestChannelIdentifier).handler = new RegisteredRequestHandler(handler as RequestHandlerCallback); + } else { + throw new Error(`Can't register a handler for ${requestChannelIdentifier} because a handler has already been registered (${existingHandler})`); + } + } + + public getRequester(requestChannelIdentifier: RequestChannelIdentifier): RequestHandlerCallback { + const requester = this.getChannel(requestChannelIdentifier).requester; + return ((request: Request) => requester.request(request)) as RequestHandlerCallback; + } + + private getChannel(requestChannelIdentifier: RequestChannelIdentifier): RequestChannel { + return this._identifierToChannel.getOrAdd(requestChannelIdentifier, () => new RequestChannel(requestChannelIdentifier)); + } +} diff --git a/src/chrome/communication/targetChannels.ts b/src/chrome/communication/targetChannels.ts new file mode 100644 index 000000000..6a4325d0a --- /dev/null +++ b/src/chrome/communication/targetChannels.ts @@ -0,0 +1,23 @@ +import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; +import { NotificationChannelIdentifier } from './notificationsCommunicator'; +import { Breakpoint } from '../internal/breakpoints/breakpoint'; +import { ScriptParsedEvent, PausedEvent } from '../target/events'; +import { registerChannels } from './channel'; + +const _debugger = { + // Notifications + OnAsyncBreakpointResolved: new NotificationChannelIdentifier>(), + OnScriptParsed: new NotificationChannelIdentifier(), + OnPaused: new NotificationChannelIdentifier(), + OnResumed: new NotificationChannelIdentifier(), +}; + +const Debugger: Readonly = _debugger; + +const _Target = { + Debugger, +}; + +export const Target: Readonly = _Target; + +registerChannels(Target, 'Target'); diff --git a/src/chrome/communication/transformedListenerRegistry.ts b/src/chrome/communication/transformedListenerRegistry.ts new file mode 100644 index 000000000..8aa32c94a --- /dev/null +++ b/src/chrome/communication/transformedListenerRegistry.ts @@ -0,0 +1,24 @@ +import { Listeners } from './listeners'; +import { PromiseOrNot } from '../utils/promises'; + +export class TransformedListenerRegistry { + private readonly _transformedListeners = new Listeners(); + + public registerListener(transformedListener: (params: T) => void) { + this._transformedListeners.add(transformedListener); + } + + public async install(): Promise { + await this._registerOriginalListener(async originalParameters => { + const transformedParameters = await this._transformation(originalParameters); + return this._transformedListeners.call(transformedParameters); + }); + return this; + } + + constructor( + public readonly _description: string, // This description is only used for debugging purposes + private readonly _registerOriginalListener: (originalListener: (originalParameters: O) => void) => PromiseOrNot, + private readonly _transformation: (originalParameters: O) => PromiseOrNot) { + } +} diff --git a/src/chrome/consoleHelper.ts b/src/chrome/consoleHelper.ts index fa0ecde2f..378ead93b 100644 --- a/src/chrome/consoleHelper.ts +++ b/src/chrome/consoleHelper.ts @@ -5,8 +5,11 @@ import { Protocol as Crdp } from 'devtools-protocol'; import * as Color from 'color'; import * as variables from './variables'; +import { ExceptionDetails } from './target/events'; +import { IScript } from './internal/scripts/script'; +import { CodeFlowStackTrace } from './internal/stackTraces/stackTrace'; -export function formatExceptionDetails(e: Crdp.Runtime.ExceptionDetails): string { +export function formatExceptionDetails(e: ExceptionDetails): string { if (!e.exception) { return `${e.text || 'Uncaught Error'}\n${stackTraceToString(e.stackTrace)}`; } @@ -17,7 +20,7 @@ export function formatExceptionDetails(e: Crdp.Runtime.ExceptionDetails): string export const clearConsoleCode = '\u001b[2J'; -export function formatConsoleArguments(type: Crdp.Runtime.ConsoleAPICalledEvent['type'], args: Crdp.Runtime.RemoteObject[], stackTrace?: Crdp.Runtime.StackTrace): { args: Crdp.Runtime.RemoteObject[], isError: boolean } { +export function formatConsoleArguments(type: Crdp.Runtime.ConsoleAPICalledEvent['type'], args: Crdp.Runtime.RemoteObject[], stackTrace?: CodeFlowStackTrace): { args: Crdp.Runtime.RemoteObject[], isError: boolean } { switch (type) { case 'log': case 'debug': @@ -50,7 +53,7 @@ export function formatConsoleArguments(type: Crdp.Runtime.ConsoleAPICalledEvent[ startMsg += ': ' + formattedGroupParams.shift().value; } - args = [{ type: 'string', value: startMsg}, ...formattedGroupParams]; + args = [{ type: 'string', value: startMsg }, ...formattedGroupParams]; break; case 'endGroup': args = [{ type: 'string', value: '‹End group›' }]; @@ -206,15 +209,15 @@ function formatArg(formatSpec: string, arg: Crdp.Runtime.RemoteObject): string | } } -function stackTraceToString(stackTrace: Crdp.Runtime.StackTrace): string { +function stackTraceToString(stackTrace: CodeFlowStackTrace): string { if (!stackTrace) { return ''; } - return stackTrace.callFrames + return stackTrace.codeFlowFrames .map(frame => { - const fnName = frame.functionName || (frame.url ? '(anonymous)' : '(eval)'); - const fileName = frame.url ? frame.url : 'eval'; + const fnName = frame.name; + const fileName = frame.script.developmentSource.identifier.textRepresentation; return ` at ${fnName} (${fileName}:${frame.lineNumber + 1}:${frame.columnNumber})`; }) .join('\n'); diff --git a/src/chrome/crdpMultiplexing/crdpMultiplexor.ts b/src/chrome/crdpMultiplexing/crdpMultiplexor.ts deleted file mode 100644 index c417686ad..000000000 --- a/src/chrome/crdpMultiplexing/crdpMultiplexor.ts +++ /dev/null @@ -1,218 +0,0 @@ -/*--------------------------------------------------------- - * Copyright (C) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------*/ - -import { LikeSocket } from 'noice-json-rpc'; -import { logger } from 'vscode-debugadapter'; - -/* Rational: The debug adapter only exposes the debugging capabilities of the Chrome Debugging Protocol. - We want to be able to connect other components to expose other of the capabilities to the users. - We are trying to do this by creating a multiplexor that will take one connection to a Chrome Debugging Protocol websocket, - and simulate from that that we have actually many independent connections to several Chrome Debugging Protocol websockets. - Given that implementing truly independent connections is not trivial, we are choosing to implement only the features that we - seem to need so far to support a component for an external Console, and an external DOM Explorer. - - The way we are going to make that work is that we'll pass the actual websocket to chrome/node to the Multiplexor, and then we are going - to requests two channels from it. One will be the debugger channel, that will be used by the traditional debug adapter for everything it does. - Another channel will be the extraCRDPEndpoint channel that will be offered thorugh the client using a websocket port (so it'll simulate that - this is an actual connection to chrome or node), so we can connect any utilities that we want there. - - In the future, if we need to, it's easy to modify this multiplexor to support more than 2 channels. -*/ - -/* Assumptions made to implement this multiplexor: - 1. The message IDs of CRDP don't need to be sent in order - 2. The Domain.enable messages don't have any side-effects (We might send them multiple times) - 3. The clients are ready to recieve domain messages when they send the Domain.enable message (A better design would be to assume that they are ready after we've sent the response for that message, but this approach seems to be working so far) - 4. The clients never disable any Domain - 5. The clients enable all domains in the first 60 seconds after they've connected - */ - -function extractDomain(method: string): string { - const methodParts = method.split('.'); - if (methodParts.length === 2) { - return methodParts[0]; - } else { - throwCriticalError(`The method ${method} didn't have exactly two parts`); - return 'Unknown'; - } -} - -function encodifyChannel(channelId: number, id: number): number { - return id * 10 + channelId; -} - -function decodifyChannelId(encodifiedId: number): number { - return encodifiedId % 10; -} -function decodifyId(encodifiedId: number): number { - return Math.floor(encodifiedId / 10); -} - -function throwCriticalError(message: string): void { - logger.error('CRDP Multiplexor - CRITICAL-ERROR: ' + message); - throw new Error(message); -} - -export class CRDPMultiplexor { - private _channels: CRDPChannel[] = []; - - private onMessage(data: string): void { - const message = JSON.parse(data); - if (message.id !== undefined) { - this.onResponseMessage(message, data); - } else if (message.method) { - this.onDomainNotification(message, data); - } else { - throwCriticalError(`Message didn't have id nor method: ${data}`); - } - } - - private onResponseMessage(message: {id: number}, data: string): void { - // The message is a response, so it should only go to the channel that requested this - const channel = this._channels[decodifyChannelId(message.id)]; - if (channel) { - message.id = decodifyId(message.id); - data = JSON.stringify(message); - channel.callMessageCallbacks(data); - } else { - throwCriticalError(`Didn't find channel for message with id: ${message.id} and data: <${data}>`); - } - } - - private onDomainNotification(message: {method: string}, data: string): void { - // The message is a notification, so it should go to all channels. The channels itself will filter based on the enabled domains - const domain = extractDomain(message.method); - for (const channel of this._channels) { - channel.callDomainMessageCallbacks(domain, data); - } - } - - constructor(private _wrappedLikeSocket: LikeSocket) { - this._wrappedLikeSocket.on('message', data => this.onMessage(data)); - } - - public addChannel(channelName: string): CRDPChannel { - if (this._channels.length >= 10) { - throw new Error(`Only 10 channels are supported`); - } - - const channel = new CRDPChannel(channelName, this._channels.length, this); - this._channels.push(channel); - return channel; - } - - public send(channel: CRDPChannel, data: string): void { - const message = JSON.parse(data); - if (message.id !== undefined) { - message.id = encodifyChannel(channel.id, message.id); - data = JSON.stringify(message); - } else { - throwCriticalError(`Channel [${channel.name}] sent a message without an id: ${data}`); - } - this._wrappedLikeSocket.send(data); - } - - public addListenerOfNonMultiplexedEvent(event: string, cb: Function): void { - this._wrappedLikeSocket.on(event, cb); - } - - public removeListenerOfNonMultiplexedEvent(event: string, cb: Function): void { - this._wrappedLikeSocket.removeListener(event, cb); - } -} - -export class CRDPChannel implements LikeSocket { - private static timeToPreserveMessagesInMillis = 60 * 1000; - - private _messageCallbacks: Function[] = []; - private _enabledDomains: { [domain: string]: boolean } = {}; - private _pendingMessagesForDomain: { [domain: string]: string[] } = {}; - - public callMessageCallbacks(messageData: string): void { - this._messageCallbacks.forEach(callback => callback(messageData)); - } - - public callDomainMessageCallbacks(domain: string, messageData: string): void { - if (this._enabledDomains[domain]) { - this.callMessageCallbacks(messageData); - } else if (this._pendingMessagesForDomain !== null) { - // We give clients 60 seconds after they connect to the channel to enable domains and receive all messages - this.storeMessageForLater(domain, messageData); - } - } - - private storeMessageForLater(domain: string, messageData: string): void { - let messagesForDomain = this._pendingMessagesForDomain[domain]; - if (messagesForDomain === undefined) { - this._pendingMessagesForDomain[domain] = []; - messagesForDomain = this._pendingMessagesForDomain[domain]; - } - - // Usually this is too much logging, but we might use it while debugging - // logger.log(`CRDP Multiplexor - Storing message to channel ${this.name} for ${domain} for later: ${messageData}`); - messagesForDomain.push(messageData); - } - - constructor(public name: string, public id: number, private _multiplexor: CRDPMultiplexor) { } - - public send(messageData: string): void { - const message = JSON.parse(messageData); - const method = message.method; - const isEnableMethod = method && method.endsWith('.enable'); - let domain; - - if (isEnableMethod) { - domain = extractDomain(method); - this._enabledDomains[domain] = true; - } - - this._multiplexor.send(this, messageData); - - if (isEnableMethod) { - this.sendUnsentPendingMessages(domain); - } - } - - private sendUnsentPendingMessages(domain: string): void { - if (this._pendingMessagesForDomain !== null) { - const pendingMessagesData = this._pendingMessagesForDomain[domain]; - if (pendingMessagesData !== undefined && this._messageCallbacks.length) { - logger.log(`CRDP Multiplexor - Sending pending messages of domain ${domain}(Count = ${pendingMessagesData.length})`); - delete this._pendingMessagesForDomain[domain]; - pendingMessagesData.forEach(pendingMessageData => { - this.callDomainMessageCallbacks(domain, pendingMessageData); - }); - } - } - } - - private discardUnsentPendingMessages(): void { - logger.log(`CRDP Multiplexor - Discarding unsent pending messages for domains: ${Object.keys(this._pendingMessagesForDomain).join(', ')}`); - this._pendingMessagesForDomain = null; - } - - public on(event: string, cb: Function): void; - public on(event: 'open', cb: (ws: LikeSocket) => void): void; - public on(event: 'message', cb: (data: string) => void): void; - public on(event: string, cb: Function): void { - if (event === 'message') { - if (this._messageCallbacks.length === 0) { - setTimeout(() => this.discardUnsentPendingMessages(), CRDPChannel.timeToPreserveMessagesInMillis); - } - - this._messageCallbacks.push(cb); - } else { - this._multiplexor.addListenerOfNonMultiplexedEvent(event, cb); - } - } - - public removeListener(event: string, cb: Function): void { - if (event === 'message') { - const index = this._messageCallbacks.indexOf(cb); - this._messageCallbacks.splice(index, 1); - } else { - this._multiplexor.removeListenerOfNonMultiplexedEvent(event, cb); - } - } -} diff --git a/src/chrome/crdpMultiplexing/webSocketToLikeSocketProxy.ts b/src/chrome/crdpMultiplexing/webSocketToLikeSocketProxy.ts index 72c280ffe..9f8c026a6 100644 --- a/src/chrome/crdpMultiplexing/webSocketToLikeSocketProxy.ts +++ b/src/chrome/crdpMultiplexing/webSocketToLikeSocketProxy.ts @@ -8,7 +8,7 @@ import { LikeSocket } from 'noice-json-rpc'; export class WebSocketToLikeSocketProxy { private _server: WebSocket.Server; - private _currentlyOpenedWebSocket: WebSocket = null; + private _currentlyOpenedWebSocket: WebSocket | null = null; constructor(private _port: number, private _socket: LikeSocket) { } @@ -48,7 +48,7 @@ export class WebSocketToLikeSocketProxy { this._currentlyOpenedWebSocket = null; }); - this._socket.on('message', data => { + this._socket.on('message', (data: string) => { logger.log(`CRDP Proxy - Target to Client: ${data}`); openedWebSocket.send(data); }); diff --git a/src/chrome/debugee/debugeeLauncher.ts b/src/chrome/debugee/debugeeLauncher.ts new file mode 100644 index 000000000..893de13f9 --- /dev/null +++ b/src/chrome/debugee/debugeeLauncher.ts @@ -0,0 +1,16 @@ +import { ITelemetryPropertyCollector } from '../../telemetry'; +import { ILaunchRequestArgs } from '../../debugAdapterInterfaces'; + +export interface ILaunchResult { + address?: string; + port?: number; + url?: string; +} + +export interface IDebuggeeLauncher { + launch(args: ILaunchRequestArgs, telemetryPropertyCollector: ITelemetryPropertyCollector): Promise; +} + +export interface IDebuggeeRunner { + run(telemetryPropertyCollector: ITelemetryPropertyCollector): Promise; +} \ No newline at end of file diff --git a/src/chrome/dependencyInjection.ts/bind.ts b/src/chrome/dependencyInjection.ts/bind.ts new file mode 100644 index 000000000..46594fa47 --- /dev/null +++ b/src/chrome/dependencyInjection.ts/bind.ts @@ -0,0 +1,92 @@ +import { Container, interfaces } from 'inversify'; +import { TYPES } from './types'; +import { IDOMInstrumentationBreakpoints, CDTPDOMDebugger, IBrowserNavigation, CDTPPage, IDebugeeVersionProvider, CDTPBrowser } from '../target/cdtpSmallerModules'; +import { IEventsToClientReporter, EventSender } from '../client/eventSender'; +import { IDebugeeExecutionControl, ControlDebugeeExecution, IDebugeeStepping } from '../target/controlDebugeeExecution'; +import { IPauseOnExceptions, IAsyncDebuggingConfiguration, IScriptSources, CDTPDebugger } from '../target/cdtpDebugger'; +import { IBreakpointFeaturesSupport, BreakpointFeaturesSupport } from '../target/breakpointFeaturesSupport'; +import { IStackTracePresentationLogicProvider, StackTracesLogic } from '../internal/stackTraces/stackTracesLogic'; +import { CDTPStackTraceParser } from '../target/cdtpStackTraceParser'; +import { CDTPLocationParser } from '../target/cdtpLocationParser'; +import { SourcesLogic } from '../internal/sources/sourcesLogic'; +import { CDTPScriptsRegistry } from '../target/cdtpScriptsRegistry'; +import { ClientToInternal } from '../client/clientToInternal'; +import { InternalToClient } from '../client/internalToClient'; +import { BreakpointsLogic } from '../internal/breakpoints/breakpointsLogic'; +import { PauseOnExceptionOrRejection } from '../internal/exceptions/pauseOnException'; +import { Stepping } from '../internal/stepping/stepping'; +import { DotScriptCommand } from '../internal/sources/features/dotScriptsCommand'; +import { BreakpointsRegistry } from '../internal/breakpoints/breakpointsRegistry'; +import { ReAddBPsWhenSourceIsLoaded } from '../internal/breakpoints/features/reAddBPsWhenSourceIsLoaded'; +import { PauseScriptLoadsToSetBPs } from '../internal/breakpoints/features/pauseScriptLoadsToSetBPs'; +import { BPRecipieInLoadedSourceLogic } from '../internal/breakpoints/bpRecipieInLoadedSourceLogic'; +import { CDTPDiagnostics } from '../target/cdtpDiagnostics'; +import { DeleteMeScriptsRegistry } from '../internal/scripts/scriptsRegistry'; +import { SyncStepping } from '../internal/stepping/features/syncStepping'; +import { AsyncStepping } from '../internal/stepping/features/asyncStepping'; +import { BreakpointIdRegistry } from '../target/breakpointIdRegistry'; +import { ExceptionThrownEventProvider } from '../target/exceptionThrownEventProvider'; +import { ExecutionContextEventsProvider } from '../target/executionContextEventsProvider'; +import { IInspectDebugeeState, InspectDebugeeState } from '../target/inspectDebugeeState'; +import { IUpdateDebugeeState, UpdateDebugeeState } from '../target/updateDebugeeState'; +import { SmartStepLogic } from '../internal/features/smartStep'; +import { LineColTransformer } from '../../transformers/lineNumberTransformer'; +import { ChromeDebugLogic } from '../chromeDebugAdapter'; +import { CDTPOnScriptParsedEventProvider, IScriptParsedProvider } from '../target/cdtpOnScriptParsedEventProvider'; +import { CDTPDebuggerEventsProvider, ICDTPDebuggerEventsProvider } from '../target/cdtpDebuggerEventsProvider'; +import { ITargetBreakpoints, CDTPTargetBreakpoints } from '../target/cdtpTargetBreakpoints'; +import { MethodsCalledLogger } from '../logging/methodsCalledLogger'; + +export function bindAll(di: Container) { + bind(di, TYPES.IDOMInstrumentationBreakpoints, CDTPDOMDebugger); + bind(di, TYPES.IAsyncDebuggingConfiguration, CDTPDebugger); + bind(di, TYPES.IScriptSources, CDTPDebugger); + bind(di, TYPES.IStackTracePresentationLogicProvider, SmartStepLogic); + // bind(di, TYPES.IStackTracePresentationLogicProvider, SkipFilesLogic); + bind(di, TYPES.IEventsToClientReporter, EventSender); + bind(di, TYPES.IDebugeeExecutionControl, ControlDebugeeExecution); + bind(di, TYPES.IPauseOnExceptions, CDTPDebugger); + bind(di, TYPES.IBreakpointFeaturesSupport, BreakpointFeaturesSupport); + bind(di, TYPES.IInspectDebugeeState, InspectDebugeeState); + bind(di, TYPES.IUpdateDebugeeState, UpdateDebugeeState); + bind(di, TYPES.CDTPStackTraceParser, CDTPStackTraceParser); + bind(di, TYPES.CDTPLocationParser, CDTPLocationParser); + bind(di, TYPES.ChromeDebugLogic, ChromeDebugLogic); + bind(di, TYPES.SourcesLogic, SourcesLogic); + bind(di, TYPES.CDTPScriptsRegistry, CDTPScriptsRegistry); + bind(di, TYPES.ClientToInternal, ClientToInternal); + bind(di, TYPES.InternalToClient, InternalToClient); + bind(di, TYPES.StackTracesLogic, StackTracesLogic); + bind(di, TYPES.BreakpointsLogic, BreakpointsLogic); + bind(di, TYPES.PauseOnExceptionOrRejection, PauseOnExceptionOrRejection); + bind(di, TYPES.Stepping, Stepping); + bind(di, TYPES.DotScriptCommand, DotScriptCommand); + bind(di, TYPES.CDTPDebugger, CDTPDebugger); + bind(di, TYPES.BreakpointsRegistry, BreakpointsRegistry); + bind(di, TYPES.ReAddBPsWhenSourceIsLoaded, ReAddBPsWhenSourceIsLoaded); + bind(di, TYPES.PauseScriptLoadsToSetBPs, PauseScriptLoadsToSetBPs); + bind(di, TYPES.BPRecipieInLoadedSourceLogic, BPRecipieInLoadedSourceLogic); + bind(di, TYPES.EventSender, EventSender); + bind(di, TYPES.CDTPDiagnostics, CDTPDiagnostics); + bind(di, TYPES.DeleteMeScriptsRegistry, DeleteMeScriptsRegistry); + // bind(di, TYPES.BaseSourceMapTransformer, BaseSourceMapTransformer); + // bind(di, TYPES.BasePathTransformer, BasePathTransformer); + bind(di, TYPES.SyncStepping, SyncStepping); + bind(di, TYPES.AsyncStepping, AsyncStepping); + bind(di, TYPES.BreakpointIdRegistry, BreakpointIdRegistry); + bind(di, TYPES.ExceptionThrownEventProvider, ExceptionThrownEventProvider); + bind(di, TYPES.ExecutionContextEventsProvider, ExecutionContextEventsProvider); + bind(di, TYPES.LineColTransformer, LineColTransformer); + bind(di, TYPES.IDebugeeStepping, ControlDebugeeExecution); + bind(di, TYPES.IBrowserNavigation, CDTPPage); + bind(di, TYPES.IScriptParsedProvider, CDTPOnScriptParsedEventProvider); + bind(di, TYPES.ICDTPDebuggerEventsProvider, CDTPDebuggerEventsProvider); + bind(di, TYPES.IDebugeeVersionProvider, CDTPBrowser); + bind(di, TYPES.ITargetBreakpoints, CDTPTargetBreakpoints); +} + +function bind(container: Container, serviceIdentifier: interfaces.ServiceIdentifier, newable: interfaces.Newable): void { + container.bind(serviceIdentifier).to(newable).inSingletonScope().onActivation((_context, object) => { + return new MethodsCalledLogger(object, serviceIdentifier.toString()).wrapped(); + }); +} diff --git a/src/chrome/dependencyInjection.ts/di.ts b/src/chrome/dependencyInjection.ts/di.ts new file mode 100644 index 000000000..dce88adb0 --- /dev/null +++ b/src/chrome/dependencyInjection.ts/di.ts @@ -0,0 +1,38 @@ +import { Container, interfaces } from 'inversify'; +import { bindAll } from './bind'; + +// Hides the current DI framework from the rest of our implementation +export class DependencyInjection { + private readonly _container = new Container({ autoBindInjectable: true, defaultScope: 'Singleton' }); + + constructor() { + } + + public configureClass(interfaceClass: interfaces.Newable | symbol, value: interfaces.Newable): this { + this._container.bind(interfaceClass).to(value).inSingletonScope(); + return this; + } + + public unconfigure(interfaceClass: interfaces.Newable | symbol): this { + this._container.unbind(interfaceClass); + return this; + } + + public configureValue(valueClass: interfaces.Newable | symbol, value: T): this { + this._container.bind(valueClass).toConstantValue(value); + return this; + } + + public createClassWithDI(classToCreate: interfaces.Newable): T { + return this._container.get(classToCreate); + } + + public createComponent(componentIdentifier: symbol): T { + return this._container.get(componentIdentifier); + } + + public bindAll(): this { + bindAll(this._container); + return this; + } +} diff --git a/src/chrome/dependencyInjection.ts/types.ts b/src/chrome/dependencyInjection.ts/types.ts index dc992f8f1..a669682e5 100644 --- a/src/chrome/dependencyInjection.ts/types.ts +++ b/src/chrome/dependencyInjection.ts/types.ts @@ -1,9 +1,63 @@ import 'reflect-metadata'; // TODO: Add all necesary types so we can use inversifyjs to create our components - const TYPES = { + ISession: Symbol.for('ISession'), + communicator: Symbol.for('communicator'), + CDTPClient: Symbol.for('chromeConnection.api'), + IDOMInstrumentationBreakpoints: Symbol.for('IDOMInstrumentationBreakpoints'), + IEventsToClientReporter: Symbol.for('IEventsToClientReporter'), + IDebugeeExecutionControl: Symbol.for('IDebugeeExecutionControl'), + IPauseOnExceptions: Symbol.for('IPauseOnExceptions'), + IBreakpointFeaturesSupport: Symbol.for('IBreakpointFeaturesSupport'), + IAsyncDebuggingConfiguration: Symbol.for('IAsyncDebuggingConfiguration'), + IStackTracePresentationLogicProvider: Symbol.for('IStackTracePresentationLogicProvider'), + IScriptSources: Symbol.for('IScriptSources'), EventsConsumedByConnectedCDA: Symbol.for('EventsConsumedByConnectedCDA'), + ICDTPDebuggerEventsProvider: Symbol.for('ICDTPDebuggerEventsProvider'), + IDebuggeeLauncher: Symbol.for('IDebuggeeLauncher'), + CDTPStackTraceParser: Symbol.for('CDTPStackTraceParser'), + CDTPLocationParser: Symbol.for('CDTPLocationParser'), + ChromeDebugLogic: Symbol.for('ChromeDebugLogic'), + SourcesLogic: Symbol.for('SourcesLogic'), + CDTPScriptsRegistry: Symbol.for('CDTPScriptsRegistry'), + ClientToInternal: Symbol.for('ClientToInternal'), + InternalToClient: Symbol.for('InternalToClient'), + StackTracesLogic: Symbol.for('StackTracesLogic'), + BreakpointsLogic: Symbol.for('BreakpointsLogic'), + PauseOnExceptionOrRejection: Symbol.for('PauseOnExceptionOrRejection'), + Stepping: Symbol.for('Stepping'), + DotScriptCommand: Symbol.for('DotScriptCommand'), + CDTPDebugger: Symbol.for('CDTPDebugger'), + BreakpointsRegistry: Symbol.for('BreakpointsRegistry'), + ReAddBPsWhenSourceIsLoaded: Symbol.for('ReAddBPsWhenSourceIsLoaded'), + PauseScriptLoadsToSetBPs: Symbol.for('PauseScriptLoadsToSetBPs'), + BPRecipieInLoadedSourceLogic: Symbol.for('BPRecipieInLoadedSourceLogic'), + EventSender: Symbol.for('EventSender'), + CDTPDiagnostics: Symbol.for('CDTPDiagnostics'), + DeleteMeScriptsRegistry: Symbol.for('DeleteMeScriptsRegistry'), + BaseSourceMapTransformer: Symbol.for('BaseSourceMapTransformer'), + BasePathTransformer: Symbol.for('BasePathTransformer'), + SyncStepping: Symbol.for('SyncStepping'), + AsyncStepping: Symbol.for('AsyncStepping'), + ConnectedCDAConfiguration: Symbol.for('ConnectedCDAConfiguration'), + BreakpointIdRegistry: Symbol.for('BreakpointIdRegistry'), + ExceptionThrownEventProvider: Symbol.for('ExceptionThrownEventProvider'), + ExecutionContextEventsProvider: Symbol.for('ExecutionContextEventsProvider'), + IInspectDebugeeState: Symbol.for('IInspectDebugeeState'), + IUpdateDebugeeState: Symbol.for('IUpdateDebugeeState'), + LineColTransformer: Symbol.for('LineColTransformer'), + ChromeConnection: Symbol.for('ChromeConnection'), + IDebugeeStepping: Symbol.for('IDebugeeStepping'), + IDebugeeVersionProvider: Symbol.for('IDebugeeVersionProvider'), + IBrowserNavigation: Symbol.for('IBrowserNavigation'), + IPausedOverlay: Symbol.for('IPausedOverlay'), + INetworkCacheConfiguration: Symbol.for('INetworkCacheConfiguration'), + ISupportedDomains: Symbol.for('ISupportedDomains'), + IDebugeeRunner: Symbol.for('IDebugeeRunner'), + ICDTPRuntime: Symbol.for('ICDTPRuntime'), + IScriptParsedProvider: Symbol.for('IScriptParsedProvider'), + ITargetBreakpoints: Symbol.for('ITargetBreakpoints'), }; export { TYPES }; diff --git a/src/chrome/extensibility/extensibilityPoints.ts b/src/chrome/extensibility/extensibilityPoints.ts new file mode 100644 index 000000000..82a618a42 --- /dev/null +++ b/src/chrome/extensibility/extensibilityPoints.ts @@ -0,0 +1,44 @@ +import { ChromeConnection, ITargetFilter } from '../chromeConnection'; +import { BasePathTransformer } from '../../transformers/basePathTransformer'; +import { BaseSourceMapTransformer } from '../../transformers/baseSourceMapTransformer'; +import { LineColTransformer } from '../../transformers/lineNumberTransformer'; +import { ILaunchRequestArgs, IAttachRequestArgs } from '../../debugAdapterInterfaces'; +import { interfaces } from 'inversify'; +import { IDebuggeeLauncher, IDebuggeeRunner } from '../debugee/debugeeLauncher'; +import { ConnectedCDAConfiguration } from '../client/chromeDebugAdapter/cdaConfiguration'; + +export interface IExtensibilityPoints { + isPromiseRejectExceptionFilterEnabled: boolean; + debugeeLauncher: interfaces.Newable; + debugeeRunner: interfaces.Newable; + + targetFilter?: ITargetFilter; + logFilePath: string; + + chromeConnection?: typeof ChromeConnection; + pathTransformer?: { new(configuration: ConnectedCDAConfiguration): BasePathTransformer }; + sourceMapTransformer?: { new(configuration: ConnectedCDAConfiguration): BaseSourceMapTransformer }; + lineColTransformer?: { new(configuration: ConnectedCDAConfiguration): LineColTransformer }; + + updateArguments(argumentsFromClient: T): T; +} + +export class OnlyProvideCustomLauncherExtensibilityPoints implements IExtensibilityPoints { + public readonly isPromiseRejectExceptionFilterEnabled = false; + + targetFilter?: ITargetFilter; + chromeConnection?: typeof ChromeConnection; + pathTransformer?: new () => BasePathTransformer; + sourceMapTransformer?: new (configuration: ConnectedCDAConfiguration) => BaseSourceMapTransformer; + lineColTransformer?: new (configuration: ConnectedCDAConfiguration) => LineColTransformer; + + public updateArguments(argumentsFromClient: T): T { + return argumentsFromClient; + } + + constructor( + public readonly debugeeLauncher: interfaces.Newable, + public readonly debugeeRunner: interfaces.Newable, + public readonly logFilePath: string) { + } +} \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/bpActionWhenHit.ts b/src/chrome/internal/breakpoints/bpActionWhenHit.ts new file mode 100644 index 000000000..bc304c707 --- /dev/null +++ b/src/chrome/internal/breakpoints/bpActionWhenHit.ts @@ -0,0 +1,125 @@ +export interface IBPActionWhenHit { + isEquivalent(bpActionWhenHit: IBPActionWhenHit): boolean; + + basedOnTypeDo(actionBasedOnClass: { + alwaysBreak?: (alwaysBreak: AlwaysBreak) => R, + conditionalBreak?: (conditionalBreak: ConditionalBreak) => R, + logMessage?: (logMessage: LogMessage) => R, + breakOnSpecificHitCounts?: (breakOnSpecificHitCounts: BreakOnHitCount) => R + }): R; + + isBreakOnHitCount(): this is BreakOnHitCount; + isAlwaysBreak(): this is AlwaysBreak; + isConditionalBreak(): this is ConditionalBreak; + isLogMessage(): this is LogMessage; +} + +export abstract class BasedOnTypeDoCommonLogic implements IBPActionWhenHit { + public abstract isEquivalent(bpActionWhenHit: IBPActionWhenHit): boolean; + + basedOnTypeDo(actionBasedOnClass: { + alwaysBreak?: (alwaysBreak: AlwaysBreak) => R, + conditionalBreak?: (conditionalBreak: ConditionalBreak) => R, + logMessage?: (logMessage: LogMessage) => R, + breakOnSpecificHitCounts?: (breakOnSpecificHitCounts: BreakOnHitCount) => R; + }): R { + if (this.isAlwaysBreak() && actionBasedOnClass.alwaysBreak) { + return actionBasedOnClass.alwaysBreak(this); + } else if (this.isConditionalBreak() && actionBasedOnClass.conditionalBreak) { + return actionBasedOnClass.conditionalBreak(this); + } else if (this.isBreakOnHitCount() && actionBasedOnClass.breakOnSpecificHitCounts) { + return actionBasedOnClass.breakOnSpecificHitCounts(this); + } else if (this.isLogMessage() && actionBasedOnClass.logMessage) { + return actionBasedOnClass.logMessage(this); + } else { + throw new Error(`Unexpected case. The logic wasn't prepared to handle the specified breakpoint action when hit: ${this}`); + } + } + + public isAlwaysBreak(): this is AlwaysBreak { + return false; + } + + public isConditionalBreak(): this is ConditionalBreak { + return false; + } + + public isBreakOnHitCount(): this is BreakOnHitCount { + return false; + } + + public isLogMessage(): this is LogMessage { + return false; + } +} + +export class AlwaysBreak extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { + public isEquivalent(otherBPActionWhenHit: IBPActionWhenHit): boolean { + return otherBPActionWhenHit.isAlwaysBreak(); + } + + public isAlwaysBreak(): this is AlwaysBreak { + return true; + } + + public toString(): string { + return 'always break'; + } +} + +export class ConditionalBreak extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { + public isEquivalent(otherBPActionWhenHit: IBPActionWhenHit): boolean { + return otherBPActionWhenHit.isConditionalBreak() + && otherBPActionWhenHit.expressionOfWhenToBreak === this.expressionOfWhenToBreak; + } + + public isConditionalBreak(): this is ConditionalBreak { + return true; + } + + public toString(): string { + return `break if: ${this.expressionOfWhenToBreak}`; + } + + constructor(public readonly expressionOfWhenToBreak: string) { + super(); + } +} + +export class BreakOnHitCount extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { + public isEquivalent(otherBPActionWhenHit: IBPActionWhenHit): boolean { + return otherBPActionWhenHit.isBreakOnHitCount() + && otherBPActionWhenHit.pauseOnHitCondition === this.pauseOnHitCondition; + } + + public isBreakOnHitCount(): this is BreakOnHitCount { + return true; + } + + public toString(): string { + return `break when hits: ${this.pauseOnHitCondition}`; + } + + constructor(public readonly pauseOnHitCondition: string) { + super(); + } +} + +export class LogMessage extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { + public isEquivalent(otherBPActionWhenHit: IBPActionWhenHit): boolean { + return otherBPActionWhenHit.isLogMessage() + && otherBPActionWhenHit.expressionToLog === this.expressionToLog; + } + + public isLogMessage(): this is LogMessage { + return true; + } + + public toString(): string { + return `log: ${this.expressionToLog}`; + } + + constructor(public readonly expressionToLog: string) { + super(); + } +} diff --git a/src/chrome/internal/breakpoints/bpRecipie.ts b/src/chrome/internal/breakpoints/bpRecipie.ts new file mode 100644 index 000000000..a365d60f3 --- /dev/null +++ b/src/chrome/internal/breakpoints/bpRecipie.ts @@ -0,0 +1,125 @@ +import { ISource } from '../sources/source'; +import { Location, ScriptOrSourceOrURLOrURLRegexp, LocationInUrl, LocationInUrlRegexp, LocationInScript } from '../locations/location'; +import { ILoadedSource } from '../sources/loadedSource'; +import { IScript } from '../scripts/script'; +import { IBPActionWhenHit, AlwaysBreak } from './bpActionWhenHit'; +import { utils } from '../../..'; +import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; +import { IResourceIdentifier, URL } from '../sources/resourceIdentifier'; +import { URLRegexp, createURLRegexp } from '../locations/subtypes'; + +export interface IBPRecipie { + readonly location: Location; + readonly bpActionWhenHit: TBPActionWhenHit; + + readonly unmappedBpRecipie: IBPRecipie; // Original bpRecipie before any mapping was done +} + +abstract class BPRecipieCommonLogic { + public abstract get bpActionWhenHit(): TBPActionWhenHit; + + constructor( + public readonly location: Location) { } + + public toString(): string { + return `BP @ ${this.location} do: ${this.bpActionWhenHit}`; + } +} + +abstract class UnamppedBPRecipieCommonLogic + extends BPRecipieCommonLogic { + + public get unmappedBpRecipie(): IBPRecipie { + return this; + } + + constructor( + location: Location, + public readonly bpActionWhenHit: TBPActionWhenHit) { + super(location); + } +} + +abstract class MappedBPRecipieCommonLogic { + public get bpActionWhenHit(): TBPActionWhenHit { + return this.unmappedBpRecipie.bpActionWhenHit; + } + + constructor(public readonly unmappedBpRecipie: IBPRecipie, + public readonly location: Location) { } + + public toString(): string { + return `BP @ ${this.location} do: ${this.bpActionWhenHit}`; + } +} + +export class BPRecipieInLoadedSource + extends MappedBPRecipieCommonLogic implements IBPRecipie { + + public asBPInScriptRecipie(): BPRecipieInScript { + return new BPRecipieInScript(this.unmappedBpRecipie, this.location.mappedToScript()); + } +} + +export class BPRecipieInUnresolvedSource extends UnamppedBPRecipieCommonLogic implements IBPRecipie { + public withAlwaysBreakAction(): BPRecipieInUnresolvedSource { + return new BPRecipieInUnresolvedSource(this.location, new AlwaysBreak()); + } + + public tryGettingBreakpointInLoadedSource( + succesfulAction: (breakpointInLoadedSource: BPRecipieInLoadedSource) => R, + failedAction: (breakpointInUnbindedSource: BPRecipieInUnresolvedSource) => R): R { + return this.location.tryResolvingSource( + locationInLoadedSource => succesfulAction(new BPRecipieInLoadedSource(this, locationInLoadedSource)), + () => failedAction(this)); + } + + public asBreakpointInLoadedSource(): BPRecipieInLoadedSource { + return this.tryGettingBreakpointInLoadedSource( + breakpointInLoadedSource => breakpointInLoadedSource, + () => { throw new Error(`Failed to convert ${this} into a breakpoint in a loaded source`); }); + } + + public asBreakpointWithLoadedSource(source: ILoadedSource): BPRecipieInLoadedSource { + return new BPRecipieInLoadedSource(this, this.location.resolvedWith(source)); + } +} + +export type IBreakpointRecipieInLoadedSource = IBPRecipie; +export type IBreakpointRecipieInUnbindedSource = IBPRecipie; + +export type BPRecipie = + TResource extends ISource ? BPRecipieInUnresolvedSource : + TResource extends ILoadedSource ? BPRecipieInLoadedSource : + TResource extends IScript ? BPRecipieInScript : + TResource extends IResourceIdentifier ? BPRecipieInUrl : + TResource extends URLRegexp ? BPRecipieInUrlRegexp : + never; + +export class BPRecipieInScript + extends MappedBPRecipieCommonLogic implements IBPRecipie { + + public atLocation(newLocation: LocationInScript): BPRecipieInScript { + return new BPRecipieInScript(this.unmappedBpRecipie, newLocation); + } + + public asBPInUrlRegexpRecipie(): BPRecipieInUrlRegexp { + const urlRegexp = createURLRegexp(utils.pathToRegex(this.location.script.url)); + return new BPRecipieInUrlRegexp(this.unmappedBpRecipie, + new LocationInUrlRegexp(urlRegexp, this.location.coordinates)); + } + + public asBPInUrlRecipie(): BPRecipieInUrl { + const url = this.location.script.runtimeSource.identifier; + return new BPRecipieInUrl(this.unmappedBpRecipie, + new LocationInUrl(url, this.location.coordinates)); + } +} + +export class BPRecipieInUrl + extends MappedBPRecipieCommonLogic, TBPActionWhenHit> implements IBPRecipie, TBPActionWhenHit> { +} + +export class BPRecipieInUrlRegexp + extends MappedBPRecipieCommonLogic implements IBPRecipie { +} diff --git a/src/chrome/internal/breakpoints/bpRecipieInLoadedSourceLogic.ts b/src/chrome/internal/breakpoints/bpRecipieInLoadedSourceLogic.ts new file mode 100644 index 000000000..258aaf632 --- /dev/null +++ b/src/chrome/internal/breakpoints/bpRecipieInLoadedSourceLogic.ts @@ -0,0 +1,112 @@ +import { BPRecipieInLoadedSource, BPRecipie } from './bpRecipie'; +import { ConditionalBreak, AlwaysBreak } from './bpActionWhenHit'; +import { IBreakpoint } from './breakpoint'; +import { ScriptOrSourceOrURLOrURLRegexp, LocationInScript, Coordinates } from '../locations/location'; +import { ISource } from '../sources/source'; +import { chromeUtils, logger } from '../../..'; +import { createColumnNumber, createLineNumber } from '../locations/subtypes'; +import { RangeInScript } from '../locations/rangeInScript'; +import { BreakpointsRegistry } from './breakpointsRegistry'; +import { PausedEvent } from '../../target/events'; +import { VoteRelevance, Vote, Abstained } from '../../communication/collaborativeDecision'; +import { inject, injectable } from 'inversify'; +import { ITargetBreakpoints } from '../../target/cdtpTargetBreakpoints'; +import { IBreakpointFeaturesSupport } from '../../target/breakpointFeaturesSupport'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { InformationAboutPausedProvider, NotifyStoppedCommonLogic } from '../features/takeProperActionOnPausedEvent'; +import { IEventsToClientReporter } from '../../client/eventSender'; +import { ReasonType } from '../../stoppedEvent'; + +export type Dummy = VoteRelevance; // If we don't do this the .d.ts doesn't include VoteRelevance and the compilation fails. Remove this when the issue disappears... + +export class HitBreakpoint extends NotifyStoppedCommonLogic { + public readonly relevance = VoteRelevance.NormalVote; + protected reason: ReasonType = 'breakpoint'; + + constructor(protected readonly _eventsToClientReporter: IEventsToClientReporter, + protected readonly _publishGoingToPauseClient: () => void) { + super(); + } +} + +export interface IBreakpointsInLoadedSource { + addBreakpointForLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise[]>; +} + +export interface BPRecipieInLoadedSourceLogicDependencies { + subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; + publishGoingToPauseClient(): void; +} + +@injectable() +export class BPRecipieInLoadedSourceLogic implements IBreakpointsInLoadedSource { + private readonly doesTargetSupportColumnBreakpointsCached: Promise; + + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + if (paused.hitBreakpoints && paused.hitBreakpoints.length > 0) { + // TODO DIEGO: Improve this to consider breakpoints where we shouldn't pause + return new HitBreakpoint(this._eventsToClientReporter, + // () => this._dependencies.publishGoingToPauseClient() TODO Figure out if we need this for the Chrome Overlay + () => { }); + } else { + return new Abstained(this); + } + } + + public async addBreakpointForLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise[]> { + const bpInScriptRecipie = bpRecipie.asBPInScriptRecipie(); + const bestLocation = await this.considerColumnAndSelectBestBPLocation(bpInScriptRecipie.location); + const bpRecipieInBestLocation = bpInScriptRecipie.atLocation(bestLocation); + + const runtimeSource = bpInScriptRecipie.location.script.runtimeSource; + this._breakpointRegistry.registerBPRecipie(bpRecipie); + + let breakpoints: IBreakpoint[]; + if (!runtimeSource.doesScriptHasUrl()) { + breakpoints = [await this._targetBreakpoints.setBreakpoint(bpRecipieInBestLocation)]; + } else if (runtimeSource.identifier.isLocalFilePath()) { + breakpoints = await this._targetBreakpoints.setBreakpointByUrlRegexp(bpRecipieInBestLocation.asBPInUrlRegexpRecipie()); + } else { // The script has a URL and it's not a local file path, so we can leave it as-is + breakpoints = await this._targetBreakpoints.setBreakpointByUrl(bpRecipieInBestLocation.asBPInUrlRecipie()); + } + + breakpoints.forEach(breakpoint => this._breakpointRegistry.registerBreakpointAsBinded(breakpoint)); + return breakpoints; + } + + public removeBreakpoint(bpRecipie: BPRecipie): Promise { + return this._targetBreakpoints.removeBreakpoint(bpRecipie); + } + + private async considerColumnAndSelectBestBPLocation(location: LocationInScript): Promise { + if (await this.doesTargetSupportColumnBreakpointsCached) { + const thisLineStart = new Coordinates(location.coordinates.lineNumber, createColumnNumber(0)); + const nextLineStart = new Coordinates(createLineNumber(location.coordinates.lineNumber + 1), createColumnNumber(0)); + const thisLineRange = new RangeInScript(location.script, thisLineStart, nextLineStart); + + const possibleLocations = await this._targetBreakpoints.getPossibleBreakpoints(thisLineRange); + + if (possibleLocations.length > 0) { + const bestLocation = chromeUtils.selectBreakpointLocation(location.lineNumber, location.columnNumber, possibleLocations); + logger.verbose(`PossibleBreakpoints: Best location for ${location} is ${bestLocation}`); + return bestLocation; + } + } + + return location; + } + + public install(): this { + this._dependencies.subscriberForAskForInformationAboutPaused(params => this.askForInformationAboutPaused(params)); + return this; + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: BPRecipieInLoadedSourceLogicDependencies, + @inject(TYPES.IBreakpointFeaturesSupport) private readonly _breakpointFeaturesSupport: IBreakpointFeaturesSupport, + private readonly _breakpointRegistry: BreakpointsRegistry, + @inject(TYPES.ITargetBreakpoints) private readonly _targetBreakpoints: ITargetBreakpoints, + @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { + this.doesTargetSupportColumnBreakpointsCached = this._breakpointFeaturesSupport.supportsColumnBreakpoints; + } +} \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/bpRecipieStatus.ts b/src/chrome/internal/breakpoints/bpRecipieStatus.ts new file mode 100644 index 000000000..c453bc916 --- /dev/null +++ b/src/chrome/internal/breakpoints/bpRecipieStatus.ts @@ -0,0 +1,63 @@ +import { IBPRecipie } from './bpRecipie'; + +import { ILoadedSource } from '../sources/loadedSource'; + +import { ScriptOrSourceOrURLOrURLRegexp, LocationInLoadedSource } from '../locations/location'; + +import { IBreakpoint } from './breakpoint'; +import { printArray } from '../../collections/printting'; + +export interface IBPRecipieStatus { + readonly statusDescription: string; + readonly recipie: IBPRecipie; + + isVerified(): boolean; + isBinded(): this is BPRecipieIsBinded; +} + +export class BPRecipieIsUnbinded implements IBPRecipieStatus { + public isBinded(): this is BPRecipieIsBinded { + return false; + } + + public isVerified(): boolean { + return false; + } + + public toString(): string { + return `${this.recipie} is unbinded because ${this.statusDescription}`; + } + + constructor( + public readonly recipie: IBPRecipie, + public readonly statusDescription: string) { + } +} + +export class BPRecipieIsBinded implements IBPRecipieStatus { + public isBinded(): this is BPRecipieIsBinded { + return true; + } + + public get actualLocationInSource(): LocationInLoadedSource { + // TODO: Figure out what is the right way to decide the actual location when we have multiple breakpoints + return this.breakpoints[0].actualLocation.mappedToSource(); + } + + public isVerified(): boolean { + return true; + } + + public toString(): string { + return `${this.recipie} is binded with all ${printArray('', this.breakpoints)} because ${this.statusDescription}`; + } + + constructor( + public readonly recipie: IBPRecipie, + public readonly breakpoints: IBreakpoint[], + public readonly statusDescription: string) { + if (this.breakpoints.length === 0) { + throw new Error(`A breakpoint recipie that is binded needs to have at least one breakpoint that was binded for the recipie yet ${this} had none`); + } + } +} diff --git a/src/chrome/internal/breakpoints/bpRecipies.ts b/src/chrome/internal/breakpoints/bpRecipies.ts new file mode 100644 index 000000000..0c83b683d --- /dev/null +++ b/src/chrome/internal/breakpoints/bpRecipies.ts @@ -0,0 +1,41 @@ +import { ILoadedSource } from '../sources/loadedSource'; +import { ISource } from '../sources/source'; +import { BPRecipie } from './bpRecipie'; +import { printArray } from '../../collections/printting'; +import { IResourceIdentifier } from '../sources/resourceIdentifier'; + +export class BPRecipiesCommonLogic { + constructor(public readonly resource: TResource, public readonly breakpoints: BPRecipie[]) { + this.breakpoints.forEach(breakpoint => { + const bpResource = breakpoint.location.resource; + if (!(bpResource as any).isEquivalent(this.resource)) { + throw new Error(`Expected all the breakpoints to have source ${resource} yet the breakpoint ${breakpoint} had ${bpResource} as it's source`); + } + }); + } + + public toString(): string { + return printArray(`Bps @ ${this.resource}`, this.breakpoints); + } +} + +export class BPRecipiesInLoadedSource extends BPRecipiesCommonLogic { + public get source(): ILoadedSource { + return this.resource; + } +} + +export class BPRecipiesInUnresolvedSource extends BPRecipiesCommonLogic { + public tryGettingBPsInLoadedSource(ifSuccesfulDo: (desiredBPsInLoadedSource: BPRecipiesInLoadedSource) => R, ifFaileDo: () => R): R { + return this.resource.tryResolving( + loadedSource => { + const loadedSourceBPs = this.breakpoints.map(breakpoint => breakpoint.asBreakpointInLoadedSource()); + return ifSuccesfulDo(new BPRecipiesInLoadedSource(loadedSource, loadedSourceBPs)); + }, + ifFaileDo); + } + + public get requestedSourcePath(): IResourceIdentifier { + return this.resource.sourceIdentifier; + } +} diff --git a/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts b/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts new file mode 100644 index 000000000..e4c8539cb --- /dev/null +++ b/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts @@ -0,0 +1,125 @@ +import { BPRecipieInUnresolvedSource, BPRecipie } from './bpRecipie'; +import { BPRecipiesInUnresolvedSource } from './bpRecipies'; +import { ISource } from '../sources/source'; +import { ILoadedSource } from '../sources/loadedSource'; +import { IBPActionWhenHit } from './bpActionWhenHit'; +import { SetUsingProjection } from '../../collections/setUsingProjection'; + +export class ReplacementForExistingBPR { + constructor( + public readonly existingBP: BPRecipieInUnresolvedSource, + public readonly replacement: BPRecipieInUnresolvedSource) { } +} + +function canonicalizeBPLocation(breakpoint: BPRecipieInUnresolvedSource): string { + return JSON.stringify({ + lineNumber: breakpoint.location.lineNumber, + columnNumber: breakpoint.location.columnNumber + }); +} + +export class BPRsDeltaCalculator { + private readonly _currentBPRecipies: SetUsingProjection; + + constructor( + public readonly requestedSourceIdentifier: ISource, + private readonly _requestedBPRecipies: BPRecipiesInUnresolvedSource, + currentBPRecipies: BPRecipieInUnresolvedSource[]) { + this._currentBPRecipies = new SetUsingProjection(canonicalizeBPLocation, currentBPRecipies); + } + + public calculate(): BPRsDeltaInRequestedSource { + const match = { + replacementsForExistingOnes: [] as ReplacementForExistingBPR[], // TODO DIEGO + matchesForRequested: [] as BPRecipieInUnresolvedSource[], // Every iteration we'll add either the existing BP match, or the new BP as it's own match here + requestedToAdd: [] as BPRecipieInUnresolvedSource[], // Every time we don't find an existing match BP, we'll add the desired BP here + existingToLeaveAsIs: [] as BPRecipieInUnresolvedSource[], // Every time we do find an existing match BP, we'll add the existing BP here + existingToRemove: [] as BPRecipieInUnresolvedSource[] // Calculated at the end of the algorithm by doing (existingBreakpoints - existingToLeaveAsIs) + }; + + this._requestedBPRecipies.breakpoints.forEach(requestedBP => { + const existingMatch = this._currentBPRecipies.tryGetting(requestedBP); + + let matchingBreakpoint; + if (existingMatch !== undefined) { + if (requestedBP.bpActionWhenHit.isEquivalent(existingMatch.bpActionWhenHit)) { + match.existingToLeaveAsIs.push(existingMatch); + matchingBreakpoint = existingMatch; + } else { + match.replacementsForExistingOnes.push(new ReplacementForExistingBPR(existingMatch, requestedBP)); + matchingBreakpoint = requestedBP; + } + } else { + match.requestedToAdd.push(requestedBP); + matchingBreakpoint = requestedBP; + } + match.matchesForRequested.push(matchingBreakpoint); + }); + + const setOfExistingToLeaveAsIs = new Set(match.existingToLeaveAsIs.concat(match.replacementsForExistingOnes.map(b => b.existingBP))); + + match.existingToRemove = Array.from(this._currentBPRecipies).filter(bp => !setOfExistingToLeaveAsIs.has(bp)); + + // Do some minor validations of the result just in case + const delta = new BPRsDeltaInRequestedSource(this.requestedSourceIdentifier, match.replacementsForExistingOnes, match.matchesForRequested, + match.requestedToAdd, match.existingToRemove, match.existingToLeaveAsIs); + this.validateResult(delta); + return delta; + } + + private validateResult(match: BPRsDeltaInRequestedSource): void { + let errorMessage = ''; + if (match.matchesForRequested.length !== this._requestedBPRecipies.breakpoints.length) { + errorMessage += 'Expected the matches for desired breakpoints list to have the same length as the desired breakpoints list\n'; + } + + if (match.requestedToAdd.length + match.existingToLeaveAsIs.length + match.existingToBeReplaced.length !== this._requestedBPRecipies.breakpoints.length) { + errorMessage += 'Expected the desired breakpoints to add plus the existing breakpoints to leave as-is to have the same quantity as the total desired breakpoints\n'; + } + + if (match.existingToLeaveAsIs.length + match.existingToBeReplaced.length + match.existingToRemove.length !== this._currentBPRecipies.size) { + errorMessage += 'Expected the existing breakpoints to leave as-is plus the existing breakpoints to remove to have the same quantity as the total existing breakpoints\n'; + } + + if (errorMessage !== '') { + const matchJson = { + matchesForRequested: this.printLocations(match.matchesForRequested), + requestedToAdd: this.printLocations(match.requestedToAdd), + existingToRemove: this.printLocations(match.existingToRemove), + existingToLeaveAsIs: this.printLocations(match.existingToLeaveAsIs), + existingToBeReplaced: this.printLocationsOfReplacements(match.existingToBeReplaced), + }; + + const additionalDetails = `\nDesired breakpoints = ${JSON.stringify(this._requestedBPRecipies.breakpoints.map(canonicalizeBPLocation))}` + + `\Existing breakpoints = ${JSON.stringify(Array.from(this._currentBPRecipies).map(canonicalizeBPLocation))}` + + `\nMatch = ${JSON.stringify(matchJson)}`; + throw new Error(errorMessage + `\nmatch: ${additionalDetails}`); + } + } + + private printLocationsOfReplacements(existingToBeReplaced: ReplacementForExistingBPR[]): string[] { + return existingToBeReplaced.map(rp => + `At ${rp.existingBP.location.coordinates} change <${rp.existingBP.bpActionWhenHit}> to <${rp.replacement.bpActionWhenHit}>`); + } + + private printLocations(bpRecipies: BPRecipieInUnresolvedSource[]): string[] { + return bpRecipies.map(bpRecipie => `${bpRecipie.location.coordinates}`); + } + + public toString(): string { + return `BPs Delta Calculator {\n\tRequested BPs: ${this._requestedBPRecipies}\n\tExisting BPs: ${this._currentBPRecipies}\n}`; + } +} + +export abstract class BPRsDeltaCommonLogic { + constructor(public readonly resource: TResource, + public readonly existingToBeReplaced: ReplacementForExistingBPR[], + public readonly matchesForRequested: BPRecipie[], + public readonly requestedToAdd: BPRecipie[], + public readonly existingToRemove: BPRecipie[], + public readonly existingToLeaveAsIs: BPRecipie[]) { } +} + +export class BPRsDeltaInRequestedSource extends BPRsDeltaCommonLogic { } + +export class BPRsDeltaInLoadedSource extends BPRsDeltaCommonLogic { } diff --git a/src/chrome/internal/breakpoints/breakpoint.ts b/src/chrome/internal/breakpoints/breakpoint.ts new file mode 100644 index 000000000..b837d6924 --- /dev/null +++ b/src/chrome/internal/breakpoints/breakpoint.ts @@ -0,0 +1,36 @@ +import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; +import { IBPRecipie } from './bpRecipie'; +import { ILoadedSource } from '../sources/loadedSource'; +import { IScript } from '../scripts/script'; +import { URL } from '../sources/resourceIdentifier'; +import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; +import { URLRegexp } from '../locations/subtypes'; + +// Should we rename this to ActionPoint? Given that it can be a LogPoint too? +export interface IBreakpoint { + readonly recipie: IBPRecipie; + readonly actualLocation: LocationInScript; +} + +export class Breakpoint implements IBreakpoint{ + public toString(): string { + return `${this.recipie} actual location is ${this.actualLocation}`; + } + + constructor(public readonly recipie: IBPRecipie, public readonly actualLocation: LocationInScript) { } +} + +export class BreakpointInLoadedSource extends Breakpoint { } + +export class BreakpointInScript extends Breakpoint { } + +export class BreakpointInUrl extends Breakpoint> { } + +export class BreakpointInUrlRegexp extends Breakpoint { } + +// export type Breakpoint = +// TResource extends ILoadedSource ? BreakpointInLoadedSource : +// TResource extends IScript ? BreakpointInScript : +// TResource extends IResourceIdentifier ? BreakpointInUrl : +// TResource extends URLRegexp ? BreakpointInUrlRegexp : +// never; diff --git a/src/chrome/internal/breakpoints/breakpointsLogic.ts b/src/chrome/internal/breakpoints/breakpointsLogic.ts new file mode 100644 index 000000000..7461502c5 --- /dev/null +++ b/src/chrome/internal/breakpoints/breakpointsLogic.ts @@ -0,0 +1,112 @@ +import { IBPRecipie } from './bpRecipie'; +import { ITelemetryPropertyCollector, IComponent, ConnectedCDAConfiguration } from '../../..'; +import { ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; +import { BPRecipiesInUnresolvedSource } from './bpRecipies'; +import { Breakpoint } from './breakpoint'; +import { ReAddBPsWhenSourceIsLoaded, EventsConsumedByReAddBPsWhenSourceIsLoaded } from './features/reAddBPsWhenSourceIsLoaded'; +import { asyncMap } from '../../collections/async'; +import { IBPRecipieStatus } from './bpRecipieStatus'; +import { ClientCurrentBPRecipiesRegistry } from './clientCurrentBPRecipiesRegistry'; +import { BreakpointsRegistry } from './breakpointsRegistry'; +import { BPRecipieInLoadedSourceLogic } from './bpRecipieInLoadedSourceLogic'; +import { RemoveProperty } from '../../../typeUtils'; +import { IEventsToClientReporter } from '../../client/eventSender'; +import { PauseScriptLoadsToSetBPs, PauseScriptLoadsToSetBPsDependencies } from './features/pauseScriptLoadsToSetBPs'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; + +export interface IOnPausedResult { + didPause: boolean; +} + +export interface InternalDependencies extends + EventsConsumedByReAddBPsWhenSourceIsLoaded, + PauseScriptLoadsToSetBPsDependencies { + + onAsyncBreakpointResolved(listener: (params: Breakpoint) => void): void; +} + +export type EventsConsumedByBreakpointsLogic = RemoveProperty & { onNoPendingBreakpoints(listener: () => void): void }; + +@injectable() +export class BreakpointsLogic implements IComponent { + private _isBpsWhileLoadingEnable: boolean; + + private readonly _clientBreakpointsRegistry = new ClientCurrentBPRecipiesRegistry(); + + protected onAsyncBreakpointResolved(breakpoint: Breakpoint): void { + this._breakpointRegistry.registerBreakpointAsBinded(breakpoint); + this.onUnbounBPRecipieIsNowBound(breakpoint.recipie); + } + + private onUnbounBPRecipieIsNowBound(bpRecipie: IBPRecipie): void { + const bpRecipieStatus = this._breakpointRegistry.getStatusOfBPRecipie(bpRecipie); + this._eventsToClientReporter.sendBPStatusChanged({ reason: 'changed', bpRecipieStatus }); + } + + public async updateBreakpointsForFile(requestedBPs: BPRecipiesInUnresolvedSource, _?: ITelemetryPropertyCollector): Promise { + const bpsDelta = this._clientBreakpointsRegistry.updateBPRecipiesAndCalculateDelta(requestedBPs); + const requestedBPsToAdd = new BPRecipiesInUnresolvedSource(bpsDelta.resource, bpsDelta.requestedToAdd); + bpsDelta.requestedToAdd.forEach(requestedBP => this._breakpointRegistry.registerBPRecipie(requestedBP)); + bpsDelta.existingToBeReplaced.forEach(existingToBeReplaced => this._breakpointRegistry.registerBPRecipie(existingToBeReplaced.replacement)); + + await requestedBPsToAdd.tryGettingBPsInLoadedSource( + async requestedBPsToAddInLoadedSources => { + // Match desired breakpoints to existing breakpoints + + await asyncMap(requestedBPsToAddInLoadedSources.breakpoints, async requestedBP => { + // DIEGO TODO: Do we need to do one breakpoint at a time to avoid issues on Crdp, or can we do them in parallel now that we use a different algorithm? + await this._bprInLoadedSourceLogic.addBreakpointForLoadedSource(requestedBP); + }); + await Promise.all(bpsDelta.existingToRemove.map(async existingBPToRemove => { + await this._bprInLoadedSourceLogic.removeBreakpoint(existingBPToRemove); + })); + + await asyncMap(bpsDelta.existingToBeReplaced, async existingToBeReplaced => { + // TODO: There is a race condition between the remove and the add line. We cannot add first and remove second, because even though + // the breakpoints have a different condition, the target won't let you add two breakpoints to the same exact location. + // We need to investigate if we can make the new breakpoint using a pseudo-regexp to make the target think that they are on different locations + // and thus workaround this issue + await this._bprInLoadedSourceLogic.removeBreakpoint(existingToBeReplaced.existingBP); + await this._bprInLoadedSourceLogic.addBreakpointForLoadedSource(existingToBeReplaced.replacement.asBreakpointInLoadedSource()); + }); + }, + () => { + const existingUnbindedBPs = bpsDelta.existingToLeaveAsIs.filter(bp => !this._breakpointRegistry.getStatusOfBPRecipie(bp).isVerified()); + const requestedBPsPendingToAdd = new BPRecipiesInUnresolvedSource(bpsDelta.resource, bpsDelta.requestedToAdd.concat(existingUnbindedBPs)); + if (this._isBpsWhileLoadingEnable) { + this._bpsWhileLoadingLogic.enableIfNeccesary(); + } + this._unbindedBreakpointsLogic.replaceBPsForSourceWith(requestedBPsPendingToAdd); + }); + + return bpsDelta.matchesForRequested.map(bpRecipie => this._breakpointRegistry.getStatusOfBPRecipie(bpRecipie)); + } + + public install(): this { + this._unbindedBreakpointsLogic.install(); + this._bpsWhileLoadingLogic.install(); + this._dependencies.onNoPendingBreakpoints(() => this._bpsWhileLoadingLogic.disableIfNeccesary()); + this._bprInLoadedSourceLogic.install(); + return this.configure(); + } + + public configure(): this { + this._isBpsWhileLoadingEnable = this._configuration.args.breakOnLoadStrategy !== 'off'; + return this; + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByBreakpointsLogic, + @inject(TYPES.BreakpointsRegistry) private readonly _breakpointRegistry: BreakpointsRegistry, + @inject(TYPES.ReAddBPsWhenSourceIsLoaded) private readonly _unbindedBreakpointsLogic: ReAddBPsWhenSourceIsLoaded, + @inject(TYPES.PauseScriptLoadsToSetBPs) private readonly _bpsWhileLoadingLogic: PauseScriptLoadsToSetBPs, + @inject(TYPES.BPRecipieInLoadedSourceLogic) private readonly _bprInLoadedSourceLogic: BPRecipieInLoadedSourceLogic, + @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter, + @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration) { + this._dependencies.onAsyncBreakpointResolved(breakpoint => this.onAsyncBreakpointResolved(breakpoint)); + } +} \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/breakpointsRegistry.ts b/src/chrome/internal/breakpoints/breakpointsRegistry.ts new file mode 100644 index 000000000..fa9897e52 --- /dev/null +++ b/src/chrome/internal/breakpoints/breakpointsRegistry.ts @@ -0,0 +1,48 @@ +import { IBPRecipieStatus, BPRecipieIsBinded, BPRecipieIsUnbinded } from './bpRecipieStatus'; +import { IBreakpoint } from './breakpoint'; +import { ValidatedMultiMap } from '../../collections/validatedMultiMap'; +import { BPRecipie, IBPRecipie } from './bpRecipie'; +import { ScriptOrSourceOrURLOrURLRegexp, LocationInScript } from '../locations/location'; +import { injectable } from 'inversify'; + +@injectable() +export class BreakpointsRegistry { + // TODO DIEGO: Figure out how to handle if two breakpoint rules set a breakpoint in the same location so it ends up being the same breakpoint id + private readonly _unmappedRecipieToBreakpoints = new ValidatedMultiMap, + IBreakpoint>(); + + public registerBPRecipie(bpRecipie: BPRecipie): void { + this._unmappedRecipieToBreakpoints.addKeyIfNotExistant(bpRecipie); + } + + public registerBreakpointAsBinded(bp: IBreakpoint): void { + this._unmappedRecipieToBreakpoints.add(bp.recipie.unmappedBpRecipie, bp); + } + + public getStatusOfBPRecipie(bpRecipie: IBPRecipie): IBPRecipieStatus { + const breakpoints = this._unmappedRecipieToBreakpoints.get(bpRecipie); + if (breakpoints.size > 0) { + return new BPRecipieIsBinded(bpRecipie, Array.from(breakpoints), 'TODO DIEGO'); + } else { + return new BPRecipieIsUnbinded(bpRecipie, 'TODO DIEGO'); + } + } + + public tryGettingBreakpointAtLocation(locationInScript: LocationInScript): IBreakpoint[] { + // TODO DIEGO: Figure out if we need a faster algorithm for this + const matchinbBps = []; + for (const bps of this._unmappedRecipieToBreakpoints.values()) { + for (const bp of bps) { + if (bp.actualLocation.isSameAs(locationInScript)) { + matchinbBps.push(bp); + } + } + } + + return matchinbBps; + } + + public toString(): string { + return `Breakpoints recipie status Registry:\nRecipie to breakpoints: ${this._unmappedRecipieToBreakpoints}`; + } +} diff --git a/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts b/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts new file mode 100644 index 000000000..bbc78de88 --- /dev/null +++ b/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts @@ -0,0 +1,28 @@ +import { BPRecipiesInUnresolvedSource } from './bpRecipies'; + +import { BPRsDeltaCalculator, BPRsDeltaInRequestedSource } from './bpsDeltaCalculator'; +import { BPRecipieInUnresolvedSource } from './bpRecipie'; +import { newResourceIdentifierMap, IResourceIdentifier } from '../sources/resourceIdentifier'; + +export class ClientCurrentBPRecipiesRegistry { + private readonly _requestedSourcePathToCurrentBPRecipies = newResourceIdentifierMap(); + + public updateBPRecipiesAndCalculateDelta(requestedBPRecipies: BPRecipiesInUnresolvedSource): BPRsDeltaInRequestedSource { + const bpsDelta = this.calculateBPSDeltaFromExistingBPs(requestedBPRecipies); + this.registerCurrentBPRecipies(requestedBPRecipies.resource.sourceIdentifier, bpsDelta.matchesForRequested); + return bpsDelta; + } + + private registerCurrentBPRecipies(requestedSourceIdentifier: IResourceIdentifier, bpRecipies: BPRecipieInUnresolvedSource[]): void { + this._requestedSourcePathToCurrentBPRecipies.set(requestedSourceIdentifier, Array.from(bpRecipies)); + } + + private calculateBPSDeltaFromExistingBPs(requestedBPRecipies: BPRecipiesInUnresolvedSource): BPRsDeltaInRequestedSource { + const bpRecipiesInSource = this._requestedSourcePathToCurrentBPRecipies.getOrAdd(requestedBPRecipies.requestedSourcePath, () => []); + return new BPRsDeltaCalculator(requestedBPRecipies.resource, requestedBPRecipies, bpRecipiesInSource).calculate(); + } + + public toString(): string { + return `Client BP Recipies Registry {${this._requestedSourcePathToCurrentBPRecipies}}`; + } +} diff --git a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts new file mode 100644 index 000000000..df794b994 --- /dev/null +++ b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts @@ -0,0 +1,81 @@ +import { IComponent } from '../../features/feature'; +import { PausedEvent } from '../../../target/events'; +import { BPRecipieInUnresolvedSource, IBPRecipie } from '../bpRecipie'; +import { BreakOnHitCount } from '../bpActionWhenHit'; +import { ValidatedMap } from '../../../collections/validatedMap'; +import { HitCountConditionParser, HitCountConditionFunction } from '../hitCountConditionParser'; +import { ScriptOrSourceOrURLOrURLRegexp } from '../../locations/location'; +import { NotifyStoppedCommonLogic, InformationAboutPausedProvider } from '../../features/takeProperActionOnPausedEvent'; +import { ReasonType } from '../../../stoppedEvent'; +import { Vote, Abstained, VoteRelevance } from '../../../communication/collaborativeDecision'; +import { injectable, inject } from 'inversify'; +import { IEventsToClientReporter } from '../../../client/eventSender'; +import { TYPES } from '../../../dependencyInjection.ts/types'; + +export interface HitCountBreakpointsDependencies { + registerAddBPRecipieHandler(handlerRequirements: (bpRecipie: BPRecipieInUnresolvedSource) => boolean, + handler: (bpRecipie: BPRecipieInUnresolvedSource) => Promise): void; + + addBPRecipie(bpRecipie: BPRecipieInUnresolvedSource): Promise; + notifyBPWasHit(bpRecipie: BPRecipieInUnresolvedSource): Promise; + + subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; + publishGoingToPauseClient(): void; +} + +class HitCountBPData { + private _hitCount = 0; + + public notifyBPHit(): VoteRelevance { + return this._shouldPauseCondition(this._hitCount++) + ? VoteRelevance.NormalVote + : VoteRelevance.Abstained; + } + + constructor( + public readonly hitBPRecipie: BPRecipieInUnresolvedSource, + private readonly _shouldPauseCondition: HitCountConditionFunction) { } +} + +export class HitAndSatisfiedCountBPCondition extends NotifyStoppedCommonLogic { + public readonly relevance = VoteRelevance.NormalVote; + protected reason: ReasonType = 'breakpoint'; + + constructor(protected readonly _eventsToClientReporter: IEventsToClientReporter, + protected readonly _publishGoingToPauseClient: () => void) { + super(); + } +} + +// TODO DIEGO: Install and use this feature +@injectable() +export class HitCountBreakpoints implements IComponent { + private readonly underlyingToBPRecipie = new ValidatedMap, HitCountBPData>(); + + public install(): void { + this._dependencies.registerAddBPRecipieHandler( + bpRecipie => bpRecipie.bpActionWhenHit.isBreakOnHitCount(), + bpRecipie => this.addBPRecipie(bpRecipie as BPRecipieInUnresolvedSource)); + this._dependencies.subscriberForAskForInformationAboutPaused(paused => this.askForInformationAboutPaused(paused)); + } + + private async addBPRecipie(bpRecipie: BPRecipieInUnresolvedSource): Promise { + const underlyingBPRecipie = bpRecipie.withAlwaysBreakAction(); + const shouldPauseCondition = new HitCountConditionParser(bpRecipie.bpActionWhenHit.pauseOnHitCondition).parse(); + this._dependencies.addBPRecipie(underlyingBPRecipie); + this.underlyingToBPRecipie.set(underlyingBPRecipie, new HitCountBPData(bpRecipie, shouldPauseCondition)); + } + + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + const hitCountBPData = paused.hitBreakpoints.map(hitBPRecipie => + this.underlyingToBPRecipie.tryGetting(hitBPRecipie.unmappedBpRecipie)).filter(bpRecipie => bpRecipie !== undefined); + + const individualDecisions = hitCountBPData.map(data => data.notifyBPHit()); + return individualDecisions.indexOf(VoteRelevance.NormalVote) >= 0 + ? new HitAndSatisfiedCountBPCondition(this._eventsToClientReporter, this._dependencies.publishGoingToPauseClient) + : new Abstained(this); + } + + constructor(private readonly _dependencies: HitCountBreakpointsDependencies, + @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { } +} \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts new file mode 100644 index 000000000..e7580d7b7 --- /dev/null +++ b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts @@ -0,0 +1,129 @@ +import { asyncMap } from '../../../collections/async'; +import { PausedEvent } from '../../../target/events'; +import { ILoadedSource } from '../../sources/loadedSource'; +import { IComponent } from '../../features/feature'; +import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../../locations/location'; +import { IBreakpoint } from '../breakpoint'; +import { NotifyStoppedCommonLogic, ResumeCommonLogic, InformationAboutPausedProvider } from '../../features/takeProperActionOnPausedEvent'; +import { ReasonType } from '../../../stoppedEvent'; +import { VoteRelevance, Vote, Abstained } from '../../../communication/collaborativeDecision'; +import { injectable, inject } from 'inversify'; +import { IDOMInstrumentationBreakpoints, IDebugeeVersionProvider } from '../../../target/cdtpSmallerModules'; +import { TYPES } from '../../../dependencyInjection.ts/types'; +import { IEventsToClientReporter } from '../../../client/eventSender'; +import { IDebugeeExecutionControl } from '../../../target/controlDebugeeExecution'; +import { ReAddBPsWhenSourceIsLoaded } from './reAddBPsWhenSourceIsLoaded'; +import { BreakpointsRegistry } from '../breakpointsRegistry'; +export type Dummy = VoteRelevance; // If we don't do this the .d.ts doesn't include VoteRelevance and the compilation fails. Remove this when the issue disappears... + +export interface PauseScriptLoadsToSetBPsDependencies { + subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; + waitUntilUnbindedBPsAreSet(loadedSource: ILoadedSource): Promise; + + tryGettingBreakpointAtLocation(locationInScript: LocationInScript): IBreakpoint[]; + publishGoingToPauseClient(): void; +} + +export class HitStillPendingBreakpoint extends NotifyStoppedCommonLogic { + public readonly relevance = VoteRelevance.NormalVote; + protected reason: ReasonType = 'breakpoint'; + + constructor(protected readonly _eventsToClientReporter: IEventsToClientReporter, + protected readonly _publishGoingToPauseClient: () => void) { + super(); + } +} + +export class PausedWhileLoadingScriptToResolveBreakpoints extends ResumeCommonLogic { + public readonly relevance = VoteRelevance.FallbackVote; + + constructor(protected readonly _debugeeExecutionControl: IDebugeeExecutionControl) { + super(); + } +} + +@injectable() +export class PauseScriptLoadsToSetBPs implements IComponent { + private readonly stopsWhileScriptsLoadInstrumentationName = 'scriptFirstStatement'; + private _isInstrumentationEnabled = false; + private _scriptFirstStatementStopsBeforeFile: boolean; + + public async enableIfNeccesary(): Promise { + if (this._isInstrumentationEnabled === false) { + await this.startPausingOnScriptFirstStatement(); + } + } + + public async disableIfNeccesary(): Promise { + if (this._isInstrumentationEnabled === true) { + await this.stopPausingOnScriptFirstStatement(); + } + } + + private async askForInformationAboutPaused(paused: PausedEvent): Promise> { + if (this.isInstrumentationPause(paused)) { + await asyncMap(paused.callFrames[0].location.script.allSources, async source => { + await this._reAddBPsWhenSourceIsLoaded.waitUntilBPsAreSet(source); + }); + + // If we pause before starting the script, we can just resume, and we'll a breakpoint if it's on 0,0 + if (!this._scriptFirstStatementStopsBeforeFile) { + // On Chrome 69 we pause inside the script, so we need to check if there is a breakpoint at 0,0 that we need to use + const breakpoints = this._breakpointsRegistry.tryGettingBreakpointAtLocation(paused.callFrames[0].location); + if (breakpoints.length > 0) { + return new HitStillPendingBreakpoint(this._eventsToClientReporter, this._dependencies.publishGoingToPauseClient); + } + } + + return new PausedWhileLoadingScriptToResolveBreakpoints(this._debugeeExecutionControl); + } else { + return new Abstained(this); + } + } + + private async startPausingOnScriptFirstStatement(): Promise { + try { + this._isInstrumentationEnabled = true; + await this._domInstrumentationBreakpoints.setInstrumentationBreakpoint({ eventName: this.stopsWhileScriptsLoadInstrumentationName }); + } catch (exception) { + this._isInstrumentationEnabled = false; + throw exception; + } + } + + private async stopPausingOnScriptFirstStatement(): Promise { + await this._domInstrumentationBreakpoints.removeInstrumentationBreakpoint({ eventName: this.stopsWhileScriptsLoadInstrumentationName }); + this._isInstrumentationEnabled = false; + } + + private isInstrumentationPause(notification: PausedEvent): boolean { + return (notification.reason === 'EventListener' && notification.data.eventName.startsWith('instrumentation:')) || + (notification.reason === 'ambiguous' && Array.isArray(notification.data.reasons) && + notification.data.reasons.every((r: any) => r.reason === 'EventListener' && r.auxData.eventName.startsWith('instrumentation:'))); + } + + public async install(): Promise { + this._dependencies.subscriberForAskForInformationAboutPaused(params => this.askForInformationAboutPaused(params)); + // TODO DIEGO: Figure out exactly when we want to block on the browser version + // On version 69 Chrome stopped sending an extra event for DOM Instrumentation: See https://bugs.chromium.org/p/chromium/issues/detail?id=882909 + // On Chrome 68 we were relying on that event to make Break on load work on breakpoints on the first line of a file. On Chrome 69 we need an alternative way to make it work. + // TODO: Reenable the code that uses Versions.Target.Version when this fails + const versions = await this._debugeeVersionProvider.getVersion(); + + const version = versions.product.replace(/Chrome\/([0-9]{2})\..*/, '$1'); + const majorVersionNumber = parseInt(version, 10); + this._scriptFirstStatementStopsBeforeFile = majorVersionNumber < 69; + return this; + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: PauseScriptLoadsToSetBPsDependencies, + @inject(TYPES.IDOMInstrumentationBreakpoints) private readonly _domInstrumentationBreakpoints: IDOMInstrumentationBreakpoints, + @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionControl, + @inject(TYPES.IEventsToClientReporter) protected readonly _eventsToClientReporter: IEventsToClientReporter, + @inject(TYPES.IDebugeeVersionProvider) protected readonly _debugeeVersionProvider: IDebugeeVersionProvider, + @inject(TYPES.ReAddBPsWhenSourceIsLoaded) protected readonly _reAddBPsWhenSourceIsLoaded: ReAddBPsWhenSourceIsLoaded, + @inject(TYPES.BreakpointsRegistry) protected readonly _breakpointsRegistry: BreakpointsRegistry, + ) { + } +} \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts new file mode 100644 index 000000000..9276f92af --- /dev/null +++ b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts @@ -0,0 +1,93 @@ +import { BPRecipiesInUnresolvedSource } from '../bpRecipies'; +import { ILoadedSource } from '../../sources/loadedSource'; +import { asyncMap } from '../../../collections/async'; +import { BPRecipieIsUnbinded, BPRecipieIsBinded } from '../bpRecipieStatus'; +import { newResourceIdentifierMap, IResourceIdentifier } from '../../sources/resourceIdentifier'; +import { IEventsToClientReporter } from '../../../client/eventSender'; +import { PromiseDefer, promiseDefer } from '../../../../utils'; +import { IComponent } from '../../features/feature'; +import { injectable, inject } from 'inversify'; +import { IBreakpointsInLoadedSource } from '../bpRecipieInLoadedSourceLogic'; +import { TYPES } from '../../../dependencyInjection.ts/types'; + +export interface EventsConsumedByReAddBPsWhenSourceIsLoaded { + onLoadedSourceIsAvailable(listener: (source: ILoadedSource) => Promise): void; + notifyNoPendingBPs(): void; +} + +@injectable() +export class ReAddBPsWhenSourceIsLoaded implements IComponent { + private readonly _sourcePathToBPRecipies = newResourceIdentifierMap(); + private readonly _sourcePathToBPsAreSetDefer = newResourceIdentifierMap>(); + + public install(): void { + this._dependencies.onLoadedSourceIsAvailable(source => this.onLoadedSourceIsAvailable(source)); + } + + public replaceBPsForSourceWith(requestedBPs: BPRecipiesInUnresolvedSource): void { + this._sourcePathToBPRecipies.set(requestedBPs.requestedSourcePath, requestedBPs); + } + + public waitUntilBPsAreSet(loadedSource: ILoadedSource): Promise { + const bpRecipies = this._sourcePathToBPRecipies.tryGetting(loadedSource.identifier); + if (bpRecipies !== undefined) { + return this.getBPsAreSetDefer(loadedSource.identifier).promise; + } else { + const defer = this._sourcePathToBPsAreSetDefer.tryGetting(loadedSource.identifier); + return Promise.resolve(defer && defer.promise); + } + } + + private getBPsAreSetDefer(identifier: IResourceIdentifier): PromiseDefer { + return this._sourcePathToBPsAreSetDefer.getOrAdd(identifier, () => promiseDefer()); + } + + private async onLoadedSourceIsAvailable(source: ILoadedSource): Promise { + const unbindBPRecipies = this._sourcePathToBPRecipies.tryGetting(source.identifier); + + if (unbindBPRecipies !== undefined) { + // We remove it first in sync just to avoid race conditions (If we get multiple refreshes fast, we could get events for the same source path severla times) + const defer = this.getBPsAreSetDefer(source.identifier); + this._sourcePathToBPRecipies.delete(source.identifier); + const remainingBPRecipies = new Set(unbindBPRecipies.breakpoints); + await asyncMap(unbindBPRecipies.breakpoints, async bpRecipie => { + try { + const bpStatus = await this._breakpointsInLoadedSource.addBreakpointForLoadedSource(bpRecipie.asBreakpointWithLoadedSource(source)); + this._eventsToClientReporter.sendBPStatusChanged({ + bpRecipieStatus: new BPRecipieIsBinded(bpRecipie, bpStatus, 'TODO DIEGO'), + reason: 'changed' + }); + remainingBPRecipies.delete(bpRecipie); + } catch (exception) { + this._eventsToClientReporter.sendBPStatusChanged({ + bpRecipieStatus: new BPRecipieIsUnbinded(bpRecipie, `An unexpected error happen while trying to set the breakpoint: ${exception})`), + reason: 'changed' + }); + } + }); + + // Notify others that we are finished setting the BPs + defer.resolve(); + this._sourcePathToBPsAreSetDefer.delete(source.identifier); + + if (remainingBPRecipies.size > 0) { + // TODO DIEGO: Add telemetry given that we don't expect this to happen + // If we still have BPs recipies that we couldn't add, we put them back in + this._sourcePathToBPRecipies.set(source.identifier, new BPRecipiesInUnresolvedSource(unbindBPRecipies.resource, Array.from(remainingBPRecipies))); + } + + if (this._sourcePathToBPRecipies.size === 0) { + this._dependencies.notifyNoPendingBPs(); + } + } + } + + public toString(): string { + return `{ BPs to re-add when source is laoded: ${this._sourcePathToBPRecipies}}`; + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByReAddBPsWhenSourceIsLoaded, + @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter, + @inject(TYPES.BPRecipieInLoadedSourceLogic) private readonly _breakpointsInLoadedSource: IBreakpointsInLoadedSource) { } +} \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/hitCountConditionParser.ts b/src/chrome/internal/breakpoints/hitCountConditionParser.ts new file mode 100644 index 000000000..e33488581 --- /dev/null +++ b/src/chrome/internal/breakpoints/hitCountConditionParser.ts @@ -0,0 +1,41 @@ +export type HitCountConditionFunction = (numHits: number) => boolean; + +export class HitCountConditionParser { + private readonly HIT_COUNT_CONDITION_PATTERN = /^(>|>=|=|<|<=|%)?\s*([0-9]+)$/; + private patternMatches: RegExpExecArray | undefined; + + public parse(): HitCountConditionFunction { + this.patternMatches = this.HIT_COUNT_CONDITION_PATTERN.exec(this._hitCountCondition.trim()); + if (this.patternMatches && this.patternMatches.length >= 3) { + // eval safe because of the regex, and this is only a string that the current user will type in + /* tslint:disable:no-function-constructor-with-string-args */ + const shouldPause: HitCountConditionFunction = new Function('numHits', this.javaScriptCodeToEvaluateCondition()); + /* tslint:enable:no-function-constructor-with-string-args */ + return shouldPause; + } else { + throw new Error(`Didn't recognize <${this._hitCountCondition}> as a valid hit count condition`); + } + } + + constructor(private readonly _hitCountCondition: string) { } + + private javaScriptCodeToEvaluateCondition() { + const operator = this.parseOperator(); + const value = this.parseValue(); + const javaScriptCode = operator === '%' + ? `return (numHits % ${value}) === 0;` + : `return numHits ${operator} ${value};`; + return javaScriptCode; + } + + private parseValue(): string { + return this.patternMatches[2]; + } + + private parseOperator(): string { + let op = this.patternMatches[1] || '>='; + if (op === '=') + op = '=='; + return op; + } +} \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts b/src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts new file mode 100644 index 000000000..8aabf31d6 --- /dev/null +++ b/src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts @@ -0,0 +1,37 @@ +// import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp, IBPRecipie, BPRecipie } from './bpRecipie'; +// import { AlwaysBreak, ConditionalBreak } from './bpBehavior'; +// import { BreakpointInScript, BreakpointInUrl, BreakpointInUrlRegexp, IBreakpoint } from './breakpoint'; +// import { SetUsingProjection } from '../../collections/setUsingProjection'; +// import { Script } from '../scripts/script'; +// import { ScriptOrSourceOrIdentifierOrUrlRegexp } from '../locations/locationInResource'; + +// export interface ITargetDuplicatedBPsLogicDependencies { +// setBreakpoint(bpRecipie: BPRecipieInScript): Promise; +// setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise; +// setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise; +// } + +// class DuplicatedBPsLogic> { +// private readonly _canonicalizedBPRecipies = new SetUsingProjection>(); + +// public setBreakpoint(bpRecipie: TBreakpoint): Promise> { +// const existingRecipie = this._canonicalizedBPRecipies.tryGetting(bpRecipie); +// return new BreakpointInScript(); +// } +// } + +// export class TargetDuplicatedBPsLogic { +// public async setBreakpoint(bpRecipie: BPRecipieInScript): Promise { +// return this._dependencies.setBreakpoint(bpRecipie); +// } + +// public async setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise { +// return this._dependencies.setBreakpointByUrl(bpRecipie); +// } + +// public async setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise { +// return this._dependencies.setBreakpointByUrlRegexp(bpRecipie); +// } + +// constructor(private readonly _dependencies: ITargetDuplicatedBPsLogicDependencies) { } +// } \ No newline at end of file diff --git a/src/chrome/internal/domains/supportedDomains.ts b/src/chrome/internal/domains/supportedDomains.ts new file mode 100644 index 000000000..f219c7e9a --- /dev/null +++ b/src/chrome/internal/domains/supportedDomains.ts @@ -0,0 +1,36 @@ +import { IComponent } from '../features/feature'; +import { Crdp } from '../../..'; +import { injectable } from 'inversify'; + +export interface SupportedDomainsDependencies { + getTargetDebuggerDomainsSchemas(): Promise; +} + +export interface ISupportedDomains { + isSupported(domainName: string): boolean; +} + +@injectable() +export class SupportedDomains implements IComponent, ISupportedDomains { + private readonly _domains = new Map(); + + public isSupported(domainName: string): boolean { + return this._domains.has(domainName); + } + + public async install(): Promise { + await this.initSupportedDomains(); + return this; + } + + private async initSupportedDomains(): Promise { + try { + const domains = await this._dependencies.getTargetDebuggerDomainsSchemas(); + domains.forEach(domain => this._domains.set(domain.name, domain)); + } catch (e) { + // If getDomains isn't supported for some reason, skip this + } + } + + constructor(private readonly _dependencies: SupportedDomainsDependencies) { } +} \ No newline at end of file diff --git a/src/chrome/internal/exceptions/pauseOnException.ts b/src/chrome/internal/exceptions/pauseOnException.ts new file mode 100644 index 000000000..b88b26af3 --- /dev/null +++ b/src/chrome/internal/exceptions/pauseOnException.ts @@ -0,0 +1,118 @@ +import { InformationAboutPausedProvider, NotifyStoppedCommonLogic } from '../features/takeProperActionOnPausedEvent'; +import { IComponent } from '../features/feature'; +import { PausedEvent } from '../../target/events'; +import * as errors from '../../../errors'; +import { utils } from '../../..'; +import { FormattedExceptionParser, IFormattedExceptionLineDescription } from '../formattedExceptionParser'; +import { PauseOnPromiseRejectionsStrategy, PauseOnExceptionsStrategy } from './strategies'; +import { VoteRelevance, Vote, Abstained } from '../../communication/collaborativeDecision'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { IPauseOnExceptions } from '../../target/cdtpDebugger'; +import { IEventsToClientReporter } from '../../client/eventSender'; +import { DeleteMeScriptsRegistry } from '../scripts/scriptsRegistry'; + +type ExceptionBreakMode = 'never' | 'always' | 'unhandled' | 'userUnhandled'; + +export type Dummy = VoteRelevance; // If we don't do this the .d.ts doesn't include VoteRelevance and the compilation fails. Remove this when the issue disappears... + +export interface IExceptionInformationDetails { + readonly stackTrace: IFormattedExceptionLineDescription[]; + readonly message: string; + readonly formattedDescription: string; + readonly typeName: string; +} + +export interface IExceptionInformation { + readonly exceptionId: string; + readonly description?: string; + readonly breakMode: ExceptionBreakMode; + readonly details?: IExceptionInformationDetails; +} + +export interface EventsConsumedByPauseOnException { + subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; + publishGoingToPauseClient(): void; +} + +export class ExceptionWasThrown extends NotifyStoppedCommonLogic { + public readonly relevance = VoteRelevance.NormalVote; + public readonly reason = 'exception'; // There is an issue of how the .d.ts is generated for this file, so we need to type that explicitly + + constructor(protected readonly _eventsToClientReporter: IEventsToClientReporter, + protected readonly _publishGoingToPauseClient: () => void) { + super(); + } +} + +export class PromiseWasRejected extends NotifyStoppedCommonLogic { + public readonly relevance = VoteRelevance.NormalVote; + public readonly reason: 'promise_rejection' = 'promise_rejection'; // There is an issue of how the .d.ts is generated for this file, so we need to type that explicitly + + constructor(protected readonly _eventsToClientReporter: IEventsToClientReporter, + protected readonly _publishGoingToPauseClient: () => void) { + super(); + } +} + +@injectable() +export class PauseOnExceptionOrRejection implements IComponent { + private _promiseRejectionsStrategy: PauseOnPromiseRejectionsStrategy; + + private _lastException: any; + + public setExceptionsStrategy(strategy: PauseOnExceptionsStrategy): Promise { + return this._pauseOnExceptions.setPauseOnExceptions(strategy); + } + + public setPromiseRejectionStrategy(promiseRejectionsStrategy: PauseOnPromiseRejectionsStrategy): void { + this._promiseRejectionsStrategy = promiseRejectionsStrategy; + } + + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + if (paused.reason === 'exception') { + // If we are here is because we either configured the debugee to pauser on unhandled or handled exceptions + this._lastException = paused.data; + return new ExceptionWasThrown(this._eventsToClientReporter, this._dependencies.publishGoingToPauseClient); + } else if (paused.reason === 'promiseRejection' && this._promiseRejectionsStrategy.shouldPauseOnRejections()) { + // TODO: Figure out if it makes sense to move this into it's own class + this._lastException = paused.data; + return new PromiseWasRejected(this._eventsToClientReporter, this._dependencies.publishGoingToPauseClient); + } else { + this._lastException = null; + return new Abstained(this); + } + } + + public async latestExceptionInfo(): Promise { + if (this._lastException) { + const isError = this._lastException.subtype === 'error'; + const message = isError ? utils.firstLine(this._lastException.description) : (this._lastException.description || this._lastException.value); + const formattedMessage = message && message.replace(/\*/g, '\\*'); + const response: IExceptionInformation = { + exceptionId: this._lastException.className || this._lastException.type || 'Error', + breakMode: 'unhandled', + details: { + stackTrace: this._lastException.description && await new FormattedExceptionParser(this._scriptsLogic, this._lastException.description).parse(), + message, + formattedDescription: formattedMessage, // VS workaround - see https://github.com/Microsoft/client/issues/34259 + typeName: this._lastException.subtype || this._lastException.type + } + }; + + return response; + } else { + throw errors.noStoredException(); + } + } + + public install(): this { + this._dependencies.subscriberForAskForInformationAboutPaused(paused => this.askForInformationAboutPaused(paused)); + return this; + } + + constructor(@inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByPauseOnException, + @inject(TYPES.DeleteMeScriptsRegistry) private readonly _scriptsLogic: DeleteMeScriptsRegistry, + @inject(TYPES.IPauseOnExceptions) private readonly _pauseOnExceptions: IPauseOnExceptions, + @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { } +} \ No newline at end of file diff --git a/src/chrome/internal/exceptions/strategies.ts b/src/chrome/internal/exceptions/strategies.ts new file mode 100644 index 000000000..6e9630b9c --- /dev/null +++ b/src/chrome/internal/exceptions/strategies.ts @@ -0,0 +1,23 @@ +export interface PauseOnExceptionsStrategy { + +} + +export class PauseOnUnhandledExceptions implements PauseOnExceptionsStrategy { } +export class PauseOnAllExceptions implements PauseOnExceptionsStrategy { } +export class DoNotPauseOnAnyExceptions implements PauseOnExceptionsStrategy { } + +export interface PauseOnPromiseRejectionsStrategy { + shouldPauseOnRejections(): boolean; +} + +export class PauseOnAllRejections implements PauseOnPromiseRejectionsStrategy { + public shouldPauseOnRejections(): boolean { + return true; + } +} + +export class DoNotPauseOnAnyRejections implements PauseOnPromiseRejectionsStrategy { + public shouldPauseOnRejections(): boolean { + return false; + } +} diff --git a/src/chrome/internal/features/feature.ts b/src/chrome/internal/features/feature.ts index 3be839558..d4b991d40 100644 --- a/src/chrome/internal/features/feature.ts +++ b/src/chrome/internal/features/feature.ts @@ -1,3 +1,26 @@ -export interface IComponent { - // TODO: Implement this +import { ConnectedCDAConfiguration } from '../../client/chromeDebugAdapter/cdaConfiguration'; +import { PromiseOrNot } from '../../utils/promises'; + +export interface IConfigurableFeature { + install(configuration: Configuration): PromiseOrNot; +} + +export interface IConfigurationlessFeature { + install(): PromiseOrNot; +} + +export type ComponentConfiguration = ConnectedCDAConfiguration; + +export type IComponent = + Configuration extends void + ? IConfigurationlessFeature + : IConfigurableFeature; + +export interface ICommandHandlerDeclaration { + readonly commandName: string; + readonly commandHandler: (args: any) => PromiseOrNot; +} + +export interface ICommandHandlerDeclarer { + getCommandHandlerDeclarations(): PromiseOrNot; } diff --git a/src/chrome/internal/features/skipFiles.ts b/src/chrome/internal/features/skipFiles.ts new file mode 100644 index 000000000..8d7303a9e --- /dev/null +++ b/src/chrome/internal/features/skipFiles.ts @@ -0,0 +1,285 @@ +import { IToggleSkipFileStatusArgs, utils, Crdp, BaseSourceMapTransformer, parseResourceIdentifier, ConnectedCDAConfiguration } from '../../..'; +import { logger } from 'vscode-debugadapter/lib/logger'; +import { IScript } from '../scripts/script'; +import { CDTPDiagnostics } from '../../target/cdtpDiagnostics'; +import { StackTracesLogic, IStackTracePresentationLogicProvider } from '../stackTraces/stackTracesLogic'; +import { newResourceIdentifierMap, IResourceIdentifier } from '../sources/resourceIdentifier'; +import { IComponent } from './feature'; +import { ScriptParsedEvent } from '../../target/events'; +import { LocationInLoadedSource } from '../locations/location'; +import { ICallFramePresentationDetails } from '../stackTraces/callFramePresentation'; +import * as nls from 'vscode-nls'; +import { injectable, inject, LazyServiceIdentifer } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { ClientToInternal } from '../../client/clientToInternal'; +const localize = nls.loadMessageBundle(); + +export interface EventsConsumedBySkipFilesLogic { + onScriptParsed(listener: (scriptEvent: ScriptParsedEvent) => Promise): void; +} + +export interface ISkipFilesConfiguration { + skipFiles?: string[]; // an array of file names or glob patterns + skipFileRegExps?: string[]; // a supplemental array of library code regex patterns +} + +@injectable() +export class SkipFilesLogic implements IComponent, IStackTracePresentationLogicProvider { + private _blackboxedRegexes: RegExp[] = []; + private _skipFileStatuses = newResourceIdentifierMap(); + public reprocessPausedEvent: () => void; // TODO DIEGO: Do this in a better way + + /** + * If the source has a saved skip status, return that, whether true or false. + * If not, check it against the patterns list. + */ + public shouldSkipSource(sourcePath: IResourceIdentifier): boolean | undefined { + const status = this.getSkipStatus(sourcePath); + if (typeof status === 'boolean') { + return status; + } + + if (this.matchesSkipFilesPatterns(sourcePath)) { + return true; + } + + return undefined; + } + + public getCallFrameAdditionalDetails(locationInLoadedSource: LocationInLoadedSource): ICallFramePresentationDetails[] { + return this.shouldSkipSource(locationInLoadedSource.source.identifier) + ? [{ + additionalSourceOrigins: [localize('skipFilesFeatureName', 'skipFiles')], + sourcePresentationHint: 'deemphasize' + }] + : []; + } + + /** + * Returns true if this path matches one of the static skip patterns + */ + private matchesSkipFilesPatterns(sourcePath: IResourceIdentifier): boolean { + return this._blackboxedRegexes.some(regex => { + return regex.test(sourcePath.canonicalized); + }); + } + + /** + * Returns the current skip status for this path, which is either an authored or generated script. + */ + private getSkipStatus(sourcePath: IResourceIdentifier): boolean | undefined { + if (this._skipFileStatuses.has(sourcePath)) { + return this._skipFileStatuses.get(sourcePath); + } + + return undefined; + } + + /* __GDPR__ + 'ClientRequest/toggleSkipFileStatus' : { + '${include}': [ + '${IExecutionResultTelemetryProperties}', + '${DebugCommonProperties}' + ] + } + */ + public async toggleSkipFileStatus(clientArgs: IToggleSkipFileStatusArgs): Promise { + const args = this._clientToInternal.toSource(clientArgs); + await args.tryResolving(async resolvedSource => { + if (!await this.isInCurrentStack(clientArgs)) { + // Only valid for files that are in the current stack + const logName = resolvedSource; + logger.log(`Can't toggle the skipFile status for ${logName} - it's not in the current stack.`); + return; + } + + if (resolvedSource === resolvedSource.script.developmentSource && resolvedSource.script.mappedSources.length < 0) { + // Ignore toggling skip status for generated scripts with sources + logger.log(`Can't toggle skipFile status for ${resolvedSource} - it's a script with a sourcemap`); + return; + } + + const newStatus = !this.shouldSkipSource(resolvedSource.identifier); + logger.log(`Setting the skip file status for: ${resolvedSource} to ${newStatus}`); + this._skipFileStatuses.set(resolvedSource.identifier, newStatus); + + await this.resolveSkipFiles(resolvedSource.script, resolvedSource.script.developmentSource.identifier, + resolvedSource.script.mappedSources.map(s => s.identifier), /*toggling=*/true); + + if (newStatus) { + // TODO: Verify that using targetPath works here. We need targetPath to be this.getScriptByUrl(targetPath).url + this.makeRegexesSkip(resolvedSource.script.runtimeSource.identifier.textRepresentation); + } else { + this.makeRegexesNotSkip(resolvedSource.script.runtimeSource.identifier.textRepresentation); + } + + this.reprocessPausedEvent(); + }, async sourceIdentifier => { + logger.log(`Can't toggle the skipFile status for: ${sourceIdentifier} - haven't seen it yet.`); + }); + } + + private makeRegexesSkip(skipPath: string): void { + let somethingChanged = false; + this._blackboxedRegexes = this._blackboxedRegexes.map(regex => { + const result = utils.makeRegexMatchPath(regex, skipPath); + somethingChanged = somethingChanged || (result !== regex); + return result; + }); + + if (!somethingChanged) { + this._blackboxedRegexes.push(new RegExp(utils.pathToRegex(skipPath), 'i')); + } + + this.refreshBlackboxPatterns(); + } + + private refreshBlackboxPatterns(): void { + // Make sure debugging domain is enabled before calling refreshBlackboxPatterns() + this.chrome.Debugger.setBlackboxPatterns({ + patterns: this._blackboxedRegexes.map(regex => regex.source) + }).catch(() => this.warnNoSkipFiles()); + } + + private async isInCurrentStack(clientArgs: IToggleSkipFileStatusArgs): Promise { + const args = this._clientToInternal.toSource(clientArgs); + return args.tryResolving(async resolvedSource => { + const currentStack = await this.stackTracesLogic.stackTrace({ threadId: undefined }); + + return currentStack.stackFrames.some(frame => { + return frame.hasCodeFlow() + && frame.codeFlow.location.source + && frame.codeFlow.location.source.isEquivalent(resolvedSource); + }); + + }, + async () => { + return false; + }); + } + + private makeRegexesNotSkip(noSkipPath: string): void { + let somethingChanged = false; + this._blackboxedRegexes = this._blackboxedRegexes.map(regex => { + const result = utils.makeRegexNotMatchPath(regex, noSkipPath); + somethingChanged = somethingChanged || (result !== regex); + return result; + }); + + if (somethingChanged) { + this.refreshBlackboxPatterns(); + } + } + + public async resolveSkipFiles(script: IScript, mappedUrl: IResourceIdentifier, sources: IResourceIdentifier[], toggling?: boolean): Promise { + if (sources && sources.length) { + const parentIsSkipped = this.shouldSkipSource(script.runtimeSource.identifier); + const libPositions: Crdp.Debugger.ScriptPosition[] = []; + + // Figure out skip/noskip transitions within script + let inLibRange = parentIsSkipped; + for (let s of sources) { + let isSkippedFile = this.shouldSkipSource(s); + if (typeof isSkippedFile !== 'boolean') { + // Inherit the parent's status + isSkippedFile = parentIsSkipped; + } + + this._skipFileStatuses.set(s, isSkippedFile); + + if ((isSkippedFile && !inLibRange) || (!isSkippedFile && inLibRange)) { + const details = await this.sourceMapTransformer.allSourcePathDetails(mappedUrl.canonicalized); + const detail = details.find(d => parseResourceIdentifier(d.inferredPath).isEquivalent(s)); + libPositions.push({ + lineNumber: detail.startPosition.line, + columnNumber: detail.startPosition.column + }); + inLibRange = !inLibRange; + } + } + + // If there's any change from the default, set proper blackboxed ranges + if (libPositions.length || toggling) { + if (parentIsSkipped) { + libPositions.splice(0, 0, { lineNumber: 0, columnNumber: 0 }); + } + + if (libPositions[0].lineNumber !== 0 || libPositions[0].columnNumber !== 0) { + // The list of blackboxed ranges must start with 0,0 for some reason. + // https://github.com/Microsoft/vscode-chrome-debug/issues/667 + libPositions[0] = { + lineNumber: 0, + columnNumber: 0 + }; + } + + await this.chrome.Debugger.setBlackboxedRanges(script, []).catch(() => this.warnNoSkipFiles()); + + if (libPositions.length) { + this.chrome.Debugger.setBlackboxedRanges(script, libPositions).catch(() => this.warnNoSkipFiles()); + } + } + } else { + const status = await this.getSkipStatus(mappedUrl); + const skippedByPattern = this.matchesSkipFilesPatterns(mappedUrl); + if (typeof status === 'boolean' && status !== skippedByPattern) { + const positions = status ? [{ lineNumber: 0, columnNumber: 0 }] : []; + this.chrome.Debugger.setBlackboxedRanges(script, positions).catch(() => this.warnNoSkipFiles()); + } + } + } + + private warnNoSkipFiles(): void { + logger.log('Warning: this runtime does not support skipFiles'); + } + + private async onScriptParsed(scriptEvent: ScriptParsedEvent): Promise { + const script = scriptEvent.script; + const sources = script.mappedSources; + await this.resolveSkipFiles(script, script.developmentSource.identifier, sources.map(source => source.identifier)); + } + + public install(): this { + this._dependencies.onScriptParsed(scriptParsed => this.onScriptParsed(scriptParsed)); + this.configure(); + return this; + } + + private configure(): SkipFilesLogic { + const _launchAttachArgs: ISkipFilesConfiguration = this._configuration.args; + let patterns: string[] = []; + + if (_launchAttachArgs.skipFiles) { + const skipFilesArgs = _launchAttachArgs.skipFiles.filter(glob => { + if (glob.startsWith('!')) { + logger.warn(`Warning: skipFiles entries starting with '!' aren't supported and will be ignored. ("${glob}")`); + return false; + } + + return true; + }); + + patterns = skipFilesArgs.map(glob => utils.pathGlobToBlackboxedRegex(glob)); + } + + if (_launchAttachArgs.skipFileRegExps) { + patterns = patterns.concat(_launchAttachArgs.skipFileRegExps); + } + + if (patterns.length) { + this._blackboxedRegexes = patterns.map(pattern => new RegExp(pattern, 'i')); + this.refreshBlackboxPatterns(); + } + + return this; + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedBySkipFilesLogic, + @inject(TYPES.CDTPDiagnostics) private readonly chrome: CDTPDiagnostics, + @inject(new LazyServiceIdentifer(() => TYPES.StackTracesLogic)) private readonly stackTracesLogic: StackTracesLogic, + @inject(TYPES.BaseSourceMapTransformer) private readonly sourceMapTransformer: BaseSourceMapTransformer, + @inject(TYPES.ClientToInternal) private readonly _clientToInternal: ClientToInternal, + @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration + ) { } +} \ No newline at end of file diff --git a/src/chrome/internal/features/smartStep.ts b/src/chrome/internal/features/smartStep.ts new file mode 100644 index 000000000..354c850b6 --- /dev/null +++ b/src/chrome/internal/features/smartStep.ts @@ -0,0 +1,122 @@ +import { BasePathTransformer } from '../../../transformers/basePathTransformer'; +import { BaseSourceMapTransformer } from '../../../transformers/baseSourceMapTransformer'; +import { IScript } from '../scripts/script'; +import { ICallFrame } from '../stackTraces/callFrame'; +import { PausedEvent } from '../../target/events'; +import { InformationAboutPausedProvider } from './takeProperActionOnPausedEvent'; +import { logger } from 'vscode-debugadapter'; +import { IComponent } from './feature'; +import { LocationInLoadedSource } from '../locations/location'; +import { ICallFramePresentationDetails } from '../stackTraces/callFramePresentation'; +import { Abstained, VoteRelevance, VoteCommonLogic, Vote } from '../../communication/collaborativeDecision'; +import * as nls from 'vscode-nls'; +import { injectable, inject } from 'inversify'; +import { IStackTracePresentationLogicProvider } from '../stackTraces/stackTracesLogic'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { utils, ConnectedCDAConfiguration } from '../../..'; +const localize = nls.loadMessageBundle(); + +export interface EventsConsumedBySmartStepLogic { + subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; +} + +export interface SmartStepLogicConfiguration { + isEnabled: boolean; +} + +export interface ShouldStepInToAvoidSkippedSourceDependencies { + stepIntoDebugee(): Promise; +} +export class ShouldStepInToAvoidSkippedSource extends VoteCommonLogic { + public readonly relevance = VoteRelevance.OverrideOtherVotes; + + private readonly _dependencies: ShouldStepInToAvoidSkippedSourceDependencies; + + public async execute(): Promise { + return this._dependencies.stepIntoDebugee(); + } +} + +@injectable() +export class SmartStepLogic implements IComponent, IStackTracePresentationLogicProvider { + private _smartStepCount = 0; + private _isEnabled = false; + + public isEnabled(): boolean { + return this._isEnabled; + } + + public toggleEnabled(): void { + this.enable(!this._isEnabled); + } + + public enable(shouldEnable: boolean): void { + this._isEnabled = shouldEnable; + } + + public async toggleSmartStep(): Promise { + this.toggleEnabled(); + this.stepInIfOnSkippedSource(); + } + + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + if (this.isEnabled() && await this.shouldSkip(paused.callFrames[0])) { + this._smartStepCount++; + return new ShouldStepInToAvoidSkippedSource(); + } else { + if (this._smartStepCount > 0) { + logger.log(`SmartStep: Skipped ${this._smartStepCount} steps`); + this._smartStepCount = 0; + } + return new Abstained(this); + } + } + + public stepInIfOnSkippedSource(): void { + throw new Error('Not implemented TODO DIEGO'); + } + + public async shouldSkip(frame: ICallFrame): Promise { + if (!this._isEnabled) return false; + + const clientPath = this._pathTransformer.getClientPathFromTargetPath(frame.location.script.runtimeSource.identifier) + || frame.location.script.runtimeSource.identifier; + const mapping = await this._sourceMapTransformer.mapToAuthored(clientPath.canonicalized, frame.codeFlow.location.lineNumber, frame.codeFlow.location.columnNumber); + if (mapping) { + return false; + } + + if ((await this._sourceMapTransformer.allSources(clientPath.canonicalized)).length) { + return true; + } + + return false; + } + + public getCallFrameAdditionalDetails(locationInLoadedSource: LocationInLoadedSource): ICallFramePresentationDetails[] { + return this.isEnabled && !locationInLoadedSource.source.isMappedSource() + ? [{ + additionalSourceOrigins: [localize('smartStepFeatureName', 'smartStep')], + sourcePresentationHint: 'deemphasize' + }] + : []; + } + + public install(): this { + this._dependencies.subscriberForAskForInformationAboutPaused(paused => this.askForInformationAboutPaused(paused)); + this.configure(); + return this; + } + + public configure(): void { + this._isEnabled = !!utils.defaultIfUndefined(this._configuration.args.smartStep, this._configuration.isVSClient); + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedBySmartStepLogic, + @inject(TYPES.BasePathTransformer) private readonly _pathTransformer: BasePathTransformer, + @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, + @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration + ) { + } +} \ No newline at end of file diff --git a/src/chrome/internal/features/takeProperActionOnPausedEvent.ts b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts new file mode 100644 index 000000000..a97870ec5 --- /dev/null +++ b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts @@ -0,0 +1,91 @@ +import { IComponent } from './feature'; +import { PausedEvent } from '../../target/events'; +import { IEventsToClientReporter } from '../../client/eventSender'; +import { ReasonType } from '../../stoppedEvent'; +import { PromiseOrNot } from '../../utils/promises'; +import { Vote, VoteCommonLogic, VoteRelevance, ExecuteDecisionBasedOnVotes } from '../../communication/collaborativeDecision'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { IDebugeeExecutionControl } from '../../target/controlDebugeeExecution'; +import { ICDTPDebuggerEventsProvider } from '../../target/cdtpDebuggerEventsProvider'; + +export abstract class ResumeCommonLogic extends VoteCommonLogic { + protected readonly abstract _debugeeExecutionControl: IDebugeeExecutionControl; + + public async execute(): Promise { + this._debugeeExecutionControl.resume(); + } +} + +export abstract class NotifyStoppedCommonLogic extends VoteCommonLogic { + protected readonly exception: any; + protected readonly abstract reason: ReasonType; + protected readonly abstract _eventsToClientReporter: IEventsToClientReporter; + protected readonly abstract _publishGoingToPauseClient: () => void; + + public async execute(): Promise { + this._publishGoingToPauseClient(); + this._eventsToClientReporter.sendDebugeeIsStopped({ reason: this.reason, exception: this.exception }); + } +} + +export type InformationAboutPausedProvider = (paused: PausedEvent) => Promise>; + +export interface EventsConsumedByTakeProperActionOnPausedEvent extends TakeActionBasedOnInformationDependencies { + // onPaused(listener: (paused: PausedEvent) => Promise | void): void; +} + +@injectable() +export class TakeProperActionOnPausedEvent implements IComponent { + public async onPause(paused: PausedEvent): Promise { + // Ask all the listeners what information they can provide + const infoPieces = await this._dependencies.askForInformationAboutPause(paused); + + // Remove pieces without any relevant information + const relevantInfoPieces = infoPieces.filter(response => response.isRelevant()); + + await new TakeActionBasedOnInformation(relevantInfoPieces, this._eventsToClientReporter).takeAction(); + } + + public install(): this { + this._cdtpDebuggerEventsProvider.onPaused(paused => this.onPause(paused)); + return this; + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: TakeActionBasedOnInformationDependencies, + @inject(TYPES.ICDTPDebuggerEventsProvider) private readonly _cdtpDebuggerEventsProvider: ICDTPDebuggerEventsProvider, + @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { } +} + +export interface TakeActionBasedOnInformationDependencies { + askForInformationAboutPause(paused: PausedEvent): PromiseOrNot[]>; +} + +export class TakeActionBasedOnInformation { + private readonly _takeActionBasedOnVotes: ExecuteDecisionBasedOnVotes; + + public async takeAction(): Promise { + this.validatePieces(); + return this._takeActionBasedOnVotes.execute(); + } + + public validatePieces(): void { + // DIEGO TODO: Change this to send telemetry instead + if (this._takeActionBasedOnVotes.getCountOfVotesWithCertainRelevance(VoteRelevance.OverrideOtherVotes) > 1) { + throw new Error(`Didn't expect to have multiple override information pieces`); + } + + if (this._takeActionBasedOnVotes.getCountOfVotesWithCertainRelevance(VoteRelevance.NormalVote) > 1) { + throw new Error(`Didn't expect to have multiple information pieces`); + } + } + + constructor(piecesOfInformation: Vote[], + private readonly _eventsToClientReporter: IEventsToClientReporter) { + this._takeActionBasedOnVotes = new ExecuteDecisionBasedOnVotes(async () => { + // If we don't have any information whatsoever, then we assume that we stopped due to a debugger statement + return this._eventsToClientReporter.sendDebugeeIsStopped({ reason: 'debugger_statement' }); + }, piecesOfInformation); + } +} \ No newline at end of file diff --git a/src/chrome/internal/formattedExceptionParser.ts b/src/chrome/internal/formattedExceptionParser.ts new file mode 100644 index 000000000..d7b2b92a8 --- /dev/null +++ b/src/chrome/internal/formattedExceptionParser.ts @@ -0,0 +1,69 @@ +import { parseResourceIdentifier } from '../..'; +import { LocationInScript, Coordinates, LocationInLoadedSource } from './locations/location'; +import { IResourceIdentifier } from './sources/resourceIdentifier'; +import { CDTPScriptUrl } from './sources/resourceIdentifierSubtypes'; +import { createLineNumber, createColumnNumber } from './locations/subtypes'; +import { DeleteMeScriptsRegistry } from './scripts/scriptsRegistry'; + +export interface IFormattedExceptionLineDescription { + generateDescription(zeroBaseNumbers: boolean): string; +} + +class CodeFlowFrameDescription implements IFormattedExceptionLineDescription { + public generateDescription(zeroBaseNumbers: boolean): string { + return this.cdtpDescription.replace( + this.printLocation(this.scriptLocation.script.url, this.scriptLocation.coordinates, false), + this.printLocation(this.sourceLocation.source.identifier.textRepresentation, this.sourceLocation.coordinates, zeroBaseNumbers)); + } + + private printLocation(locationIdentifier: string, coordinates: Coordinates, zeroBaseNumbers: boolean): string { + const constantToAdd = zeroBaseNumbers ? 0 : 1; + return `${locationIdentifier}:${coordinates.lineNumber + constantToAdd}:${coordinates.columnNumber + constantToAdd}`; + } + + constructor( + public readonly cdtpDescription: string, + public readonly scriptLocation: LocationInScript, + public readonly sourceLocation: LocationInLoadedSource) { } +} + +class UnparsableFrameDescription implements IFormattedExceptionLineDescription { + public generateDescription(_zeroBaseNumbers: boolean): string { + return this.cdtpDescription; + } + + constructor( + public readonly cdtpDescription: string) { } +} + +export class FormattedExceptionParser { + // We parse stack trace from `this.formattedException`, source map it and return a new string + public async parse(): Promise { + return this.exceptionLines().map(line => { + const matches = line.match(/^\s+at (.*?)\s*\(?([^ ]+):(\d+):(\d+)\)?$/); + if (matches) { + const url = parseResourceIdentifier(matches[2]) as IResourceIdentifier; + const lineNumber = parseInt(matches[3], 10); + const zeroBasedLineNumber = createLineNumber(lineNumber - 1); + const columnNumber = createColumnNumber(parseInt(matches[4], 10)); + const zeroBasedColumnNumber = createColumnNumber(columnNumber - 1); + const scripts = this._scriptsLogic.getScriptsByPath(url); + if (scripts.length > 0) { + const scriptLocation = new LocationInScript(scripts[0], new Coordinates(zeroBasedLineNumber, zeroBasedColumnNumber)); + const location = scriptLocation.mappedToSource(); + return new CodeFlowFrameDescription(line, scriptLocation, location); + } + } + + return new UnparsableFrameDescription(line); + }); + } + + private exceptionLines() { + return this._formattedException.split(/\r?\n/); + } + + constructor( + private readonly _scriptsLogic: DeleteMeScriptsRegistry, + private readonly _formattedException: string) { } +} \ No newline at end of file diff --git a/src/chrome/internal/locations/location.ts b/src/chrome/internal/locations/location.ts new file mode 100644 index 000000000..1244f3f39 --- /dev/null +++ b/src/chrome/internal/locations/location.ts @@ -0,0 +1,157 @@ +import * as Validation from '../../../validation'; +import { IScript } from '../scripts/script'; +import { ISource } from '../sources/source'; +import { ILoadedSource } from '../sources/loadedSource'; +import { logger } from 'vscode-debugadapter'; +import { ColumnNumber, LineNumber, URLRegexp } from './subtypes'; +import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; +import { IResourceIdentifier, parseResourceIdentifier, URL } from '../sources/resourceIdentifier'; + +export type integer = number; + +export class Coordinates { + public isSameAs(location: Coordinates): boolean { + return this.lineNumber === location.lineNumber + && this.columnNumber === location.columnNumber; + } + + public toString(): string { + return this.columnNumber !== undefined + ? `${this.lineNumber}:${this.columnNumber}` + : `${this.lineNumber}`; + } + + constructor( + public readonly lineNumber: LineNumber, + public readonly columnNumber?: ColumnNumber) { + Validation.zeroOrPositive('Line number', lineNumber); + if (columnNumber !== undefined) { + Validation.zeroOrPositive('Column number', columnNumber); + } + } +} + +interface ILocation { + readonly lineNumber: integer; + readonly columnNumber?: integer; + readonly coordinates: Coordinates; + readonly resource: T; +} + +export type ScriptOrSourceOrURLOrURLRegexp = IScript | ILoadedSource | ISource | URLRegexp | URL; + +export type Location = + T extends ISource ? LocationInSource : // Used when receiving locations from the client + T extends ILoadedSource ? LocationInLoadedSource : // Used to translate between locations on the client and the debugee + T extends IScript ? LocationInScript : // Used when receiving locations from the debugee + T extends URLRegexp ? LocationInUrlRegexp : // Used when setting a breakpoint by URL in a local file path in windows, to make it case insensitive + T extends URL ? LocationInUrl : // Used when setting a breakpoint by URL for case-insensitive URLs + never; + +abstract class LocationCommonLogic implements ILocation { + public get lineNumber(): LineNumber { + return this.coordinates.lineNumber; + } + + public get columnNumber(): ColumnNumber { + return this.coordinates.columnNumber; + } + + public toString(): string { + return `${this.resource}:${this.coordinates}`; + } + + constructor( + public readonly resource: T, + public readonly coordinates: Coordinates) { } +} + +export class LocationInSource extends LocationCommonLogic implements ILocation { + public get identifier(): ISource { + return this.resource; + } + + public tryResolvingSource( + whenSuccesfulDo: (locationInLoadedSource: LocationInLoadedSource) => R, + whenFailedDo: (locationInSource: LocationInSource) => R): R { + return this.identifier.tryResolving( + loadedSource => whenSuccesfulDo(new LocationInLoadedSource(loadedSource, this.coordinates)), + () => whenFailedDo(this)); + } + + public resolvedWith(loadedSource: ILoadedSource): LocationInLoadedSource { + if (this.resource.sourceIdentifier.isEquivalent(loadedSource.identifier)) { + return new LocationInLoadedSource(loadedSource, this.coordinates); + } else { + throw new Error(`Can't resolve a location with a source (${this}) to a location with a loaded source that doesn't match the unresolved source: ${loadedSource}`); + } + } +} + +export class LocationInScript extends LocationCommonLogic implements ILocation { + public get script(): IScript { + return this.resource; + } + + public mappedToSource(): LocationInLoadedSource { + const mapped = this.script.sourcesMapper.getPositionInSource({ line: this.lineNumber, column: this.columnNumber }); + if (mapped) { + const loadedSource = this.script.getSource(parseResourceIdentifier(mapped.source)); + const result = new LocationInLoadedSource(loadedSource, new Coordinates(mapped.line, mapped.column)); + logger.verbose(`SourceMap: ${this} to ${result}`); + return result; + } else { + return new LocationInLoadedSource(this.script.developmentSource, this.coordinates); + } + } + + public mappedToUrl(): LocationInUrl { + if (this.script.runtimeSource.doesScriptHasUrl()) { + return new LocationInUrl(this.script.runtimeSource.identifier, this.coordinates); + } else { + throw new Error(`Can't convert a location in a script without an URL (${this}) into a location in an URL`); + } + } + + public isSameAs(locationInScript: LocationInScript): boolean { + return this.script === locationInScript.script && + this.coordinates.isSameAs(locationInScript.coordinates); + } + + public toString(): string { + return `${this.resource}:${this.coordinates}`; + } +} + +export class LocationInLoadedSource extends LocationCommonLogic implements ILocation { + public get source(): ILoadedSource { + return this.resource; + } + + public mappedToScript(): LocationInScript { + const mapped = this.source.script.sourcesMapper.getPositionInScript({ + source: this.source.identifier.textRepresentation, + line: this.lineNumber, + column: this.columnNumber + }); + if (mapped) { + const result = new LocationInScript(this.source.script, new Coordinates(mapped.line, mapped.column)); + logger.verbose(`SourceMap: ${this} to ${result}`); + return result; + } else { + throw new Error(`Couldn't map the location (${this.coordinates}) in the source $(${this.source}) to a script file`); + } + } +} + +export class LocationInUrl extends LocationCommonLogic> implements ILocation> { + public get url(): URL { + return this.resource; + } +} + +export class LocationInUrlRegexp extends LocationCommonLogic implements ILocation { + public get urlRegexp(): URLRegexp { + return this.resource; + } +} diff --git a/src/chrome/internal/locations/rangeInScript.ts b/src/chrome/internal/locations/rangeInScript.ts new file mode 100644 index 000000000..7b1e8a4ed --- /dev/null +++ b/src/chrome/internal/locations/rangeInScript.ts @@ -0,0 +1,23 @@ +import { Coordinates, LocationInScript } from './location'; +import { IScript } from '../scripts/script'; + +/** Used by CDTP getPossibleBreakpoints API to inquire the valid set of positions for a breakpoint in a particular range of the script */ +export class RangeInScript { + constructor( + public readonly script: IScript, + public readonly start: Coordinates, + public readonly end: Coordinates) { + if (start.lineNumber > end.lineNumber + || (start.lineNumber === end.lineNumber && start.columnNumber > end.columnNumber)) { + throw new Error(`Can't create a range in a script ${script.runtimeSource} where the end position (${end}) happens before the start position ${start}`); + } + } + + public get startInScript(): LocationInScript { + return new LocationInScript(this.script, this.start); + } + + public get endInScript(): LocationInScript { + return new LocationInScript(this.script, this.end); + } +} diff --git a/src/chrome/internal/locations/subtypes.ts b/src/chrome/internal/locations/subtypes.ts index 17405f551..2671c2012 100644 --- a/src/chrome/internal/locations/subtypes.ts +++ b/src/chrome/internal/locations/subtypes.ts @@ -3,5 +3,20 @@ const lineIndexSymbol = Symbol(); export type LineNumber = number & { [lineIndexSymbol]: true }; +export function createLineNumber(numberRepresentation: number): LineNumber { + return numberRepresentation; +} + const columnIndexSymbol = Symbol(); export type ColumnNumber = number & { [columnIndexSymbol]: true }; + +export function createColumnNumber(numberRepresentation: number): ColumnNumber { + return numberRepresentation; +} + +const URLRegexpSymbol = Symbol(); +export type URLRegexp = string & { [URLRegexpSymbol]: true }; + +export function createURLRegexp(textRepresentation: string): URLRegexp { + return textRepresentation; +} \ No newline at end of file diff --git a/src/chrome/internal/requests.ts b/src/chrome/internal/requests.ts new file mode 100644 index 000000000..211047023 --- /dev/null +++ b/src/chrome/internal/requests.ts @@ -0,0 +1,20 @@ +import { IScript } from './scripts/script'; +import { ILoadedSource } from './sources/loadedSource'; +import { ICallFrame } from './stackTraces/callFrame'; + +export interface EvaluateArguments { + readonly expression: string; + readonly frame?: ICallFrame; + readonly context?: string; + readonly format?: { + /** Display the value in hex. */ + readonly hex?: boolean; + }; +} + +export interface CompletionsArguments { + readonly frame?: ICallFrame; + readonly text: string; + readonly column: number; + readonly line?: number; +} diff --git a/src/chrome/internal/scripts/script.ts b/src/chrome/internal/scripts/script.ts index d5ea4e45e..7512c83f8 100644 --- a/src/chrome/internal/scripts/script.ts +++ b/src/chrome/internal/scripts/script.ts @@ -18,7 +18,7 @@ export interface IScript { readonly runtimeSource: ILoadedSource; // Source in Webserver readonly developmentSource: ILoadedSource; // Source in Workspace readonly mappedSources: MappedSource[]; // Sources before compilation - readonly allSources: ILoadedSource[]; // runtimeSource + developmentSource + sourcesOfCompiled + readonly allSources: ILoadedSource[]; // runtimeSource + developmentSource + mappedSources readonly url: CDTPScriptUrl; readonly sourcesMapper: ISourcesMapper; // TODO DIEGO: See if we can delete this property @@ -35,7 +35,7 @@ export class Script implements IScript { public static create(executionContext: IExecutionContext, locationInRuntimeEnvironment: IResourceLocation, locationInDevelopmentEnvinronment: IResourceLocation, sourcesMapper: ISourcesMapper): Script { - const sourcesOfCompiled = (script: IScript) => newResourceIdentifierMap(sourcesMapper.sources.map(path => { + const mappedSources = (script: IScript) => newResourceIdentifierMap(sourcesMapper.sources.map(path => { const identifier = parseResourceIdentifier(path); return [identifier, new MappedSource(script, identifier, 'TODO DIEGO')] as [IResourceIdentifier, MappedSource]; })); @@ -61,7 +61,7 @@ export class Script implements IScript { runtimeSource = script => new ScriptRuntimeSource(script, locationInRuntimeEnvironment, 'TODO DIEGO'); developmentSource = script => new ScriptDevelopmentSource(script, locationInDevelopmentEnvinronment, 'TODO DIEGO'); } - return new Script(executionContext, runtimeSource, developmentSource, sourcesOfCompiled, sourcesMapper); + return new Script(executionContext, runtimeSource, developmentSource, mappedSources, sourcesMapper); } public static createEval(executionContext: IExecutionContext, name: ResourceName, sourcesMapper: ISourcesMapper): Script { diff --git a/src/chrome/internal/scripts/scriptsRegistry.ts b/src/chrome/internal/scripts/scriptsRegistry.ts new file mode 100644 index 000000000..dd5fbfeb2 --- /dev/null +++ b/src/chrome/internal/scripts/scriptsRegistry.ts @@ -0,0 +1,94 @@ +import { Crdp } from '../../..'; +import { IScript } from './script'; +import { ValidatedMap } from '../../collections/validatedMap'; +import { IResourceIdentifier, newResourceIdentifierMap } from '../sources/resourceIdentifier'; +import { ExecutionContext, IExecutionContext } from './executionContext'; +import { injectable } from 'inversify'; + +@injectable() +export class DeleteMeScriptsRegistry { + private readonly _scriptsGeneration = new ScriptsGeneration(); + private readonly _idToExecutionContext = new ValidatedMap(); + + public registerExecutionContext(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { + const executionContext = new ExecutionContext(); + this._idToExecutionContext.set(executionContextId, executionContext); + return executionContext; + } + + public getExecutionContextById(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { + return this._idToExecutionContext.get(executionContextId); + } + + public registerNewScript(scriptId: Crdp.Runtime.ScriptId, obtainScript: () => Promise): Promise { + return this._scriptsGeneration.registerNewScript(scriptId, obtainScript); + } + + public getCrdpId(script: IScript): any { + return this._scriptsGeneration.getCdtpId(script); + } + + public getScriptById(runtimeScriptCrdpId: Crdp.Runtime.ScriptId): Promise { + return this._scriptsGeneration.scriptById(runtimeScriptCrdpId); + } + + public getScriptsByPath(nameOrLocation: IResourceIdentifier): IScript[] { + return this._scriptsGeneration.getScriptByPath(nameOrLocation); + } + + public getAllScripts(): Promise { + return this._scriptsGeneration.getAllScripts(); + } +} + +export class ScriptsGeneration { + private readonly _cdtpIdByScript = new ValidatedMap>(); + private readonly _scriptByCdtpId = new ValidatedMap(); + private readonly _scriptByPath = newResourceIdentifierMap(); + + private createScriptInitialConfiguration(scriptId: Crdp.Runtime.ScriptId, script: IScript): void { + this._scriptByCdtpId.set(script, scriptId); + + let scriptsWithSamePath = this._scriptByPath.getOrAdd(script.runtimeSource.identifier, () => []); + scriptsWithSamePath.push(script); + } + + public async registerNewScript(scriptId: Crdp.Runtime.ScriptId, obtainScript: () => Promise): Promise { + const scriptWithConfigurationPromise = obtainScript().then(script => { + /** + * We need to configure the script here, so we can guarantee that clients who try to use a script will get + * blocked until the script is created, and all the initial configuration is done, so they can use APIs to get + * the script id, search by URL, etc... + */ + this.createScriptInitialConfiguration(scriptId, script); + return script; + }); + + this._cdtpIdByScript.set(scriptId, scriptWithConfigurationPromise); + + return await scriptWithConfigurationPromise; + } + + public getCdtpId(script: IScript): Crdp.Runtime.ScriptId { + const scriptId = this._scriptByCdtpId.get(script); + + if (script === undefined) { + throw new Error(`Couldn't find a CRDP id for script ${script}`); + } + + return scriptId; + } + + public scriptById(runtimeScriptCrdpId: string): Promise { + return this._cdtpIdByScript.get(runtimeScriptCrdpId); + } + + public getScriptByPath(path: IResourceIdentifier): IScript[] { + const runtimeScript = this._scriptByPath.tryGetting(path); + return runtimeScript || []; + } + + public getAllScripts(): Promise { + return Promise.all(Array.from(this._cdtpIdByScript.values())); + } +} diff --git a/src/chrome/internal/scripts/sourcesMapper.ts b/src/chrome/internal/scripts/sourcesMapper.ts index b0d956b6c..f655d11c2 100644 --- a/src/chrome/internal/scripts/sourcesMapper.ts +++ b/src/chrome/internal/scripts/sourcesMapper.ts @@ -1,4 +1,4 @@ -import { LineNumber, ColumnNumber } from '../locations/subtypes'; +import { LineNumber, ColumnNumber, createColumnNumber, createLineNumber } from '../locations/subtypes'; import { SourceMap } from '../../../sourceMaps/sourceMap'; export interface ISourcesMapper { @@ -23,7 +23,7 @@ export class SourcesMapper implements ISourcesMapper { public getPositionInSource(positionInScript: IPositionInScript): IPositionInSource | null { const mappedPosition = this._sourceMap.authoredPositionFor(positionInScript.line, positionInScript.column || 0); return mappedPosition && mappedPosition.source && mappedPosition.line - ? { source: mappedPosition.source, line: mappedPosition.line as LineNumber, column: mappedPosition.column as ColumnNumber } + ? { source: mappedPosition.source, line: createLineNumber(mappedPosition.line), column: createColumnNumber(mappedPosition.column) } : null; } @@ -31,7 +31,7 @@ export class SourcesMapper implements ISourcesMapper { const mappedPosition = this._sourceMap.generatedPositionFor(positionInSource.source, positionInSource.line, positionInSource.column || 0); return mappedPosition && mappedPosition.line - ? { line: mappedPosition.line as LineNumber, column: mappedPosition.column as ColumnNumber } + ? { line: createLineNumber(mappedPosition.line), column: createColumnNumber(mappedPosition.column) } : null; } diff --git a/src/chrome/internal/services/logging.ts b/src/chrome/internal/services/logging.ts new file mode 100644 index 000000000..25f18440c --- /dev/null +++ b/src/chrome/internal/services/logging.ts @@ -0,0 +1,28 @@ +import { Logger, logger } from 'vscode-debugadapter'; +import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; + +export interface LoggingConfiguration { + logLevel?: Logger.LogLevel; + shouldLogTimestamps: boolean; + logFilePath: string; +} + +export class Logging { + public verbose(entry: string): void { + logger.verbose(entry); + } + + public install(extensibilityPoints: IExtensibilityPoints, configuration: LoggingConfiguration): this { + this.configure(extensibilityPoints, configuration); + return this; + } + + public configure(extensibilityPoints: IExtensibilityPoints, configuration: LoggingConfiguration): void { + const logToFile = !!configuration.logLevel; + + // The debug configuration provider should have set logFilePath on the launch config. If not, default to 'true' to use the + // "legacy" log file path from the CDA subclass + const logFilePath = configuration.logFilePath || extensibilityPoints.logFilePath || logToFile; + logger.setup(configuration.logLevel || Logger.LogLevel.Warn, logFilePath, configuration.shouldLogTimestamps); + } +} \ No newline at end of file diff --git a/src/chrome/internal/sources/features/dotScriptsCommand.ts b/src/chrome/internal/sources/features/dotScriptsCommand.ts new file mode 100644 index 000000000..8e7e5eb2b --- /dev/null +++ b/src/chrome/internal/sources/features/dotScriptsCommand.ts @@ -0,0 +1,68 @@ +import { IScript } from '../../scripts/script'; + +import { parseResourceIdentifier } from '../../../..'; + +import { IEventsToClientReporter } from '../../../client/eventSender'; +import { determineOrderingOfStrings } from '../../../collections/utilities'; +import { inject, injectable } from 'inversify'; +import { BaseSourceMapTransformer } from '../../../../transformers/baseSourceMapTransformer'; +import { DeleteMeScriptsRegistry } from '../../scripts/scriptsRegistry'; +import { TYPES } from '../../../dependencyInjection.ts/types'; +import { IScriptSources } from '../../../target/cdtpDebugger'; + +@injectable() +export class DotScriptCommand { + /** + * Handle the .scripts command, which can be used as `.scripts` to return a list of all script details, + * or `.scripts ` to show the contents of the given script. + */ + public handleScriptsCommand(scriptsRest: string): Promise { + let outputStringP: Promise; + if (scriptsRest) { + // `.scripts ` was used, look up the script by url + const requestedScript = this._scriptsLogic.getScriptsByPath(parseResourceIdentifier(scriptsRest)); + if (requestedScript) { + outputStringP = this._scriptSources.getScriptSource(requestedScript[0]) + .then(result => { + const maxLength = 1e5; + return result.length > maxLength ? + result.substr(0, maxLength) + '[⋯]' : + result; + }); + } else { + outputStringP = Promise.resolve(`No runtime script with url: ${scriptsRest}\n`); + } + } else { + outputStringP = this.getAllScriptsString(); + } + + return outputStringP.then(scriptsStr => { + this._eventsToClientReporter.sendOutput({ output: scriptsStr, category: null }); + }); + } + + private async getAllScriptsString(): Promise { + const scripts = (await this._scriptsLogic.getAllScripts()).sort((left, script) => determineOrderingOfStrings(left.url, script.url)); + const scriptsPrinted = await Promise.all(scripts.map(script => this.getOneScriptString(script))); + return scriptsPrinted.join('\n'); + } + + private getOneScriptString(script: IScript): Promise { + let result = '› ' + script.runtimeSource.identifier.textRepresentation; + const clientPath = script.developmentSource.identifier.textRepresentation; + if (script.developmentSource !== script.runtimeSource) result += ` (${clientPath})`; + + return this._sourceMapTransformer.allSourcePathDetails(script.developmentSource.identifier.canonicalized).then(sourcePathDetails => { + let mappedSourcesStr = sourcePathDetails.map(details => ` - ${details.originalPath} (${details.inferredPath})`).join('\n'); + if (sourcePathDetails.length) mappedSourcesStr = '\n' + mappedSourcesStr; + + return result + mappedSourcesStr; + }); + } + + constructor( + @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, + @inject(TYPES.DeleteMeScriptsRegistry) private readonly _scriptsLogic: DeleteMeScriptsRegistry, + @inject(TYPES.IScriptSources) private readonly _scriptSources: IScriptSources, + @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter) { } +} diff --git a/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts new file mode 100644 index 000000000..da00dc7a9 --- /dev/null +++ b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts @@ -0,0 +1,76 @@ +import { IComponent } from '../../features/feature'; +import { IScript } from '../../scripts/script'; +import { ScriptParsedEvent } from '../../../target/events'; +import { telemetry } from '../../../../telemetry'; +import { SourceWasLoadedParameters, IEventsToClientReporter } from '../../../client/eventSender'; +import { ValidatedMap } from '../../../collections/validatedMap'; +import { CDTPScriptUrl } from '../resourceIdentifierSubtypes'; +import { LoadedSourceEventReason, utils } from '../../../..'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../../dependencyInjection.ts/types'; + +export interface NotifyClientOfLoadedSourcesDependencies { + sendSourceWasLoaded(params: SourceWasLoadedParameters): Promise; + onScriptParsed(listener: (scriptEvent: ScriptParsedEvent) => Promise): void; +} + +@injectable() +export class NotifyClientOfLoadedSources implements IComponent { + // TODO DIEGO: Ask VS what index do they use internally to verify if the source is the same or a new one + private _notifiedSourceByUrl = new ValidatedMap(); + + public install(): this { + this._dependencies.onScriptParsed(async scriptParsed => this.sendLoadedSourceEvent(scriptParsed.script, 'new')); + return this; + } + + /** + * e.g. the target navigated + */ + protected onExecutionContextsCleared(): void { + for (const script of this._notifiedSourceByUrl.values()) { + this.sendLoadedSourceEvent(script, 'removed'); + } + } + + protected async sendLoadedSourceEvent(script: IScript, loadedSourceEventReason: LoadedSourceEventReason): Promise { + switch (loadedSourceEventReason) { + case 'new': + case 'changed': + if (script.executionContext.isDestroyed()) { + return; // We processed the events out of order, and this event got here after we destroyed the context. ignore it. + } + + if (this._notifiedSourceByUrl.tryGetting(script.url) !== undefined) { + const exists = await utils.existsAsync(script.developmentSource.identifier.canonicalized); + if (exists) { + // We only need to send changed events for dynamic scripts. The client tracks files on storage on it's own, so this notification is not needed + loadedSourceEventReason = 'changed'; + } else { + return; // VS is strict about the changed notifications, and it will fail if we send a changed notification for a file on storage, so we omit it on purpose + } + } else { + loadedSourceEventReason = 'new'; + } + this._notifiedSourceByUrl.set(script.url, script); + break; + case 'removed': + if (!this._notifiedSourceByUrl.delete(script.url)) { + telemetry.reportEvent('LoadedSourceEventError', { issue: 'Tried to remove non-existent script', scriptId: script }); + return; + } + break; + default: + telemetry.reportEvent('LoadedSourceEventError', { issue: 'Unknown reason', reason: loadedSourceEventReason }); + } + + // TODO DIEGO: Should we be using the source tree here? + // const sourceTree = this._sourcesLogic.getLoadedSourcesTree(script.script); + + this._eventsToClientReporter.sendSourceWasLoaded({ reason: loadedSourceEventReason, source: script.developmentSource }); + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: NotifyClientOfLoadedSourcesDependencies, + @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter) { } +} \ No newline at end of file diff --git a/src/chrome/internal/sources/sourceResolver.ts b/src/chrome/internal/sources/sourceResolver.ts index 5a75dad46..4e7c7e9f7 100644 --- a/src/chrome/internal/sources/sourceResolver.ts +++ b/src/chrome/internal/sources/sourceResolver.ts @@ -50,4 +50,4 @@ export class SourceResolver implements IComponent { constructor( @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedBySourceResolver) { } -} \ No newline at end of file +} diff --git a/src/chrome/internal/sources/sourcesLogic.ts b/src/chrome/internal/sources/sourcesLogic.ts new file mode 100644 index 000000000..6116cc251 --- /dev/null +++ b/src/chrome/internal/sources/sourcesLogic.ts @@ -0,0 +1,60 @@ +import { SourceTextLogic } from './sourcesTextLogic'; +import { SourcesTreeNodeLogic } from './sourcesTreeNodeLogic'; +import { SourceResolver } from './sourceResolver'; +import { ILoadedSource, ILoadedSourceTreeNode } from './loadedSource'; +import { ISource } from './source'; +import { IScript } from '../scripts/script'; +import { IResourceIdentifier } from './resourceIdentifier'; +import { IComponent } from '../features/feature'; +import { injectable } from 'inversify'; + +@injectable() +export class SourcesLogic implements IComponent { + public tryResolving(sourceIdentifier: IResourceIdentifier, + ifSuccesfulDo: (resolvedSource: ILoadedSource) => R, + ifFailedDo?: (sourceIdentifier: IResourceIdentifier) => R): R { + return this._sourceResolverLogic.tryResolving(sourceIdentifier, ifSuccesfulDo, ifFailedDo); + } + + public createSourceResolver(sourceIdentifier: IResourceIdentifier): ISource { + return this._sourceResolverLogic.createUnresolvedSource(sourceIdentifier); + } + + public async getLoadedSourcesTrees(): Promise { + return this._sourceTreeNodeLogic.getLoadedSourcesTrees(); + } + + public getLoadedSourcesTreeForScript(script: IScript): ILoadedSourceTreeNode { + return this._sourceTreeNodeLogic.getLoadedSourcesTreeForScript(script); + } + + public async getScriptText(script: IScript): Promise { + return await this._sourceTextLogic.text(script.runtimeSource); + } + + public async getText(source: ISource): Promise { + return await source.tryResolving( + async loadedSource => await this._sourceTextLogic.text(loadedSource), + identifier => { + throw new Error(`Couldn't resolve the source with the path: ${identifier.textRepresentation}`); + }); + } + + public toString(): string { + return `Sources logic {\nResolver:\n${this._sourceResolverLogic}\n` + + `Text:\n${this._sourceTextLogic}\nTree node:\n${this._sourceTreeNodeLogic}\n}`; + } + + public async install(): Promise { + await this._sourceResolverLogic.install(); + await this._sourceTextLogic.install(); + await this._sourceTreeNodeLogic.install(); + return this; + } + + constructor( + private readonly _sourceResolverLogic: SourceResolver, + private readonly _sourceTextLogic: SourceTextLogic, + private readonly _sourceTreeNodeLogic: SourcesTreeNodeLogic + ) { } +} \ No newline at end of file diff --git a/src/chrome/internal/sources/sourcesTextLogic.ts b/src/chrome/internal/sources/sourcesTextLogic.ts new file mode 100644 index 000000000..b6ac9b1b4 --- /dev/null +++ b/src/chrome/internal/sources/sourcesTextLogic.ts @@ -0,0 +1,33 @@ +import { ILoadedSource } from './loadedSource'; +import { ValidatedMap } from '../../collections/validatedMap'; +import { printIterable } from '../../collections/printting'; +import { IComponent } from '../features/feature'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { IScriptSources } from '../../target/cdtpDebugger'; + +@injectable() +export class SourceTextLogic implements IComponent { + private _sourceToText = new ValidatedMap(); + + public async text(loadedSource: ILoadedSource): Promise { + let text = this._sourceToText.tryGetting(loadedSource); + + if (text !== null) { + text = await this._scriptSources.getScriptSource(loadedSource.script); + this._sourceToText.set(loadedSource, text); + } + + return text; + } + + public toString(): string { + return `Sources text logic\n${printIterable('sources in cache', this._sourceToText.keys())}`; + } + + public install(): this { + return this; + } + + constructor(@inject(TYPES.IScriptSources) private readonly _scriptSources: IScriptSources) { } +} \ No newline at end of file diff --git a/src/chrome/internal/sources/sourcesTreeNodeLogic.ts b/src/chrome/internal/sources/sourcesTreeNodeLogic.ts new file mode 100644 index 000000000..2d95eb5b3 --- /dev/null +++ b/src/chrome/internal/sources/sourcesTreeNodeLogic.ts @@ -0,0 +1,44 @@ +import { ILoadedSource, ILoadedSourceTreeNode, determineOrderingOfLoadedSources } from './loadedSource'; +import { IScript } from '../scripts/script'; +import { IComponent } from '../features/feature'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { CDTPScriptsRegistry } from '../../target/cdtpScriptsRegistry'; + +@injectable() +export class SourcesTreeNodeLogic implements IComponent { + /* + We create a tree like: + + RuntimeSource_1 + + RuntimeSource_2 + - Source of Compiled_2_a + - Source of Compiled_2_b + */ + // TODO DIEGO: Verify if this is the format we should use for the tree + public async getLoadedSourcesTrees(): Promise { + const scripts = await Promise.all(Array.from(await this._cdtpScriptsRegistry.getAllScripts())); + const sourceMetadataTree = scripts.map(script => this.getLoadedSourcesTreeForScript(script)); + return sourceMetadataTree; + } + + public getLoadedSourcesTreeForScript(script: IScript): ILoadedSourceTreeNode { + const sortedSourcesOfCompiled = script.mappedSources.sort(determineOrderingOfLoadedSources); + return this.toTreeNode(script.runtimeSource, this.toTreeNodes(sortedSourcesOfCompiled)); + } + + private toTreeNodes(sources: ILoadedSource[]): ILoadedSourceTreeNode[] { + return sources.map(source => this.toTreeNode(source, [])); + } + + private toTreeNode(source: ILoadedSource, relatedSources: ILoadedSourceTreeNode[] = []): ILoadedSourceTreeNode { + // TODO DIEGO: MAKE ORIGIN WORK + // const origin = [this._chromeDebugAdapter.getReadonlyOrigin(source.script.runtimeSource.identifier.textRepresentation)]; + return { mainSource: source, relatedSources: relatedSources }; + } + + public install(): this { + return this; + } + + constructor(@inject(TYPES.CDTPScriptsRegistry) private readonly _cdtpScriptsRegistry: CDTPScriptsRegistry) { } +} \ No newline at end of file diff --git a/src/chrome/internal/sources/unresolvedSource.ts b/src/chrome/internal/sources/unresolvedSource.ts new file mode 100644 index 000000000..dac05a6a9 --- /dev/null +++ b/src/chrome/internal/sources/unresolvedSource.ts @@ -0,0 +1,51 @@ +import { IResourceIdentifier } from './resourceIdentifier'; +import { ILoadedSource } from './loadedSource'; +import { SourceResolver } from './sourceResolver'; + +export interface IUnresolvedSource { + readonly sourceIdentifier: IResourceIdentifier; + isEquivalent(right: IUnresolvedSource): boolean; + tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, failedAction: (sourceIdentifier: IResourceIdentifier) => R): R; +} + +abstract class UnresolvedSourceCommonLogic implements IUnresolvedSource { + public abstract tryResolving(succesfulAction: (loadedSource: ILoadedSource) => R, failedAction: (identifier: IResourceIdentifier) => R): R; + public abstract get sourceIdentifier(): IResourceIdentifier; + + public isEquivalent(right: IUnresolvedSource): boolean { + return this.sourceIdentifier.isEquivalent(right.sourceIdentifier); + } +} + +// Find the source to resolve to by using the path +export class SourceToBeResolvedViaPath extends UnresolvedSourceCommonLogic implements IUnresolvedSource { + public tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, failedAction: (sourceIdentifier: IResourceIdentifier) => R) { + return this._sourceResolver.tryResolving(this.sourceIdentifier, succesfulAction, failedAction); + } + + public toString(): string { + return `Resolve source using #${this.sourceIdentifier}`; + } + + constructor(public readonly sourceIdentifier: IResourceIdentifier, private readonly _sourceResolver: SourceResolver) { + super(); + } +} + +export class SourceAlreadyResolvedToLoadedSource extends UnresolvedSourceCommonLogic implements IUnresolvedSource { + public tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, _failedAction: (sourceIdentifier: IResourceIdentifier) => R) { + return succesfulAction(this.loadedSource); + } + + public get sourceIdentifier(): IResourceIdentifier { + return this.loadedSource.identifier; + } + + public toString(): string { + return `${this.loadedSource}`; + } + + constructor(public readonly loadedSource: ILoadedSource) { + super(); + } +} diff --git a/src/chrome/internal/stackTraces/callFrame.ts b/src/chrome/internal/stackTraces/callFrame.ts new file mode 100644 index 000000000..5d7ba97d4 --- /dev/null +++ b/src/chrome/internal/stackTraces/callFrame.ts @@ -0,0 +1,115 @@ +import { Location } from '../locations/location'; +import { integer } from '../../target/events'; +import { ILoadedSource } from '../sources/loadedSource'; +import { IScript } from '../scripts/script'; +import { Crdp } from '../../..'; +import { ICallFrameName } from './callFrameName'; +import { Scope } from './scopes'; + +export type ScriptOrLoadedSource = IScript | ILoadedSource; // Used for stack traces + +/** This interface represents the code flow (which code was executed) of a call frame */ +export class CodeFlowFrame { + constructor( + public readonly index: integer, + public readonly nameStrategy: ICallFrameName, + public readonly location: Location) { } + + public get source(): TResource extends ILoadedSource ? TResource : never { + return this.location.resource as any; + } + + public get script(): TResource extends IScript ? TResource : never { + return this.location.resource as any; + } + + public get lineNumber(): number { + return this.location.lineNumber; + } + + public get columnNumber(): number { + return this.location.columnNumber; + } + + public get name(): string { + return this.nameStrategy.name; + } +} + +export interface ICallFrame { + readonly index: number; + readonly source: TResource extends ILoadedSource ? TResource : never; + readonly location: Location; + readonly lineNumber: number; + readonly columnNumber: number; + readonly name: string; + readonly codeFlow: CodeFlowFrame; + readonly scopeChain: Scope[]; + readonly frameThis?: Crdp.Runtime.RemoteObject; + readonly returnValue?: Crdp.Runtime.RemoteObject; + readonly unmappedCallFrame: ICallFrame; +} + +abstract class CallFrameCommonLogic implements ICallFrame { + public abstract get scopeChain(): Scope[]; + public abstract get unmappedCallFrame(): ICallFrame; + public abstract get codeFlow(): CodeFlowFrame; + + public get source(): TResource extends ILoadedSource ? TResource : never { + return this.codeFlow.source; + } + + public get location(): Location { + return this.codeFlow.location; + } + + public get lineNumber(): number { + return this.codeFlow.lineNumber; + } + + public get columnNumber(): number { + return this.codeFlow.columnNumber; + } + + public get index(): number { + return this.codeFlow.index; + } + + public get name(): string { + return this.codeFlow.name; + } +} + +export class ScriptCallFrame extends CallFrameCommonLogic { + public get unmappedCallFrame(): ICallFrame { + return this; + } + + constructor( + public readonly codeFlow: CodeFlowFrame, + public readonly scopeChain: Scope[], + public readonly frameThis?: Crdp.Runtime.RemoteObject, // This is optional only to support Runtime.StackTraces aka StackTraceCodeFlow + public readonly returnValue?: Crdp.Runtime.RemoteObject) { + super(); + } +} + +export class LoadedSourceCallFrame extends CallFrameCommonLogic { + public get scopeChain(): Scope[] { + return this.unmappedCallFrame.scopeChain; + } + + public get frameThis(): Crdp.Runtime.RemoteObject { + return this.unmappedCallFrame.frameThis; + } + + public get returnValue(): Crdp.Runtime.RemoteObject { + return this.unmappedCallFrame.returnValue; + } + + constructor( + public readonly unmappedCallFrame: ICallFrame, + public readonly codeFlow: CodeFlowFrame) { + super(); + } +} diff --git a/src/chrome/internal/stackTraces/callFrameName.ts b/src/chrome/internal/stackTraces/callFrameName.ts new file mode 100644 index 000000000..702a3f6a0 --- /dev/null +++ b/src/chrome/internal/stackTraces/callFrameName.ts @@ -0,0 +1,31 @@ +import { IScript } from '../scripts/script'; + +export interface ICallFrameName { + readonly name: string; +} + +export class NamedFunctionCallFrameName implements ICallFrameName { + constructor(public readonly name: string) { } +} + +export class UnamedFunctionInEvalScriptCallFrameName implements ICallFrameName { + public readonly name = '(eval code)'; +} + +export class UnamedFunctionInFileCallFrameName implements ICallFrameName { + public readonly name = '(anonymous function)'; +} + +export class FormattedName implements ICallFrameName { + constructor(public readonly name: string) { } +} + +export function createCallFrameName(script: IScript, functionName: string) { + if (functionName) { + return new NamedFunctionCallFrameName(functionName); + } else if (script.runtimeSource.doesScriptHasUrl()) { + return new UnamedFunctionInFileCallFrameName(); + } else { + return new UnamedFunctionInEvalScriptCallFrameName(); + } +} diff --git a/src/chrome/internal/stackTraces/callFramePresentation.ts b/src/chrome/internal/stackTraces/callFramePresentation.ts new file mode 100644 index 000000000..7a49f52f9 --- /dev/null +++ b/src/chrome/internal/stackTraces/callFramePresentation.ts @@ -0,0 +1,86 @@ +import { Location } from '../locations/location'; + +import { ILoadedSource } from '../sources/loadedSource'; + +import { CodeFlowFrame, ICallFrame, ScriptOrLoadedSource } from './callFrame'; + +import { CodeFlowFramePresentationRow } from './stackTracePresentation'; + +export type SourcePresentationHint = 'normal' | 'emphasize' | 'deemphasize'; +export type CallFramePresentationHint = 'normal' | 'label' | 'subtle'; + +export interface ICallFramePresentationDetails { + readonly additionalSourceOrigins: string[]; + readonly sourcePresentationHint: SourcePresentationHint; +} + +export interface ICodeFlowFramePresentation extends CodeFlowFramePresentationRow { + readonly name: string; + readonly source: ILoadedSource; + readonly location: Location; + readonly lineNumber: number; + readonly columnNumber: number; +} + +export abstract class CodeFlowFramePresentationCommonLogic implements ICodeFlowFramePresentation { + public abstract get codeFlow(): CodeFlowFrame; + public abstract hasCallFrame(): this is CallFramePresentation; + + public get name(): string { + return this.codeFlow.name; + } + + public get source(): ILoadedSource { + return this.codeFlow.source; + } + + public get location(): Location { + return this.codeFlow.location; + } + + public get lineNumber(): number { + return this.codeFlow.lineNumber; + } + + public get columnNumber(): number { + return this.codeFlow.columnNumber; + } + + public hasCodeFlow(): this is ICodeFlowFramePresentation { + return true; + } + + constructor( + public readonly additionalPresentationDetails?: ICallFramePresentationDetails, + public readonly presentationHint?: CallFramePresentationHint) { } +} + +export class CallFramePresentation extends CodeFlowFramePresentationCommonLogic implements CodeFlowFramePresentationRow { + public get codeFlow(): CodeFlowFrame { + return this.callFrame.codeFlow; + } + + public hasCallFrame(): this is CallFramePresentation { + return true; + } + + constructor( + public readonly callFrame: ICallFrame, + additionalPresentationDetails?: ICallFramePresentationDetails, + presentationHint?: CallFramePresentationHint) { + super(additionalPresentationDetails, presentationHint); + } +} + +export class CodeFlowFramePresentation extends CodeFlowFramePresentationCommonLogic implements CodeFlowFramePresentationRow { + public hasCallFrame(): this is CallFramePresentation { + return false; + } + + constructor( + public readonly codeFlow: CodeFlowFrame, + additionalPresentationDetails?: ICallFramePresentationDetails, + presentationHint?: CallFramePresentationHint) { + super(additionalPresentationDetails, presentationHint); + } +} diff --git a/src/chrome/internal/stackTraces/scopes.ts b/src/chrome/internal/stackTraces/scopes.ts new file mode 100644 index 000000000..01313357d --- /dev/null +++ b/src/chrome/internal/stackTraces/scopes.ts @@ -0,0 +1,11 @@ +import { LocationInScript } from '../locations/location'; +import { Crdp } from '../../..'; + +export class Scope { + constructor( + public readonly type: ('global' | 'local' | 'with' | 'closure' | 'catch' | 'block' | 'script' | 'eval' | 'module'), + public readonly object: Crdp.Runtime.RemoteObject, + public readonly name?: string, + public readonly startLocation?: LocationInScript, + public readonly endLocation?: LocationInScript) { } +} diff --git a/src/chrome/internal/stackTraces/stackTrace.ts b/src/chrome/internal/stackTraces/stackTrace.ts new file mode 100644 index 000000000..c6bc1ad6f --- /dev/null +++ b/src/chrome/internal/stackTraces/stackTrace.ts @@ -0,0 +1,8 @@ +import { CodeFlowFrame, ScriptOrLoadedSource } from './callFrame'; + +export class CodeFlowStackTrace { + constructor( + public readonly codeFlowFrames: CodeFlowFrame[], + public readonly description?: string, + public readonly parent?: CodeFlowStackTrace) { } +} diff --git a/src/chrome/internal/stackTraces/stackTracePresentation.ts b/src/chrome/internal/stackTraces/stackTracePresentation.ts new file mode 100644 index 000000000..7617839d6 --- /dev/null +++ b/src/chrome/internal/stackTraces/stackTracePresentation.ts @@ -0,0 +1,27 @@ +import { ILoadedSource } from '../sources/loadedSource'; +import { ICodeFlowFramePresentation, CodeFlowFramePresentation, CallFramePresentation } from './callFramePresentation'; +import { ScriptOrLoadedSource } from './callFrame'; + +export interface CodeFlowFramePresentationRow { + hasCodeFlow(): this is ICodeFlowFramePresentation; + hasCallFrame(): this is CallFramePresentation; +} + +export class StackTraceLabel implements CodeFlowFramePresentationRow { + public hasCallFrame(): this is CallFramePresentation { + return false; + } + + public hasCodeFlow(): this is ICodeFlowFramePresentation { + return false; + } + + constructor(public readonly description: string) { } +} + +export type FramePresentationOrLabel = CodeFlowFramePresentation | CallFramePresentation | StackTraceLabel; + +export interface StackTracePresentation { + readonly stackFrames: FramePresentationOrLabel[]; + readonly totalFrames?: number; +} diff --git a/src/chrome/internal/stackTraces/stackTracesLogic.ts b/src/chrome/internal/stackTraces/stackTracesLogic.ts new file mode 100644 index 000000000..b3f469f8e --- /dev/null +++ b/src/chrome/internal/stackTraces/stackTracesLogic.ts @@ -0,0 +1,164 @@ +import { DebugProtocol } from 'vscode-debugprotocol'; +import { injectable, inject } from 'inversify'; + +import * as errors from '../../../errors'; +import * as path from 'path'; + +import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); +import { PausedEvent } from '../../target/events'; +import { StackTracePresentation, FramePresentationOrLabel, StackTraceLabel } from './stackTracePresentation'; +import { ILoadedSource } from '../sources/loadedSource'; +import { CodeFlowStackTrace } from './stackTrace'; +import { IScript } from '../scripts/script'; +import { CodeFlowFrame, ICallFrame, ScriptCallFrame, LoadedSourceCallFrame } from './callFrame'; +import { LocationInLoadedSource } from '../locations/location'; +import { CallFramePresentation, CallFramePresentationHint, SourcePresentationHint, ICallFramePresentationDetails } from './callFramePresentation'; +import { FormattedName } from './callFrameName'; +import { IComponent, ComponentConfiguration } from '../features/feature'; +import { InformationAboutPausedProvider } from '../features/takeProperActionOnPausedEvent'; +import { asyncMap } from '../../collections/async'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { IAsyncDebuggingConfiguration } from '../../target/cdtpDebugger'; +import { ConnectedCDAConfiguration } from '../../..'; +import { Vote, Abstained } from '../../communication/collaborativeDecision'; + +export interface EventsConsumedByStackTrace { + subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; + onResumed(listener: () => void): void; +} + +export interface IStackTracePresentationLogicProvider { + getCallFrameAdditionalDetails(locationInLoadedSource: LocationInLoadedSource): ICallFramePresentationDetails[]; +} + +export interface IStackTracesConfiguration { + showAsyncStacks: boolean; +} + +@injectable() +export class StackTracesLogic implements IComponent { + public static ASYNC_CALL_STACK_DEPTH = 4; + + private _currentPauseEvent: PausedEvent | null = null; + + public onResumed(): any { + this._currentPauseEvent = null; + } + + public async onPaused(pausedEvent: PausedEvent): Promise> { + this._currentPauseEvent = pausedEvent; + return new Abstained(this); + } + + public async stackTrace(args: DebugProtocol.StackTraceArguments): Promise { + if (!this._currentPauseEvent) { + return Promise.reject(errors.noCallStackAvailable()); + } + + const syncFames: FramePresentationOrLabel[] = await asyncMap(this._currentPauseEvent.callFrames, frame => this.toPresentation(frame, args.format)); + const asyncStackTrace = this._currentPauseEvent.asyncStackTrace; + let stackFrames = asyncStackTrace ? syncFames.concat(await this.asyncCallFrames(asyncStackTrace, args.format)) : syncFames; + + const totalFrames = stackFrames.length; + if (typeof args.startFrame === 'number') { + stackFrames = stackFrames.slice(args.startFrame); + } + + if (typeof args.levels === 'number') { + stackFrames = stackFrames.slice(0, args.levels); + } + + const stackTraceResponse: StackTracePresentation = { + stackFrames, + totalFrames + }; + + return stackTraceResponse; + } + + private async asyncCallFrames(stackTrace: CodeFlowStackTrace, formatArgs?: DebugProtocol.StackFrameFormat): Promise[]> { + const asyncFrames: FramePresentationOrLabel[] = await asyncMap(stackTrace.codeFlowFrames, + frame => this.toPresentation(this.codeFlowToCallFrame(frame), formatArgs)); + + asyncFrames.unshift(new StackTraceLabel(stackTrace.description)); + + return asyncFrames.concat(stackTrace.parent ? await this.asyncCallFrames(stackTrace.parent, formatArgs) : []); + } + + private codeFlowToCallFrame(frame: CodeFlowFrame): ICallFrame { + return new ScriptCallFrame(frame, [], undefined, undefined); + } + + private formatStackFrameName(name: string, locationInLoadedSource: LocationInLoadedSource, formatArgs?: DebugProtocol.StackFrameFormat): string { + let formattedName = name; + if (formatArgs) { + if (formatArgs.module) { + formattedName += ` [${path.basename(locationInLoadedSource.source.identifier.textRepresentation)}]`; + } + + if (formatArgs.line) { + formattedName += ` Line ${locationInLoadedSource.lineNumber}`; + } + } + + return formattedName; + } + + private async toPresentation(frame: ICallFrame, formatArgs?: DebugProtocol.StackFrameFormat): Promise> { + // DIEGO TODO: Make getReadonlyOrigin work again + // this.getReadonlyOrigin(frame.location.script.runtimeSource.identifier.textRepresentation) + const locationInLoadedSource = frame.location.mappedToSource(); + + let presentationHint: CallFramePresentationHint = 'normal'; + + // Apply hints to skipped frames + const getSkipReason = (reason: string) => localize('skipReason', "(skipped by '{0}')", reason); + const providedDetails: ICallFramePresentationDetails[] = [].concat(await asyncMap([this._stackTracePresentationLogicProviders], provider => + provider.getCallFrameAdditionalDetails(locationInLoadedSource))); + const actualDetails = providedDetails.length === 0 + ? [{ + additionalSourceOrigins: [] as string[], + sourcePresentationHint: 'normal' as SourcePresentationHint + }] + : providedDetails; // Here we guarantee that actualDetails.length > 0 + const allAdditionalSourceOrigins = await asyncMap(actualDetails, detail => detail.additionalSourceOrigins); + + const presentationDetails: ICallFramePresentationDetails = { + additionalSourceOrigins: [getSkipReason(allAdditionalSourceOrigins.join(','))], + sourcePresentationHint: actualDetails[0].sourcePresentationHint // We know that actualDetails.length > 0 + }; + + const formattedName = this.formatStackFrameName(frame.name, locationInLoadedSource, formatArgs); + const codeFlow = new CodeFlowFrame(frame.index, new FormattedName(formattedName), locationInLoadedSource); + const callFrame = new LoadedSourceCallFrame(frame, codeFlow); + + return new CallFramePresentation(callFrame, presentationDetails, presentationHint); + } + + public async install(): Promise { + this._dependencies.subscriberForAskForInformationAboutPaused(params => this.onPaused(params)); + this._dependencies.onResumed(() => this.onResumed()); + return await this.configure(this._configuration); + } + + private async configure(configuration: ComponentConfiguration): Promise { + const showAsyncStacks = typeof configuration.args.showAsyncStacks === 'undefined' || configuration.args.showAsyncStacks; + const maxDepth = showAsyncStacks ? StackTracesLogic.ASYNC_CALL_STACK_DEPTH : 0; + + try { + await this._breakpointFeaturesSupport.setAsyncCallStackDepth(maxDepth); + } catch (e) { + // Not supported by older runtimes, ignore it. + } + return this; + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByStackTrace, + // TODO DIEGO: @multiInject(new LazyServiceIdentifer(() => TYPES.IStackTracePresentationLogicProvider)) private readonly _stackTracePresentationLogicProviders: IStackTracePresentationLogicProvider[], + @inject(TYPES.IStackTracePresentationLogicProvider) private readonly _stackTracePresentationLogicProviders: IStackTracePresentationLogicProvider, + @inject(TYPES.IAsyncDebuggingConfiguration) private readonly _breakpointFeaturesSupport: IAsyncDebuggingConfiguration, + @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration) { + } +} \ No newline at end of file diff --git a/src/chrome/internal/stepping/features/asyncStepping.ts b/src/chrome/internal/stepping/features/asyncStepping.ts new file mode 100644 index 000000000..2745a712b --- /dev/null +++ b/src/chrome/internal/stepping/features/asyncStepping.ts @@ -0,0 +1,40 @@ +import { IComponent } from '../../features/feature'; +import { PausedEvent } from '../../../target/events'; +import { InformationAboutPausedProvider, ResumeCommonLogic } from '../../features/takeProperActionOnPausedEvent'; +import { VoteRelevance, Vote, Abstained } from '../../../communication/collaborativeDecision'; +import { injectable, inject } from 'inversify'; +import { IDebugeeExecutionControl, IDebugeeStepping } from '../../../target/controlDebugeeExecution'; +import { TYPES } from '../../../dependencyInjection.ts/types'; + +export interface EventsConsumedByAsyncStepping { + subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; +} + +export class PausedBecauseAsyncCallWasScheduled extends ResumeCommonLogic { + public readonly relevance = VoteRelevance.FallbackVote; + + constructor(protected _debugeeExecutionControl: IDebugeeExecutionControl) { + super(); + } +} + +@injectable() +export class AsyncStepping implements IComponent { + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + if (paused.asyncCallStackTraceId) { + await this._debugeeStepping.pauseOnAsyncCall({ parentStackTraceId: paused.asyncCallStackTraceId }); + return new PausedBecauseAsyncCallWasScheduled(this._debugeeExecutionControl); + } + + return new Abstained(this); + } + + public install(): void { + this._dependencies.subscriberForAskForInformationAboutPaused(paused => this.askForInformationAboutPaused(paused)); + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByAsyncStepping, + @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionControl, + @inject(TYPES.IDebugeeStepping) private readonly _debugeeStepping: IDebugeeStepping) { } +} \ No newline at end of file diff --git a/src/chrome/internal/stepping/features/syncStepping.ts b/src/chrome/internal/stepping/features/syncStepping.ts new file mode 100644 index 000000000..2d06e6b3f --- /dev/null +++ b/src/chrome/internal/stepping/features/syncStepping.ts @@ -0,0 +1,77 @@ +import { ICallFrame } from '../../stackTraces/callFrame'; + +import { IScript } from '../../scripts/script'; +import { InformationAboutPausedProvider, } from '../../features/takeProperActionOnPausedEvent'; +import { IComponent } from '../../features/feature'; +import { PausedEvent } from '../../../target/events'; +import { Abstained, Vote } from '../../../communication/collaborativeDecision'; +import { injectable, inject } from 'inversify'; +import { IDebugeeStepping, IDebugeeExecutionControl } from '../../../target/controlDebugeeExecution'; +import { TYPES } from '../../../dependencyInjection.ts/types'; + +type SteppingAction = () => Promise; + +interface SyncSteppingStatus { + startStepping(): SyncSteppingStatus; +} + +class CurrentlyStepping implements SyncSteppingStatus { + public startStepping(): SyncSteppingStatus { + throw new Error('Cannot start stepping again while the program is already stepping'); + } + +} + +class CurrentlyIdle implements SyncSteppingStatus { + public startStepping(): SyncSteppingStatus { + return new CurrentlyStepping(); + } +} + +export interface SyncSteppingDependencies { + subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; +} + +@injectable() +export class SyncStepping implements IComponent { + private _status: SyncSteppingStatus = new CurrentlyIdle(); + + public stepOver = this.createSteppingMethod(() => this._debugeeStepping.stepOver()); + public stepInto = this.createSteppingMethod(() => this._debugeeStepping.stepInto({ breakOnAsyncCall: true })); + public stepOut = this.createSteppingMethod(() => this._debugeeStepping.stepOut()); + + public continue(): Promise { + return this._debugeeExecutionControl.resume(); + } + + public pause(): Promise { + return this._debugeeExecutionControl.pause(); + } + + private async askForInformationAboutPaused(_paused: PausedEvent): Promise> { + return new Abstained(this); + } + + public async restartFrame(callFrame: ICallFrame): Promise { + this._status = this._status.startStepping(); + await this._debugeeStepping.restartFrame(callFrame); + await this._debugeeStepping.stepInto({ breakOnAsyncCall: true }); + } + + private createSteppingMethod(steppingAction: SteppingAction): (() => Promise) { + return async () => { + this._status = this._status.startStepping(); + await steppingAction(); + this._status = new CurrentlyIdle(); + }; + } + + public install(): void { + this._dependencies.subscriberForAskForInformationAboutPaused(paused => this.askForInformationAboutPaused(paused)); + } + + constructor( + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: SyncSteppingDependencies, + @inject(TYPES.IDebugeeStepping) private readonly _debugeeStepping: IDebugeeStepping, + @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionControl) { } +} \ No newline at end of file diff --git a/src/chrome/internal/stepping/stepping.ts b/src/chrome/internal/stepping/stepping.ts new file mode 100644 index 000000000..579c77429 --- /dev/null +++ b/src/chrome/internal/stepping/stepping.ts @@ -0,0 +1,44 @@ +import { IComponent } from '../features/feature'; +import { AsyncStepping } from './features/asyncStepping'; +import { SyncStepping } from './features/syncStepping'; +import { ICallFrame } from '../stackTraces/callFrame'; +import { IScript } from '../scripts/script'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; + +@injectable() +export class Stepping implements IComponent { + public continue(): Promise { + return this._syncStepping.continue(); + } + + public next(): Promise { + return this._syncStepping.stepOver(); + } + + public stepIn(): Promise { + return this._syncStepping.stepInto(); + } + + public stepOut(): Promise { + return this._syncStepping.stepOut(); + } + + public pause(): Promise { + return this._syncStepping.pause(); + } + + public restartFrame(callFrame: ICallFrame): Promise { + return this._syncStepping.restartFrame(callFrame); + } + + public install(): this { + this._asyncStepping.install(); + return this; + } + + constructor( + @inject(TYPES.SyncStepping) private readonly _syncStepping: SyncStepping, + @inject(TYPES.AsyncStepping) private readonly _asyncStepping: AsyncStepping + ) { } +} \ No newline at end of file diff --git a/src/chrome/internalSourceBreakpoint.ts b/src/chrome/internalSourceBreakpoint.ts index ba42322b1..beb252b26 100644 --- a/src/chrome/internalSourceBreakpoint.ts +++ b/src/chrome/internalSourceBreakpoint.ts @@ -2,8 +2,10 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { Protocol as Crdp } from 'devtools-protocol'; import { DebugProtocol } from 'vscode-debugprotocol'; +import { IScript } from './internal/scripts/script'; +import { CodeFlowStackTrace } from './internal/stackTraces/stackTrace'; +import { parseResourceIdentifier } from './internal/sources/resourceIdentifier'; export class InternalSourceBreakpoint { static readonly LOGPOINT_URL = 'vscode.logpoint.js'; @@ -29,15 +31,15 @@ export class InternalSourceBreakpoint { } } -function isLogpointStack(stackTrace: Crdp.Runtime.StackTrace | null): boolean { - return stackTrace && stackTrace.callFrames.length > 0 && stackTrace.callFrames[0].url === InternalSourceBreakpoint.LOGPOINT_URL; +function isLogpointStack(stackTrace: CodeFlowStackTrace | null): boolean { + return stackTrace && stackTrace.codeFlowFrames.length > 0 && stackTrace.codeFlowFrames[0].script.runtimeSource.identifier.isEquivalent(parseResourceIdentifier(InternalSourceBreakpoint.LOGPOINT_URL)); } -export function stackTraceWithoutLogpointFrame(stackTrace: Crdp.Runtime.StackTrace): Crdp.Runtime.StackTrace { +export function stackTraceWithoutLogpointFrame(stackTrace: CodeFlowStackTrace): CodeFlowStackTrace { if (isLogpointStack(stackTrace)) { return { ...stackTrace, - callFrames: stackTrace.callFrames.slice(1) + codeFlowFrames: stackTrace.codeFlowFrames.slice(1) }; } @@ -50,7 +52,7 @@ function logMessageToExpression(msg: string): string { msg = msg.replace('%', '%%'); const args: string[] = []; - let format = msg.replace(LOGMESSAGE_VARIABLE_REGEXP, (match, group) => { + let format = msg.replace(LOGMESSAGE_VARIABLE_REGEXP, (_match, group) => { const a = group.trim(); if (a) { args.push(`(${a})`); diff --git a/src/chrome/logging/executionLogger.ts b/src/chrome/logging/executionLogger.ts new file mode 100644 index 000000000..fe638a56d --- /dev/null +++ b/src/chrome/logging/executionLogger.ts @@ -0,0 +1,43 @@ +import { PromiseOrNot } from '../utils/promises'; +import { Logging } from '../internal/services/logging'; + +export interface IExecutionLogger { + logAsyncFunctionCall(description: string, functionToCall: (parameters: T) => PromiseOrNot, parameters: T): PromiseOrNot; +} + +export class ExecutionLogger implements IExecutionLogger { + private _depth = 0; + + public async logAsyncFunctionCall(description: string, functionToCall: (parameters: T) => PromiseOrNot, parameters: T): Promise { + this._logging.verbose(`${this.indentationForDepth()}${description}(${this.printParameters(parameters)})`); + this._depth++; + try { + const result = await functionToCall(parameters); + this._depth--; + this._logging.verbose(`${this.indentationForDepth()}${description} = ${this.printResult(result)}`); + return result; + } catch (exception) { + this._depth--; + this._logging.verbose(`${this.indentationForDepth()}${description} throws ${this.printException(exception)}`); + throw exception; + } + } + + private indentationForDepth(): string { + return ' '.repeat(this._depth); + } + + private printParameters(parameters: T): string { + return `${parameters}`; + } + + private printResult(parameters: T): string { + return `${parameters}`; + } + + private printException(exception: unknown): string { + return `${exception}`; + } + + constructor(private readonly _logging: Logging) { } +} \ No newline at end of file diff --git a/src/chrome/logging/methodsCalledLogger.ts b/src/chrome/logging/methodsCalledLogger.ts new file mode 100644 index 000000000..00cafb2d6 --- /dev/null +++ b/src/chrome/logging/methodsCalledLogger.ts @@ -0,0 +1,70 @@ +enum Synchronicity { + Sync, + Async +} + +enum Outcome { + Succesful, + Failure +} + +export class MethodsCalledLogger { + public wrapped(): T { + const handler = { + get: (target: T, propertyKey: K, _receiver: any) => { + const originalPropertyValue = target[propertyKey]; + if (typeof originalPropertyValue === 'function') { + return (...args: any) => { + try { + const result = originalPropertyValue.apply(target, args); + if (!result.then) { + this.logCall(propertyKey, Synchronicity.Sync, args, Outcome.Succesful, result); + } else { + return result.then((promiseResult: unknown) => { + this.logCall(propertyKey, Synchronicity.Async, args, Outcome.Succesful, promiseResult); + return promiseResult; + }, (rejection: unknown) => { + this.logCall(propertyKey, Synchronicity.Async, args, Outcome.Failure, rejection); + return rejection; + }); + } + } catch (exception) { + this.logCall(propertyKey, Synchronicity.Sync, args, Outcome.Failure, exception); + } + }; + } else { + return originalPropertyValue; + } + } + }; + + return new Proxy(this._objectToWrap, handler); + } + + private printMethodCall(propertyKey: PropertyKey, methodCallArguments: any[]): string { + return `${this._objectToWrapName}.${String(propertyKey)}(${this.printArguments(methodCallArguments)})`; + } + + private printMethodResponse(outcome: Outcome, resultOrException: unknown): string { + return `${outcome === Outcome.Succesful ? '->' : 'threw'} ${this.printObject(resultOrException)}`; + } + + private printMethodSynchronicity(synchronicity: Synchronicity): string { + return `${synchronicity === Synchronicity.Sync ? '' : ' async'}`; + } + + private logCall(propertyKey: PropertyKey, synchronicity: Synchronicity, methodCallArguments: any[], outcome: Outcome, resultOrException: unknown): void { + const message = `${this.printMethodCall(propertyKey, methodCallArguments)} ${this.printMethodSynchronicity(synchronicity)} ${this.printMethodResponse(outcome, resultOrException)}`; + console.log(message); + } + + private printArguments(methodCallArguments: any[]): string { + return methodCallArguments.map(methodCallArgument => this.printObject(methodCallArgument)).join(', '); + } + + private printObject(objectToPrint: unknown): string { + return `${objectToPrint}`; + } + + constructor(private readonly _objectToWrap: T, private readonly _objectToWrapName: string) { } +} diff --git a/src/chrome/target/addSourceUriToExpression.ts b/src/chrome/target/addSourceUriToExpression.ts new file mode 100644 index 000000000..35b537472 --- /dev/null +++ b/src/chrome/target/addSourceUriToExpression.ts @@ -0,0 +1,15 @@ +export class AddSourceUriToExpession { + private nextEvaluateScriptId = 0; + + public addURLIfMissing(expression: string): string { + const sourceUrlPrefix = '\n//# sourceURL='; + + if (expression.indexOf(sourceUrlPrefix) < 0) { + expression += `${sourceUrlPrefix}/${this._prefix}/id=${this.nextEvaluateScriptId++}`; + } + + return expression; + } + + constructor(private readonly _prefix: string) {} +} \ No newline at end of file diff --git a/src/chrome/target/breakpointFeaturesSupport.ts b/src/chrome/target/breakpointFeaturesSupport.ts new file mode 100644 index 000000000..5d976b8dd --- /dev/null +++ b/src/chrome/target/breakpointFeaturesSupport.ts @@ -0,0 +1,34 @@ +import { Crdp, utils } from '../..'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; + +export interface IBreakpointFeaturesSupport { + supportsColumnBreakpoints: Promise; +} + +@injectable() +export class BreakpointFeaturesSupport implements IBreakpointFeaturesSupport { + private result = utils.promiseDefer(); + + public supportsColumnBreakpoints = this.result.promise; + + private async onScriptParsed(params: Crdp.Debugger.ScriptParsedEvent): Promise { + const scriptId = params.scriptId; + + try { + await this.api.Debugger.getPossibleBreakpoints({ + start: { scriptId, lineNumber: 0, columnNumber: 0 }, + end: { scriptId, lineNumber: 1, columnNumber: 0 }, + restrictToFunction: false + }); + this.result.resolve(true); + } catch (e) { + this.result.resolve(false); + } + } + + constructor( + @inject(TYPES.CDTPClient) protected readonly api: Crdp.ProtocolApi) { + api.Debugger.on('scriptParsed', params => this.onScriptParsed(params)); + } +} \ No newline at end of file diff --git a/src/chrome/target/breakpointIdRegistry.ts b/src/chrome/target/breakpointIdRegistry.ts new file mode 100644 index 000000000..dacc7503e --- /dev/null +++ b/src/chrome/target/breakpointIdRegistry.ts @@ -0,0 +1,31 @@ +import { BidirectionalMap } from '../collections/bidirectionalMap'; +import { BPRecipie, IBPRecipie } from '../internal/breakpoints/bpRecipie'; +import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; +import { Crdp } from '../..'; +import { injectable } from 'inversify'; + +@injectable() +export class BreakpointIdRegistry { + // TODO DIEGO: Figure out how to handle if two breakpoint rules set a breakpoint in the same location so it ends up being the same breakpoint id + private readonly _recipieToBreakpointId = new BidirectionalMap, Crdp.Debugger.BreakpointId>(); + + public registerRecipie(cdtpBreakpointId: Crdp.Debugger.BreakpointId, bpRecipie: BPRecipie): void { + this._recipieToBreakpointId.set(bpRecipie.unmappedBpRecipie, cdtpBreakpointId); + } + + public unregisterRecipie(bpRecipie: BPRecipie): void { + this._recipieToBreakpointId.deleteByLeft(bpRecipie.unmappedBpRecipie); + } + + public getBreakpointId(bpRecipie: BPRecipie): Crdp.Debugger.BreakpointId { + return this._recipieToBreakpointId.getByLeft(bpRecipie); + } + + public getRecipieByBreakpointId(cdtpBreakpointId: Crdp.Debugger.BreakpointId): IBPRecipie { + return this._recipieToBreakpointId.getByRight(cdtpBreakpointId); + } + + public toString(): string { + return `Breakpoint IDs: ${this._recipieToBreakpointId}`; + } +} diff --git a/src/chrome/target/callFrameRegistry.ts b/src/chrome/target/callFrameRegistry.ts new file mode 100644 index 000000000..bf7425b5c --- /dev/null +++ b/src/chrome/target/callFrameRegistry.ts @@ -0,0 +1,14 @@ +import { IScript } from '../internal/scripts/script'; +import { Crdp } from '../..'; +import { ValidatedMap } from '../collections/validatedMap'; +import { ICallFrame, ScriptOrLoadedSource } from '../internal/stackTraces/callFrame'; +import { injectable } from 'inversify'; + +@injectable() +export class CallFrameRegistry { + private readonly _callFrameToId = new ValidatedMap, Crdp.Debugger.CallFrameId>(); + + public getFrameId(frame: ICallFrame): Crdp.Debugger.CallFrameId { + return this._callFrameToId.get(frame.unmappedCallFrame); + } +} \ No newline at end of file diff --git a/src/chrome/target/cdtpDebugger.ts b/src/chrome/target/cdtpDebugger.ts new file mode 100644 index 000000000..10c2025b0 --- /dev/null +++ b/src/chrome/target/cdtpDebugger.ts @@ -0,0 +1,65 @@ +import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; +import { Crdp } from '../..'; +import { ScriptParsedEvent } from './events'; +import { IScript } from '../internal/scripts/script'; +import { PauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions } from '../internal/exceptions/strategies'; +import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; + +export type ScriptParsedListener = (params: ScriptParsedEvent) => void; + +export interface IPauseOnExceptions { + setPauseOnExceptions(strategy: PauseOnExceptionsStrategy): Promise; +} + +export interface IAsyncDebuggingConfiguration { + setAsyncCallStackDepth(maxDepth: Crdp.integer): Promise; +} + +export interface IScriptSources { + getScriptSource(script: IScript): Promise; +} + +@injectable() +export class CDTPDebugger extends CDTPEventsEmitterDiagnosticsModule implements IPauseOnExceptions, IScriptSources, IAsyncDebuggingConfiguration { + protected readonly api = this._protocolApi.Debugger; + + public setAsyncCallStackDepth(maxDepth: Crdp.integer): Promise { + return this.api.setAsyncCallStackDepth({ maxDepth }); + } + + public setBlackboxedRanges(script: IScript, positions: Crdp.Debugger.ScriptPosition[]): Promise { + return this.api.setBlackboxedRanges({ scriptId: this._scriptsRegistry.getCrdpId(script), positions: positions }); + } + + public setBlackboxPatterns(params: Crdp.Debugger.SetBlackboxPatternsRequest): Promise { + return this.api.setBlackboxPatterns(params); + } + + public setPauseOnExceptions(strategy: PauseOnExceptionsStrategy): Promise { + let state: 'none' | 'uncaught' | 'all'; + + if (strategy instanceof PauseOnAllExceptions) { + state = 'all'; + } else if (strategy instanceof PauseOnUnhandledExceptions) { + state = 'uncaught'; + } else if (strategy instanceof DoNotPauseOnAnyExceptions) { + state = 'none'; + } else { + throw new Error(`Can't pause on exception using an unknown strategy ${strategy}`); + } + + return this.api.setPauseOnExceptions({ state }); + } + + public async getScriptSource(script: IScript): Promise { + return (await this.api.getScriptSource({ scriptId: this._scriptsRegistry.getCrdpId(script) })).scriptSource; + } + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: Crdp.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry) { + super(); + } +} diff --git a/src/chrome/target/cdtpDebuggerEventsProvider.ts b/src/chrome/target/cdtpDebuggerEventsProvider.ts new file mode 100644 index 000000000..d2d9a9ed3 --- /dev/null +++ b/src/chrome/target/cdtpDebuggerEventsProvider.ts @@ -0,0 +1,77 @@ +import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; +import { asyncMap } from '../collections/async'; +import { PausedEvent } from './events'; +import { CDTPStackTraceParser } from './cdtpStackTraceParser'; +import { adaptToSinglIntoToMulti } from '../../utils'; +import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; +import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; +import { BreakpointIdRegistry } from './breakpointIdRegistry'; +import { ScriptCallFrame, ICallFrame, CodeFlowFrame } from '../internal/stackTraces/callFrame'; +import { asyncUndefinedOnFailure } from '../utils/failures'; +import { CDTPLocationParser } from './cdtpLocationParser'; +import { Scope } from '../internal/stackTraces/scopes'; +import { IScript } from '../internal/scripts/script'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; +import { Crdp } from '../..'; + +export interface ICDTPDebuggerEventsProvider { + onPaused(listener: (event: PausedEvent) => void): void; + onResumed(listener: () => void): void; +} + +@injectable() +export class CDTPDebuggerEventsProvider extends CDTPEventsEmitterDiagnosticsModule implements ICDTPDebuggerEventsProvider { + protected readonly api = this._protocolApi.Debugger; + + private getBPsFromIDs = adaptToSinglIntoToMulti(this, this.getBPFromID); + + public readonly onPaused = this.addApiListener('paused', async (params: Crdp.Debugger.PausedEvent) => { + if (params.callFrames.length === 0) { + throw new Error(`Expected a pause event to have at least a single call frame: ${JSON.stringify(params)}`); + } + + const callFrames = await asyncMap(params.callFrames, (callFrame, index) => this.toCallFrame(index, callFrame)); + return new PausedEvent(callFrames, params.reason, params.data, + this.getBPsFromIDs(params.hitBreakpoints), + params.asyncStackTrace && await this._crdpToInternal.toStackTraceCodeFlow(params.asyncStackTrace), + params.asyncStackTraceId, params.asyncCallStackTraceId); + }); + + public readonly onResumed = this.addApiListener('resumed', (params: void) => params); + + public readonly onScriptFailedToParse = this.addApiListener('resumed', (params: Crdp.Debugger.ScriptFailedToParseEvent) => params); + + private getBPFromID(hitBreakpoint: Crdp.Debugger.BreakpointId): IBPRecipie { + return this._breakpointIdRegistry.getRecipieByBreakpointId(hitBreakpoint); + } + + private async toCallFrame(index: number, callFrame: Crdp.Debugger.CallFrame): Promise> { + return new ScriptCallFrame(await this.DebuggertoCallFrameCodeFlow(index, callFrame), + await Promise.all(callFrame.scopeChain.map(scope => this.toScope(scope))), + callFrame.this, callFrame.returnValue); + } + + private DebuggertoCallFrameCodeFlow(index: number, callFrame: Crdp.Debugger.CallFrame): Promise> { + return this._crdpToInternal.configurableToCallFrameCodeFlow(index, callFrame, callFrame.location); + } + + private async toScope(scope: Crdp.Debugger.Scope): Promise { + return { + type: scope.type, + object: scope.object, + name: scope.name, + // TODO FILE BUG: Chrome sometimes returns line -1 when the doc says it's 0 based + startLocation: await asyncUndefinedOnFailure(async () => scope.startLocation && await this._cdtpLocationParser.getPositionInScript(scope.startLocation)), + endLocation: await asyncUndefinedOnFailure(async () => scope.endLocation && await this._cdtpLocationParser.getPositionInScript(scope.endLocation)) + }; + } + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: Crdp.ProtocolApi, + @inject(TYPES.CDTPStackTraceParser) private readonly _crdpToInternal: CDTPStackTraceParser, + @inject(TYPES.CDTPLocationParser) private readonly _cdtpLocationParser: CDTPLocationParser, + @inject(TYPES.BreakpointIdRegistry) private readonly _breakpointIdRegistry: BreakpointIdRegistry) { + super(); + } +} \ No newline at end of file diff --git a/src/chrome/target/cdtpDiagnostics.ts b/src/chrome/target/cdtpDiagnostics.ts new file mode 100644 index 000000000..7e02eb7fb --- /dev/null +++ b/src/chrome/target/cdtpDiagnostics.ts @@ -0,0 +1,57 @@ +import { Crdp } from '../..'; +import { CDTPStackTraceParser } from './cdtpStackTraceParser'; +import { CDTPDebugger } from './cdtpDebugger'; +import { CDTPConsole, CDTPSchema, CDTPDOMDebugger, CDTPPage, CDTPNetwork, CDTPBrowser, CDTPOverlay, CDTPLog } from './cdtpSmallerModules'; +import { CDTPRuntime } from './cdtpRuntime'; +import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; +import { injectable, inject } from 'inversify'; +import { IComponent } from '../internal/features/feature'; +import { CDTPDebuggerEventsProvider } from './cdtpDebuggerEventsProvider'; +import { CDTPLocationParser } from './cdtpLocationParser'; +import { ExceptionThrownEventProvider } from './exceptionThrownEventProvider'; +import { TYPES } from '../dependencyInjection.ts/types'; + +// TODO: Remove this class and use dependency injection/inversify to initialize all this +@injectable() +export class CDTPDiagnostics implements IComponent { + public Debugger: CDTPDebugger; + public ExceptionThrownEventProvider: ExceptionThrownEventProvider; + public Console: CDTPConsole; + public Runtime: CDTPRuntime; + public Schema: CDTPSchema; + public DOMDebugger: CDTPDOMDebugger; + public Page: CDTPPage; + public Network: CDTPNetwork; + public Browser: CDTPBrowser; + public Overlay: CDTPOverlay; + public Log: CDTPLog; + + public async install(): Promise { + // Enable domains so we can use the handlers + await Promise.all([ + this.Debugger.enable(), + this.Runtime.enable().then(() => this.Runtime.runIfWaitingForDebugger()), + this.Log.enable().catch(_exception => { }) // Not supported by all runtimes + ]); + } + + constructor( + @inject(TYPES.CDTPClient) private _api: Crdp.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) protected scriptsRegistry: CDTPScriptsRegistry, + @inject(TYPES.CDTPLocationParser) protected cdtpLocationParser: CDTPLocationParser, + @inject(TYPES.CDTPStackTraceParser) protected cdtpStackTraceParser: CDTPStackTraceParser, + @inject(TYPES.ICDTPDebuggerEventsProvider) public debuggerEvents: CDTPDebuggerEventsProvider, + ) { + this.Debugger = new CDTPDebugger(this._api, scriptsRegistry); + this.ExceptionThrownEventProvider = new ExceptionThrownEventProvider(this._api, cdtpStackTraceParser, scriptsRegistry); + this.Console = new CDTPConsole(this._api.Console); + this.Runtime = new CDTPRuntime(this._api.Runtime, cdtpStackTraceParser); + this.Schema = new CDTPSchema(this._api.Schema); + this.DOMDebugger = new CDTPDOMDebugger(this._api); + this.Page = new CDTPPage(this._api); + this.Network = new CDTPNetwork(this._api.Network); + this.Browser = new CDTPBrowser(this._api); + this.Overlay = new CDTPOverlay(this._api.Overlay); + this.Log = new CDTPLog(this._api.Log, cdtpStackTraceParser); + } +} diff --git a/src/chrome/target/cdtpDiagnosticsModule.ts b/src/chrome/target/cdtpDiagnosticsModule.ts new file mode 100644 index 000000000..32e26e7a6 --- /dev/null +++ b/src/chrome/target/cdtpDiagnosticsModule.ts @@ -0,0 +1,34 @@ +import { TransformedListenerRegistry } from '../communication/transformedListenerRegistry'; +import { PromiseOrNot } from '../utils/promises'; +import { injectable } from 'inversify'; + +export interface IEnableableApi { + enable(parameters: EnableParameters): Promise; +} + +@injectable() +export abstract class CDTPEnableableDiagnosticsModule, EnableParameters = void, EnableResponse = void> { + protected abstract get api(): T; + + // TODO DIEGO IMPORTANT: Figure out how to ensure that the Enable messages get sent after we declare or the event subscribers. They also need to follow the dependencies order + public enable(): EnableParameters extends void ? Promise : never; + public enable(parameters: EnableParameters): Promise; + public async enable(parameters?: EnableParameters): Promise { + return await this.api.enable(parameters); + } +} + +@injectable() +export abstract class CDTPEventsEmitterDiagnosticsModule, EnableParameters = void, EnableResponse = void> + extends CDTPEnableableDiagnosticsModule { + public addApiListener(eventName: string, transformation: (params: O) => PromiseOrNot): (transformedListener: ((params: T) => void)) => void { + /** + * We don't want the constructor of the subclass to be async (It's also not allowed). We want the onScriptParsed() method to wait on enabling the domain before setting the handler if neccesary + * so we store the TransformedListenerRegistry as a promise. + */ + const transformedListenerRegistryPromise = new TransformedListenerRegistry(this.constructor.name, async originalListener => { + this.api.on(eventName, originalListener); + }, transformation).install(); + return async transformedListener => (await transformedListenerRegistryPromise).registerListener(transformedListener); + } +} \ No newline at end of file diff --git a/src/chrome/target/cdtpLocationParser.ts b/src/chrome/target/cdtpLocationParser.ts new file mode 100644 index 000000000..9bce12208 --- /dev/null +++ b/src/chrome/target/cdtpLocationParser.ts @@ -0,0 +1,32 @@ +import { Coordinates, LocationInScript } from '../internal/locations/location'; +import { createColumnNumber, createLineNumber } from '../internal/locations/subtypes'; +import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; +import { Crdp } from '../..'; + +interface HasLocation { + lineNumber: number; + columnNumber?: number; +} + +interface HasScript { + scriptId: Crdp.Runtime.ScriptId; +} + +export interface HasScriptLocation extends HasLocation, HasScript { } + +@injectable() +export class CDTPLocationParser { + public async getPositionInScript(crdpScriptLocation: HasScriptLocation): Promise { + return new LocationInScript(await this._scriptsRegistry.getScriptById(crdpScriptLocation.scriptId), + this.getLocation(crdpScriptLocation)); + } + + private getLocation(crdpLocation: HasLocation): Coordinates { + return new Coordinates(createLineNumber(crdpLocation.lineNumber), createColumnNumber(crdpLocation.columnNumber)); + } + + constructor( + @inject(TYPES.CDTPScriptsRegistry) private _scriptsRegistry: CDTPScriptsRegistry) { } +} diff --git a/src/chrome/target/cdtpOnScriptParsedEventProvider.ts b/src/chrome/target/cdtpOnScriptParsedEventProvider.ts new file mode 100644 index 000000000..89de911aa --- /dev/null +++ b/src/chrome/target/cdtpOnScriptParsedEventProvider.ts @@ -0,0 +1,85 @@ +import { Crdp, parseResourceIdentifier, BasePathTransformer, BaseSourceMapTransformer } from '../..'; +import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; +import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; +import { IScript, Script } from '../internal/scripts/script'; +import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; +import { SourcesMapper, NoSourceMapping } from '../internal/scripts/sourcesMapper'; +import { ResourceName } from '../internal/sources/resourceIdentifier'; +import { ScriptParsedEvent } from './events'; +import { TYPES } from '../dependencyInjection.ts/types'; +import { CDTPStackTraceParser } from './cdtpStackTraceParser'; +import { inject } from 'inversify'; + +export interface IScriptParsedProvider { + onScriptParsed(listener: (event: ScriptParsedEvent) => void): void; +} + +export class CDTPOnScriptParsedEventProvider extends CDTPEventsEmitterDiagnosticsModule implements IScriptParsedProvider { + protected readonly api = this._protocolApi.Debugger; + + public onScriptParsed = this.addApiListener('scriptParsed', async (params: Crdp.Debugger.ScriptParsedEvent) => { + await this.createAndRegisterScript(params); + + return await this.toScriptParsedEvent(params); + }); + + private async createAndRegisterScript(params: Crdp.Debugger.ScriptParsedEvent): Promise { + // The stack trace and hash can be large and the DA doesn't need it. + delete params.stackTrace; + delete params.hash; + + const executionContext = this._scriptsRegistry.getExecutionContextById(params.executionContextId); + + const script = await this._scriptsRegistry.registerNewScript(params.scriptId, async () => { + if (params.url !== undefined && params.url !== '') { + const runtimeSourceLocation = parseResourceIdentifier(params.url as CDTPScriptUrl); + const developmentSourceLocation = await this._pathTransformer.scriptParsed(runtimeSourceLocation); + const sourceMap = await this._sourceMapTransformer.scriptParsed(runtimeSourceLocation.canonicalized, params.sourceMapURL); + const sourceMapper = sourceMap + ? new SourcesMapper(sourceMap) + : new NoSourceMapping(); + + const runtimeScript = Script.create(executionContext, runtimeSourceLocation, developmentSourceLocation, sourceMapper); + return runtimeScript; + } else { + const sourceMap = await this._sourceMapTransformer.scriptParsed('', params.sourceMapURL); + const sourceMapper = sourceMap + ? new SourcesMapper(sourceMap) + : new NoSourceMapping(); + const runtimeScript = Script.createEval(executionContext, new ResourceName(params.scriptId as CDTPScriptUrl), sourceMapper); + return runtimeScript; + } + }); + + return script; + } + + private async toScriptParsedEvent(params: Crdp.Debugger.ScriptParsedEvent): Promise { + return { + script: await this._scriptsRegistry.getScriptById(params.scriptId), + url: params.url, + startLine: params.startLine, + startColumn: params.startColumn, + endLine: params.endLine, + endColumn: params.endColumn, + executionContextId: params.executionContextId, + hash: params.hash, + executionContextAuxData: params.executionContextAuxData, + isLiveEdit: params.isLiveEdit, + sourceMapURL: params.sourceMapURL, + hasSourceURL: params.hasSourceURL, + isModule: params.isModule, + length: params.length, + stackTrace: params.stackTrace && await this._crdpToInternal.toStackTraceCodeFlow(params.stackTrace) + }; + } + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: Crdp.ProtocolApi, + @inject(TYPES.CDTPStackTraceParser) private readonly _crdpToInternal: CDTPStackTraceParser, + @inject(TYPES.BasePathTransformer) private readonly _pathTransformer: BasePathTransformer, + @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, + @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry) { + super(); + } +} \ No newline at end of file diff --git a/src/chrome/target/cdtpRuntime.ts b/src/chrome/target/cdtpRuntime.ts new file mode 100644 index 000000000..e8ef6b61d --- /dev/null +++ b/src/chrome/target/cdtpRuntime.ts @@ -0,0 +1,32 @@ +import { Crdp } from '../..'; +import { CDTPEventsEmitterDiagnosticsModule, IEnableableApi } from './cdtpDiagnosticsModule'; +import { CDTPStackTraceParser } from './cdtpStackTraceParser'; + +export interface ICDTPRuntime extends IEnableableApi {} + +export class CDTPRuntime extends CDTPEventsEmitterDiagnosticsModule implements ICDTPRuntime { + public readonly onConsoleAPICalled = this.addApiListener('consoleAPICalled', async (params: Crdp.Runtime.ConsoleAPICalledEvent) => + ({ + args: params.args, context: params.context, executionContextId: params.executionContextId, + stackTrace: params.stackTrace && await this._crdpToInternal.toStackTraceCodeFlow(params.stackTrace), timestamp: params.timestamp, type: params.type + })); + + public async runIfWaitingForDebugger(): Promise { + // This is a CDP version difference which will have to be handled more elegantly with others later... + // For now, we need to send both messages and ignore a failing one. + try { + await Promise.all([ + this.api.runIfWaitingForDebugger(), + (this.api as any).run() + ]); + } catch (exception) { + // Ignore the failed call + } + } + + constructor( + protected readonly api: Crdp.RuntimeApi, + private readonly _crdpToInternal: CDTPStackTraceParser) { + super(); + } +} diff --git a/src/chrome/target/cdtpScriptsRegistry.ts b/src/chrome/target/cdtpScriptsRegistry.ts new file mode 100644 index 000000000..0bc7b7cb8 --- /dev/null +++ b/src/chrome/target/cdtpScriptsRegistry.ts @@ -0,0 +1,103 @@ +import { Crdp } from '../..'; +import { IScript } from '../internal/scripts/script'; +import { newResourceIdentifierMap, IResourceIdentifier } from '../internal/sources/resourceIdentifier'; +import { ValidatedMap } from '../collections/validatedMap'; +import { ExecutionContext, IExecutionContext } from '../internal/scripts/executionContext'; +import { injectable } from 'inversify'; + +@injectable() +export class CDTPScriptsRegistry { + private readonly _idToExecutionContext = new ValidatedMap(); + private readonly _scripts = new CDTPCurrentGeneration(); + + public markExecutionContextAsDestroyed(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { + const executionContext = this._idToExecutionContext.get(executionContextId); + executionContext.markAsDestroyed(); + return executionContext; + } + + public registerExecutionContext(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { + const executionContext = new ExecutionContext(); + this._idToExecutionContext.set(executionContextId, executionContext); + return executionContext; + } + + public getExecutionContextById(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { + return this._idToExecutionContext.get(executionContextId); + } + + public registerNewScript(scriptId: Crdp.Runtime.ScriptId, obtainScript: () => Promise): Promise { + return this._scripts.registerNewScript(scriptId, obtainScript); + } + + public getCrdpId(script: IScript): any { + return this._scripts.getCdtpId(script); + } + + public getScriptById(runtimeScriptCrdpId: Crdp.Runtime.ScriptId): Promise { + return this._scripts.scriptById(runtimeScriptCrdpId); + } + + public getScriptsByPath(nameOrLocation: IResourceIdentifier): IScript[] { + return this._scripts.getScriptByPath(nameOrLocation); + } + + public getAllScripts(): IterableIterator> { + return this._scripts.getAllScripts(); + } + + constructor() { + } +} + +export class CDTPCurrentGeneration { + private readonly _cdtpIdByScript = new ValidatedMap>(); + private readonly _scriptByCdtpId = new ValidatedMap(); + private readonly _scriptByPath = newResourceIdentifierMap(); + + private createScriptInitialConfiguration(scriptId: Crdp.Runtime.ScriptId, script: IScript): void { + this._scriptByCdtpId.set(script, scriptId); + + let scriptsWithSamePath = this._scriptByPath.getOrAdd(script.runtimeSource.identifier, () => []); + scriptsWithSamePath.push(script); + } + + public async registerNewScript(scriptId: Crdp.Runtime.ScriptId, obtainScript: () => Promise): Promise { + const scriptWithConfigurationPromise = obtainScript().then(script => { + /** + * We need to configure the script here, so we can guarantee that clients who try to use a script will get + * blocked until the script is created, and all the initial configuration is done, so they can use APIs to get + * the script id, search by URL, etc... + */ + this.createScriptInitialConfiguration(scriptId, script); + return script; + }); + + this._cdtpIdByScript.set(scriptId, scriptWithConfigurationPromise); + + return await scriptWithConfigurationPromise; + } + + public getCdtpId(script: IScript): Crdp.Runtime.ScriptId { + const scriptId = this._scriptByCdtpId.get(script); + + if (script === undefined) { + throw new Error(`Couldn't find a CRDP id for script ${script}`); + } + + return scriptId; + } + + public scriptById(runtimeScriptCrdpId: string): Promise { + return this._cdtpIdByScript.get(runtimeScriptCrdpId); + } + + public getScriptByPath(path: IResourceIdentifier): IScript[] { + const runtimeScript = this._scriptByPath.tryGetting(path); + return runtimeScript || []; + } + + public getAllScripts(): IterableIterator> { + return this._cdtpIdByScript.values(); + } +} diff --git a/src/chrome/target/cdtpSmallerModules.ts b/src/chrome/target/cdtpSmallerModules.ts new file mode 100644 index 000000000..14b481c9c --- /dev/null +++ b/src/chrome/target/cdtpSmallerModules.ts @@ -0,0 +1,138 @@ +import { CDTPEnableableDiagnosticsModule, CDTPEventsEmitterDiagnosticsModule, IEnableableApi } from './cdtpDiagnosticsModule'; +import { Crdp } from '../..'; +import { CDTPStackTraceParser } from './cdtpStackTraceParser'; +import { injectable, inject } from 'inversify'; +import { LogEntry } from './events'; +import { TYPES } from '../dependencyInjection.ts/types'; + +export class CDTPConsole extends CDTPEventsEmitterDiagnosticsModule { + public readonly onMessageAdded = this.addApiListener('messageAdded', (params: Crdp.Console.MessageAddedEvent) => params); + + constructor(protected api: Crdp.ConsoleApi) { + super(); + } +} + +export class CDTPSchema { + public async getDomains(): Promise { + return (await this.api.getDomains()).domains; + } + + constructor(protected api: Crdp.SchemaApi) {} +} + +export interface IDOMInstrumentationBreakpoints { + setInstrumentationBreakpoint(params: Crdp.DOMDebugger.SetInstrumentationBreakpointRequest): Promise; + removeInstrumentationBreakpoint(params: Crdp.DOMDebugger.SetInstrumentationBreakpointRequest): Promise; +} + +@injectable() +export class CDTPDOMDebugger implements IDOMInstrumentationBreakpoints { + protected api = this._protocolApi.DOMDebugger; + + public setInstrumentationBreakpoint(params: Crdp.DOMDebugger.SetInstrumentationBreakpointRequest): Promise { + return this.api.setInstrumentationBreakpoint(params); + } + + public removeInstrumentationBreakpoint(params: Crdp.DOMDebugger.SetInstrumentationBreakpointRequest): Promise { + return this.api.removeInstrumentationBreakpoint(params); + } + + constructor(@inject(TYPES.CDTPClient) protected _protocolApi: Crdp.ProtocolApi) {} +} + +export interface IBrowserNavigation extends IEnableableApi { + navigate(params: Crdp.Page.NavigateRequest): Promise; + reload(params: Crdp.Page.ReloadRequest): Promise; + onFrameNavigated(listener: (params: Crdp.Page.FrameNavigatedEvent) => void): void; +} + +@injectable() +export class CDTPPage extends CDTPEventsEmitterDiagnosticsModule implements IBrowserNavigation { + protected api = this._protocolApi.Page; + + public readonly onFrameNavigated = this.addApiListener('frameNavigated', (params: Crdp.Page.FrameNavigatedEvent) => params); + + public navigate(params: Crdp.Page.NavigateRequest): Promise { + return this.api.navigate(params); + } + + public reload(params: Crdp.Page.ReloadRequest): Promise { + return this.api.reload(params); + } + + constructor(@inject(TYPES.CDTPClient) protected _protocolApi: Crdp.ProtocolApi) { + super(); + } +} + +export interface INetworkCacheConfiguration { + setCacheDisabled(params: Crdp.Network.SetCacheDisabledRequest): Promise; +} + +export class CDTPNetwork extends CDTPEventsEmitterDiagnosticsModule implements INetworkCacheConfiguration { + public disable(): Promise { + return this.api.disable(); + } + + public setCacheDisabled(params: Crdp.Network.SetCacheDisabledRequest): Promise { + return this.api.setCacheDisabled(params); + } + + constructor(protected api: Crdp.NetworkApi) { + super(); + } +} + +export interface IDebugeeVersionProvider { + getVersion(): Promise; +} + +@injectable() +export class CDTPBrowser implements IDebugeeVersionProvider { + protected api = this._protocolApi.Browser; + + public getVersion(): Promise { + return this.api.getVersion(); + } + + constructor(@inject(TYPES.CDTPClient) protected _protocolApi: Crdp.ProtocolApi) { + } +} + +export interface IPausedOverlay { + setPausedInDebuggerMessage(params: Crdp.Overlay.SetPausedInDebuggerMessageRequest): Promise; +} + +export class CDTPOverlay extends CDTPEnableableDiagnosticsModule implements IPausedOverlay { + public setPausedInDebuggerMessage(params: Crdp.Overlay.SetPausedInDebuggerMessageRequest): Promise { + return this.api.setPausedInDebuggerMessage(params); + } + + constructor(protected api: Crdp.OverlayApi) { + super(); + } +} + +export class CDTPLog extends CDTPEventsEmitterDiagnosticsModule { + public readonly onEntryAdded = this.addApiListener('entryAdded', async (params: Crdp.Log.EntryAddedEvent) => await this.toLogEntry(params.entry)); + + private async toLogEntry(entry: Crdp.Log.LogEntry): Promise { + return { + source: entry.source, + level: entry.level, + text: entry.text, + timestamp: entry.timestamp, + url: entry.url, + lineNumber: entry.lineNumber, + stackTrace: entry.stackTrace && await this._crdpToInternal.toStackTraceCodeFlow(entry.stackTrace), + networkRequestId: entry.networkRequestId, + workerId: entry.workerId, + args: entry.args, + }; + } + + constructor(protected readonly api: Crdp.LogApi, private readonly _crdpToInternal: CDTPStackTraceParser) { + super(); + } +} diff --git a/src/chrome/target/cdtpStackTraceParser.ts b/src/chrome/target/cdtpStackTraceParser.ts new file mode 100644 index 000000000..86b69b34a --- /dev/null +++ b/src/chrome/target/cdtpStackTraceParser.ts @@ -0,0 +1,36 @@ +import { Crdp } from '../..'; +import { IScript, } from '../internal/scripts/script'; +import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; +import { CodeFlowStackTrace } from '../internal/stackTraces/stackTrace'; +import { CodeFlowFrame } from '../internal/stackTraces/callFrame'; +import { createCallFrameName } from '../internal/stackTraces/callFrameName'; +import { IResourceIdentifier } from '../internal/sources/resourceIdentifier'; +import { CDTPLocationParser, HasScriptLocation } from './cdtpLocationParser'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; +import { URLRegexp } from '../internal/locations/subtypes'; + +export type CDTPResource = IScript | URLRegexp | IResourceIdentifier; + +@injectable() +export class CDTPStackTraceParser { + public async toStackTraceCodeFlow(stackTrace: Crdp.Runtime.StackTrace): Promise> { + return { + codeFlowFrames: await Promise.all(stackTrace.callFrames.map((callFrame, index) => this.RuntimetoCallFrameCodeFlow(index, callFrame))), + description: stackTrace.description, parent: stackTrace.parent && await this.toStackTraceCodeFlow(stackTrace.parent) + }; + } + + private RuntimetoCallFrameCodeFlow(index: number, callFrame: Crdp.Runtime.CallFrame): Promise> { + return this.configurableToCallFrameCodeFlow(index, callFrame, callFrame); + } + + public async configurableToCallFrameCodeFlow(index: number, callFrame: Crdp.Runtime.CallFrame | Crdp.Debugger.CallFrame, location: HasScriptLocation): Promise> { + const scriptLocation = await this._cdtpLocationParser.getPositionInScript(location); + const name = createCallFrameName(scriptLocation.script, callFrame.functionName); + return new CodeFlowFrame(index, name, scriptLocation); + } + + constructor( + @inject(TYPES.CDTPLocationParser) private readonly _cdtpLocationParser: CDTPLocationParser) { } +} diff --git a/src/chrome/target/cdtpTargetBreakpoints.ts b/src/chrome/target/cdtpTargetBreakpoints.ts new file mode 100644 index 000000000..da2c4888c --- /dev/null +++ b/src/chrome/target/cdtpTargetBreakpoints.ts @@ -0,0 +1,137 @@ +import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp, BPRecipie, IBPRecipie } from '../internal/breakpoints/bpRecipie'; +import { AlwaysBreak, ConditionalBreak } from '../internal/breakpoints/bpActionWhenHit'; +import { BreakpointInScript, BreakpointInUrl, BreakpointInUrlRegexp, Breakpoint } from '../internal/breakpoints/breakpoint'; +import { RangeInScript } from '../internal/locations/rangeInScript'; +import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; +import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; +import { Crdp } from '../..'; +import { BreakpointIdRegistry } from './breakpointIdRegistry'; +import { TYPES } from '../dependencyInjection.ts/types'; +import { asyncMap } from '../collections/async'; +import { IScript } from '../internal/scripts/script'; +import { URL } from '../internal/sources/resourceIdentifier'; +import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; +import { CDTPLocationParser } from './cdtpLocationParser'; +import { inject, injectable } from 'inversify'; +import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; +import { URLRegexp } from '../internal/locations/subtypes'; + +export interface ITargetBreakpoints { + setBreakpoint(bpRecipie: BPRecipieInScript): Promise; + setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise; + setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise; + getPossibleBreakpoints(rangeInScript: RangeInScript): Promise; + removeBreakpoint(bpRecipie: BPRecipie): Promise; +} + +interface BreakpointClass { + new(recipie: BPRecipie, actualLocation: LocationInScript): Breakpoint; +} + +@injectable() +export class CDTPTargetBreakpoints extends CDTPEventsEmitterDiagnosticsModule implements ITargetBreakpoints { + protected readonly api: Crdp.DebuggerApi = this.protocolApi.Debugger; + + public readonly onBreakpointResolved = this.addApiListener('breakpointResolved', async (params: Crdp.Debugger.BreakpointResolvedEvent) => { + const bpRecipie = this._breakpointIdRegistry.getRecipieByBreakpointId(params.breakpointId); + const breakpoint = new Breakpoint(bpRecipie, + await this.toLocationInScript(params.location)); + return breakpoint; + }); + + public async setBreakpoint(bpRecipie: BPRecipieInScript): Promise { + const condition = this.getBPRecipieCondition(bpRecipie); + + const response = await this.api.setBreakpoint({ location: this.toCrdpLocation(bpRecipie.location), condition }); + + // We need to call registerRecipie sync with the response, before any awaits so if we get an event witha breakpointId we'll be able to resolve it properly + this._breakpointIdRegistry.registerRecipie(response.breakpointId, bpRecipie); + + return this.toBreakpointInScript(bpRecipie, response); + } + + public async setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise { + const condition = this.getBPRecipieCondition(bpRecipie); + const url = bpRecipie.location.url.textRepresentation; + const location = bpRecipie.location.coordinates; + + const response = await this.api.setBreakpointByUrl({ url, lineNumber: location.lineNumber, columnNumber: location.columnNumber, condition }); + + // We need to call registerRecipie sync with the response, before any awaits so if we get an event witha breakpointId we'll be able to resolve it properly + this._breakpointIdRegistry.registerRecipie(response.breakpointId, bpRecipie); + + return Promise.all(response.locations.map(cdtpLocation => this.toBreakpointInUrl(bpRecipie, cdtpLocation))); + } + + public async setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise { + const condition = this.getBPRecipieCondition(bpRecipie); + const urlRegex = bpRecipie.location.urlRegexp; + const location = bpRecipie.location.coordinates; + + const response = await this.api.setBreakpointByUrl({ urlRegex, lineNumber: location.lineNumber, columnNumber: location.columnNumber, condition }); + + // We need to call registerRecipie sync with the response, before any awaits so if we get an event witha breakpointId we'll be able to resolve it properly + this._breakpointIdRegistry.registerRecipie(response.breakpointId, bpRecipie); + + return Promise.all(response.locations.map(cdtpLocation => this.toBreakpointInUrlRegexp(bpRecipie, cdtpLocation))); + } + + public async getPossibleBreakpoints(rangeInScript: RangeInScript): Promise { + const response = await this.api.getPossibleBreakpoints({ + start: this.toCrdpLocation(rangeInScript.startInScript), + end: this.toCrdpLocation(rangeInScript.endInScript) + }); + + return asyncMap(response.locations, async location => await this.toLocationInScript(location)); + } + + public async removeBreakpoint(bpRecipie: BPRecipie): Promise { + await this.api.removeBreakpoint({ breakpointId: this._breakpointIdRegistry.getBreakpointId(bpRecipie) }); + this._breakpointIdRegistry.unregisterRecipie(bpRecipie); + } + + private getBPRecipieCondition(bpRecipie: IBPRecipie): string | undefined { + return bpRecipie.bpActionWhenHit.basedOnTypeDo({ + alwaysBreak: () => undefined, + conditionalBreak: conditionalBreak => conditionalBreak.expressionOfWhenToBreak + }); + } + + private async toBreakpointInUrlRegexp(bpRecipie: BPRecipieInUrlRegexp, actualLocation: Crdp.Debugger.Location): Promise { + return this.toBreakpoinInResource(BreakpointInUrlRegexp, bpRecipie, actualLocation); + } + + private async toBreakpoinInResource(classToUse: BreakpointClass, + bpRecipie: BPRecipie, actualLocation: Crdp.Debugger.Location): Promise> { + const breakpoint = new classToUse(bpRecipie, await this.toLocationInScript(actualLocation)); + return breakpoint; + } + + private async toBreakpointInScript(bpRecipie: BPRecipieInScript, params: Crdp.Debugger.SetBreakpointResponse): Promise { + return this.toBreakpoinInResource(BreakpointInScript, bpRecipie, params.actualLocation); + } + + private async toBreakpointInUrl(bpRecipie: BPRecipieInUrl, actualLocation: Crdp.Debugger.Location): Promise { + return this.toBreakpoinInResource>(BreakpointInUrl, bpRecipie, actualLocation); + } + + private toCrdpLocation(location: LocationInScript): Crdp.Debugger.Location { + return { + scriptId: this._scriptsRegistry.getCrdpId(location.script), + lineNumber: location.lineNumber, + columnNumber: location.columnNumber + }; + } + + public toLocationInScript(location: Crdp.Debugger.Location): Promise { + return this._cdtpLocationParser.getPositionInScript(location); + } + + constructor( + @inject(TYPES.CDTPClient) protected readonly protocolApi: Crdp.ProtocolApi, + @inject(TYPES.CDTPLocationParser) private readonly _cdtpLocationParser: CDTPLocationParser, + @inject(TYPES.BreakpointIdRegistry) private readonly _breakpointIdRegistry: BreakpointIdRegistry, + @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry) { + super(); + } +} diff --git a/src/chrome/target/controlDebugeeExecution.ts b/src/chrome/target/controlDebugeeExecution.ts new file mode 100644 index 000000000..3d7a10a42 --- /dev/null +++ b/src/chrome/target/controlDebugeeExecution.ts @@ -0,0 +1,57 @@ +import { Crdp } from '../..'; + +import { ICallFrame } from '../internal/stackTraces/callFrame'; + +import { IScript } from '../internal/scripts/script'; +import { CallFrameRegistry } from './callFrameRegistry'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; + +export interface IDebugeeExecutionControl { + resume(): Promise; + pause(): Promise; +} + +export interface IDebugeeStepping { + stepOver(): Promise; + stepInto(params: { breakOnAsyncCall: boolean }): Promise; + stepOut(): Promise; + restartFrame(callFrame: ICallFrame): Promise; + pauseOnAsyncCall(params: Crdp.Debugger.PauseOnAsyncCallRequest): Promise; +} + +@injectable() +export class ControlDebugeeExecution implements IDebugeeExecutionControl, IDebugeeStepping { + public pauseOnAsyncCall(params: Crdp.Debugger.PauseOnAsyncCallRequest): Promise { + return this.api.Debugger.pauseOnAsyncCall(params); + } + + public resume(): Promise { + return this.api.Debugger.resume(); + } + + public stepOver(): Promise { + return this.api.Debugger.stepOver(); + } + + public stepInto(params: Crdp.Debugger.StepIntoRequest): Promise { + return this.api.Debugger.stepInto(params); + } + + public stepOut(): Promise { + return this.api.Debugger.stepOut(); + } + + public pause(): Promise { + return this.api.Debugger.pause(); + } + + public restartFrame(frame: ICallFrame): Promise { + return this.api.Debugger.restartFrame({ callFrameId: this._callFrameRegistry.getFrameId(frame) }); + } + + constructor( + @inject(TYPES.CDTPClient) protected readonly api: Crdp.ProtocolApi, + private readonly _callFrameRegistry: CallFrameRegistry) { + } +} \ No newline at end of file diff --git a/src/chrome/target/events.ts b/src/chrome/target/events.ts index 78122dbf2..3d0324b4a 100644 --- a/src/chrome/target/events.ts +++ b/src/chrome/target/events.ts @@ -2,6 +2,11 @@ import { IScript } from '../internal/scripts/script'; import { Crdp } from '../..'; +import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; +import { CodeFlowStackTrace } from '../internal/stackTraces/stackTrace'; +import { ICallFrame, ScriptOrLoadedSource } from '../internal/stackTraces/callFrame'; +import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; + export type integer = number; /** @@ -22,4 +27,76 @@ export interface ScriptParsedEvent { readonly hasSourceURL?: boolean; readonly isModule?: boolean; readonly length?: integer; + readonly stackTrace?: CodeFlowStackTrace; +} + +export class PausedEvent { + public cloneButWithHitBreakpoints(hitBreakpoints: IBPRecipie[]): PausedEvent { + return new PausedEvent( + this.callFrames, + this.reason, + this.data, + hitBreakpoints, + this.asyncStackTrace, + this.asyncCallStackTraceId, + this.asyncStackTraceId); + } + + constructor( + public readonly callFrames: ICallFrame[], + public readonly reason: ('XHR' | 'DOM' | 'EventListener' | 'exception' | 'assert' | 'debugCommand' | 'promiseRejection' | 'OOM' | 'other' | 'ambiguous'), + public readonly data?: any, + public readonly hitBreakpoints?: IBPRecipie[], // TODO DIEGO: Make this readonly + public readonly asyncStackTrace?: CodeFlowStackTrace, + public readonly asyncStackTraceId?: Crdp.Runtime.StackTraceId, + public readonly asyncCallStackTraceId?: Crdp.Runtime.StackTraceId) { } +} + +export interface ConsoleAPICalledEvent { + readonly type: ('log' | 'debug' | 'info' | 'error' | 'warning' | 'dir' | 'dirxml' | 'table' | 'trace' | 'clear' | 'startGroup' | 'startGroupCollapsed' | 'endGroup' | 'assert' | 'profile' | 'profileEnd' | 'count' | 'timeEnd'); + readonly args: Crdp.Runtime.RemoteObject[]; + readonly executionContextId: Crdp.Runtime.ExecutionContextId; + readonly timestamp: Crdp.Runtime.Timestamp; + readonly stackTrace?: CodeFlowStackTrace; + readonly context?: string; +} + +export interface ExceptionThrownEvent { + readonly timestamp: Crdp.Runtime.Timestamp; + readonly exceptionDetails: ExceptionDetails; +} + +export interface ExceptionDetails { + readonly exceptionId: integer; + readonly text: string; + readonly lineNumber: integer; + readonly columnNumber: integer; + readonly script?: IScript; + readonly url?: string; + readonly stackTrace?: CodeFlowStackTrace; + readonly exception?: Crdp.Runtime.RemoteObject; + readonly executionContextId?: Crdp.Runtime.ExecutionContextId; +} + +export interface SetVariableValueRequest { + readonly scopeNumber: integer; + readonly variableName: string; + readonly newValue: Crdp.Runtime.CallArgument; + readonly frame: ICallFrame; +} + +export type LogEntrySource = 'xml' | 'javascript' | 'network' | 'storage' | 'appcache' | 'rendering' | 'security' | 'deprecation' | 'worker' | 'violation' | 'intervention' | 'recommendation' | 'other'; +export type LogLevel = 'verbose' | 'info' | 'warning' | 'error'; + +export interface LogEntry { + readonly source: LogEntrySource; + readonly level: LogLevel; + readonly text: string; + readonly timestamp: Crdp.Runtime.Timestamp; + readonly url?: string; + readonly lineNumber?: integer; + readonly stackTrace?: CodeFlowStackTrace; + readonly networkRequestId?: Crdp.Network.RequestId; + readonly workerId?: string; + readonly args?: Crdp.Runtime.RemoteObject[]; } diff --git a/src/chrome/target/exceptionThrownEventProvider.ts b/src/chrome/target/exceptionThrownEventProvider.ts new file mode 100644 index 000000000..5c21ec3a1 --- /dev/null +++ b/src/chrome/target/exceptionThrownEventProvider.ts @@ -0,0 +1,44 @@ +import { Crdp } from '../..'; +import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; +import { ExceptionDetails } from './events'; +import { CDTPStackTraceParser } from './cdtpStackTraceParser'; +import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; + +export interface IExceptionThrownEventProvider { + +} + +@injectable() +export class ExceptionThrownEventProvider extends CDTPEventsEmitterDiagnosticsModule implements IExceptionThrownEventProvider { + protected readonly api: Crdp.RuntimeApi = this.protocolApi.Runtime; + + public readonly onExceptionThrown = this.addApiListener('exceptionThrown', async (params: Crdp.Runtime.ExceptionThrownEvent) => + ({ + timestamp: params.timestamp, + exceptionDetails: await this.toExceptionDetails(params.exceptionDetails) + })); + + private async toExceptionDetails(exceptionDetails: Crdp.Runtime.ExceptionDetails): Promise { + return { + exceptionId: exceptionDetails.exceptionId, + text: exceptionDetails.text, + lineNumber: exceptionDetails.lineNumber, + columnNumber: exceptionDetails.columnNumber, + script: exceptionDetails.scriptId ? await this._scriptsRegistry.getScriptById(exceptionDetails.scriptId) : undefined, + url: exceptionDetails.url, + stackTrace: exceptionDetails.stackTrace && await this._cdtpStackTraceParser.toStackTraceCodeFlow(exceptionDetails.stackTrace), + exception: exceptionDetails.exception, + executionContextId: exceptionDetails.executionContextId, + }; + } + + constructor( + @inject(TYPES.CDTPClient) private readonly protocolApi: Crdp.ProtocolApi, + private readonly _cdtpStackTraceParser: CDTPStackTraceParser, + private readonly _scriptsRegistry: CDTPScriptsRegistry, + ) { + super(); + } +} \ No newline at end of file diff --git a/src/chrome/target/executionContextEventsProvider.ts b/src/chrome/target/executionContextEventsProvider.ts new file mode 100644 index 000000000..27188fd91 --- /dev/null +++ b/src/chrome/target/executionContextEventsProvider.ts @@ -0,0 +1,24 @@ +import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; +import { Crdp } from '../..'; +import { inject, injectable } from 'inversify'; +import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; +import { TYPES } from '../dependencyInjection.ts/types'; + +@injectable() +export class ExecutionContextEventsProvider extends CDTPEventsEmitterDiagnosticsModule { + protected readonly api: Crdp.RuntimeApi = this._protocolApi.Runtime; + + public readonly onExecutionContextsCleared = this.addApiListener('executionContextsCleared', (params: void) => params); + + public readonly onExecutionContextDestroyed = this.addApiListener('executionContextDestroyed', async (params: Crdp.Runtime.ExecutionContextDestroyedEvent) => + this._scriptsRegistry.markExecutionContextAsDestroyed(params.executionContextId)); + + public readonly onExecutionContextCreated = this.addApiListener('executionContextCreated', async (params: Crdp.Runtime.ExecutionContextCreatedEvent) => + this._scriptsRegistry.registerExecutionContext(params.context.id)); + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: Crdp.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry) { + super(); + } +} \ No newline at end of file diff --git a/src/chrome/target/inspectDebugeeState.ts b/src/chrome/target/inspectDebugeeState.ts new file mode 100644 index 000000000..c8c24ba11 --- /dev/null +++ b/src/chrome/target/inspectDebugeeState.ts @@ -0,0 +1,50 @@ +import { EvaluateOnCallFrameRequest } from './requests'; +import { Crdp } from '../..'; +import { CallFrameRegistry } from './callFrameRegistry'; +import { AddSourceUriToExpession } from './addSourceUriToExpression'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../dependencyInjection.ts/types'; + +export interface IInspectDebugeeState { + callFunctionOn(params: Crdp.Runtime.CallFunctionOnRequest): Promise; + getProperties(params: Crdp.Runtime.GetPropertiesRequest): Promise; + evaluate(params: Crdp.Runtime.EvaluateRequest): Promise; + evaluateOnCallFrame(params: EvaluateOnCallFrameRequest): Promise; +} + +@injectable() +export class InspectDebugeeState implements IInspectDebugeeState { + private addSourceUriToEvaluates = new AddSourceUriToExpession('evaluateOnFrame'); + + public callFunctionOn(params: Crdp.Runtime.CallFunctionOnRequest): Promise { + return this.api.Runtime.callFunctionOn(params); + } + + public getProperties(params: Crdp.Runtime.GetPropertiesRequest): Promise { + return this.api.Runtime.getProperties(params); + } + + public evaluate(params: Crdp.Runtime.EvaluateRequest): Promise { + params.expression = this.addSourceUriToEvaluates.addURLIfMissing(params.expression); + return this.api.Runtime.evaluate(params); + } + + public evaluateOnCallFrame(params: EvaluateOnCallFrameRequest): Promise { + return this.api.Debugger.evaluateOnCallFrame({ + callFrameId: this._callFrameRegistry.getFrameId(params.frame.unmappedCallFrame), + expression: this.addSourceUriToEvaluates.addURLIfMissing(params.expression), + objectGroup: params.objectGroup, + includeCommandLineAPI: params.includeCommandLineAPI, + silent: params.silent, + returnByValue: params.returnByValue, + generatePreview: params.generatePreview, + throwOnSideEffect: params.throwOnSideEffect, + timeout: params.timeout, + }); + } + + constructor( + @inject(TYPES.CDTPClient) protected readonly api: Crdp.ProtocolApi, + private readonly _callFrameRegistry: CallFrameRegistry) { + } +} \ No newline at end of file diff --git a/src/chrome/target/requests.ts b/src/chrome/target/requests.ts new file mode 100644 index 000000000..2d5da392b --- /dev/null +++ b/src/chrome/target/requests.ts @@ -0,0 +1,25 @@ +import { Crdp } from '../..'; +import { LocationInScript } from '../internal/locations/location'; +import { ICallFrame, ScriptOrLoadedSource } from '../internal/stackTraces/callFrame'; + +export interface INewSetBreakpointResult { + readonly breakpointId?: Crdp.Debugger.BreakpointId; + readonly actualLocation?: LocationInScript; +} + +export interface INewAddBreakpointsResult { + readonly breakpointId?: Crdp.Debugger.BreakpointId; + readonly actualLocation?: LocationInScript & { scriptId?: Crdp.Runtime.ScriptId }; // TODO: node-debug2 is currently using the scriptId property +} + +export interface EvaluateOnCallFrameRequest { + readonly frame: ICallFrame; + readonly expression: string; + readonly objectGroup?: string; + readonly includeCommandLineAPI?: boolean; + readonly silent?: boolean; + readonly returnByValue?: boolean; + readonly generatePreview?: boolean; + readonly throwOnSideEffect?: boolean; + readonly timeout?: Crdp.Runtime.TimeDelta; +} \ No newline at end of file diff --git a/src/chrome/target/updateDebugeeState.ts b/src/chrome/target/updateDebugeeState.ts new file mode 100644 index 000000000..f6d305299 --- /dev/null +++ b/src/chrome/target/updateDebugeeState.ts @@ -0,0 +1,26 @@ +import { Crdp } from '../..'; +import { SetVariableValueRequest } from './events'; +import { CallFrameRegistry } from './callFrameRegistry'; +import { TYPES } from '../dependencyInjection.ts/types'; +import { injectable, inject } from 'inversify'; + +export interface IUpdateDebugeeState { + setVariableValue(params: SetVariableValueRequest): Promise; +} + +@injectable() +export class UpdateDebugeeState implements IUpdateDebugeeState { + public setVariableValue(params: SetVariableValueRequest): Promise { + return this.api.Debugger.setVariableValue({ + callFrameId: this._callFrameRegistry.getFrameId(params.frame), + scopeNumber: params.scopeNumber, + variableName: params.variableName, + newValue: params.newValue + }); + } + + constructor( + @inject(TYPES.CDTPClient) private readonly api: Crdp.ProtocolApi, + private readonly _callFrameRegistry: CallFrameRegistry) { + } +} \ No newline at end of file diff --git a/src/chrome/utils/combine.ts b/src/chrome/utils/combine.ts new file mode 100644 index 000000000..215fc502b --- /dev/null +++ b/src/chrome/utils/combine.ts @@ -0,0 +1,27 @@ +import { ValidatedMap } from '../collections/validatedMap'; + +export function combine(object1: T1, object2: T2): T1 & T2; +export function combine(...objects: object[]): any { + const keyToObject = new ValidatedMap(); + for (const object of objects) { + for (const key in object) { + if (!keyToObject.has(key)) { + keyToObject.set(key, object); + } else { + throw new Error(`Can't combine objects into a proxy because both ${object} and ${keyToObject.get(key)} have a property named ${key}`); + } + } + } + + return new Proxy({}, { + get: (_target: any, key: PropertyKey, _receiver: any): any => { + const choosenReceiver = keyToObject.get(key) as any; + return choosenReceiver[key].bind(choosenReceiver); + } + }); +} + +export function combineProperties(object1: T1, object2: T2): T1 & T2; +export function combineProperties(...objects: object[]): any { + return Object.assign({}, ...objects); +} \ No newline at end of file diff --git a/src/chrome/utils/failures.ts b/src/chrome/utils/failures.ts new file mode 100644 index 000000000..7da836dcf --- /dev/null +++ b/src/chrome/utils/failures.ts @@ -0,0 +1,17 @@ +export function undefinedOnFailure(operation: () => R): R | undefined { + try { + return operation(); + } catch (exception) { + // TODO DIEGO: Report telemetry for this + return undefined; + } +} + +export async function asyncUndefinedOnFailure(operation: () => Promise): Promise { + try { + return await operation(); + } catch (exception) { + // TODO DIEGO: Report telemetry for this + return undefined; + } +} \ No newline at end of file diff --git a/src/chrome/utils/localization.ts b/src/chrome/utils/localization.ts new file mode 100644 index 000000000..5c3aab1b4 --- /dev/null +++ b/src/chrome/utils/localization.ts @@ -0,0 +1,18 @@ +// import { LocalizeInfo, loadMessageBundle, config } from 'vscode-nls'; +// let _localize = loadMessageBundle(); // Initialize to an unlocalized version until we know which locale to use + +// // TODO DIEGO: Make sure this works + +// export function localize(info: LocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): string; +// export function localize(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): string; +// export function localize(infoOrKey: string | LocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]) { +// if (typeof infoOrKey === 'string') { // The compiler doesn't like it if we just make a single call +// return _localize(infoOrKey, message, ...args); +// } else { +// return _localize(infoOrKey, message, ...args); +// } +// } + +// export function setLocale(locale: string): void { +// _localize = config({ locale: locale })(); // Replace with the proper locale +// } diff --git a/src/chrome/utils/namespaceReverseLookupCreator.ts b/src/chrome/utils/namespaceReverseLookupCreator.ts new file mode 100644 index 000000000..f1023338c --- /dev/null +++ b/src/chrome/utils/namespaceReverseLookupCreator.ts @@ -0,0 +1,27 @@ +export type NamespaceTree = { [name: string]: NamespaceTree | T }; + +export class NamespaceReverseLookupCreator { + private readonly _leafToNameMapping = new Map(); + + constructor( + private readonly _root: NamespaceTree, + private readonly _isLeaf: (node: NamespaceTree | T) => node is T, + private readonly _namesPrefix: string) { } + + public create(): Map { + this.exploreLeaf(this._root, this._namesPrefix); + return this._leafToNameMapping; + } + + private exploreLeaf(currentRoot: NamespaceTree, namePrefix: string): void { + for (const propertyNamme in currentRoot) { + const propertyName = namePrefix ? `${namePrefix}.${propertyNamme}` : propertyNamme; + const propertyValue = currentRoot[propertyNamme]; + if (this._isLeaf(propertyValue)) { + this._leafToNameMapping.set(propertyValue as T, propertyName); + } else { + this.exploreLeaf(propertyValue, propertyName); + } + } + } +} \ No newline at end of file diff --git a/src/chrome/utils/promises.ts b/src/chrome/utils/promises.ts new file mode 100644 index 000000000..8af59dca9 --- /dev/null +++ b/src/chrome/utils/promises.ts @@ -0,0 +1 @@ +export type PromiseOrNot = Promise | T; \ No newline at end of file diff --git a/src/chrome/variables.ts b/src/chrome/variables.ts index 9184fe5ae..4777002eb 100644 --- a/src/chrome/variables.ts +++ b/src/chrome/variables.ts @@ -5,30 +5,31 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { Handles } from 'vscode-debugadapter'; -import { ChromeDebugAdapter, VariableContext } from './chromeDebugAdapter'; +import { ChromeDebugLogic, VariableContext } from './chromeDebugAdapter'; import { Protocol as Crdp } from 'devtools-protocol'; import * as utils from '../utils'; +import { ICallFrame, ScriptOrLoadedSource } from './internal/stackTraces/callFrame'; export interface IVariableContainer { - expand(adapter: ChromeDebugAdapter, filter?: string, start?: number, count?: number): Promise; - setValue(adapter: ChromeDebugAdapter, name: string, value: string): Promise; + expand(adapter: ChromeDebugLogic, filter?: string, start?: number, count?: number): Promise; + setValue(adapter: ChromeDebugLogic, name: string, value: string): Promise; } export abstract class BaseVariableContainer implements IVariableContainer { constructor(protected objectId: string, protected evaluateName?: string) { } - public expand(adapter: ChromeDebugAdapter, filter?: string, start?: number, count?: number): Promise { + public expand(adapter: ChromeDebugLogic, filter?: string, start?: number, count?: number): Promise { return adapter.getVariablesForObjectId(this.objectId, this.evaluateName, filter, start, count); } - public setValue(adapter: ChromeDebugAdapter, name: string, value: string): Promise { + public setValue(_adapter: ChromeDebugLogic, _name: string, _value: string): Promise { return utils.errP('setValue not supported by this variable type'); } } export class PropertyContainer extends BaseVariableContainer { - public setValue(adapter: ChromeDebugAdapter, name: string, value: string): Promise { + public setValue(adapter: ChromeDebugLogic, name: string, value: string): Promise { return adapter.setPropertyValue(this.objectId, name, value); } } @@ -38,7 +39,7 @@ export class LoggedObjects extends BaseVariableContainer { super(undefined); } - public expand(adapter: ChromeDebugAdapter, filter?: string, start?: number, count?: number): Promise { + public expand(adapter: ChromeDebugLogic, _filter?: string, _start?: number, _count?: number): Promise { return Promise.all(this.args.map((arg, i) => adapter.remoteObjectToVariable('' + i, arg, undefined, /*stringify=*/false, 'repl'))); } } @@ -46,10 +47,10 @@ export class LoggedObjects extends BaseVariableContainer { export class ScopeContainer extends BaseVariableContainer { private _thisObj: Crdp.Runtime.RemoteObject; private _returnValue: Crdp.Runtime.RemoteObject; - private _frameId: string; + private _frameId: ICallFrame; private _origScopeIndex: number; - public constructor(frameId: string, origScopeIndex: number, objectId: string, thisObj?: Crdp.Runtime.RemoteObject, returnValue?: Crdp.Runtime.RemoteObject) { + public constructor(frameId: ICallFrame, origScopeIndex: number, objectId: string, thisObj?: Crdp.Runtime.RemoteObject, returnValue?: Crdp.Runtime.RemoteObject) { super(objectId, ''); this._thisObj = thisObj; this._returnValue = returnValue; @@ -60,10 +61,10 @@ export class ScopeContainer extends BaseVariableContainer { /** * Call super then insert the 'this' object if needed */ - public expand(adapter: ChromeDebugAdapter, filter?: string, start?: number, count?: number): Promise { + public expand(adapter: ChromeDebugLogic, _filter?: string, start?: number, count?: number): Promise { // No filtering in scopes right now return super.expand(adapter, 'all', start, count).then(variables => { - if (this._thisObj) { + if (this._thisObj && !variables.find(v => v.name === 'this')) { // If this is a scope that should have the 'this', prop, insert it at the top of the list return this.insertRemoteObject(adapter, variables, 'this', this._thisObj); } @@ -78,11 +79,11 @@ export class ScopeContainer extends BaseVariableContainer { }); } - public setValue(adapter: ChromeDebugAdapter, name: string, value: string): Promise { + public setValue(adapter: ChromeDebugLogic, name: string, value: string): Promise { return adapter.setVariableValue(this._frameId, this._origScopeIndex, name, value); } - private insertRemoteObject(adapter: ChromeDebugAdapter, variables: DebugProtocol.Variable[], name: string, obj: Crdp.Runtime.RemoteObject): Promise { + private insertRemoteObject(adapter: ChromeDebugLogic, variables: DebugProtocol.Variable[], name: string, obj: Crdp.Runtime.RemoteObject): Promise { return adapter.remoteObjectToVariable(name, obj).then(variable => { variables.unshift(variable); return variables; @@ -93,7 +94,7 @@ export class ScopeContainer extends BaseVariableContainer { export class ExceptionContainer extends PropertyContainer { protected _exception: Crdp.Runtime.RemoteObject; - protected constructor(objectId: string, exception: Crdp.Runtime.RemoteObject) { + protected constructor(_objectId: string, exception: Crdp.Runtime.RemoteObject) { super(exception.objectId, undefined); this._exception = exception; } @@ -119,7 +120,7 @@ export class ExceptionValueContainer extends ExceptionContainer { /** * Make up a fake 'Exception' property to hold the thrown value, displayed under the Exception Scope */ - public expand(adapter: ChromeDebugAdapter, filter?: string, start?: number, count?: number): Promise { + public expand(adapter: ChromeDebugLogic, _filter?: string, _start?: number, _count?: number): Promise { const excValuePropDescriptor: Crdp.Runtime.PropertyDescriptor = { name: 'Exception', value: this._exception }; return adapter.propertyDescriptorToVariable(excValuePropDescriptor) .then(variable => [variable]); @@ -143,7 +144,7 @@ function getArrayPreview(object: Crdp.Runtime.RemoteObject, context?: string): s // Take the first 3 props, and parse the indexes const propsWithIdx = indexedProps.slice(0, numProps) - .map((prop, i) => { + .map((prop, _i) => { return { idx: parseInt(prop.name, 10), value: propertyPreviewToString(prop) @@ -275,7 +276,7 @@ export function getRemoteObjectPreview_primitive(object: Crdp.Runtime.RemoteObje } } -export function getRemoteObjectPreview_function(object: Crdp.Runtime.RemoteObject, context?: string): string { +export function getRemoteObjectPreview_function(object: Crdp.Runtime.RemoteObject, _context?: string): string { const firstBraceIdx = object.description.indexOf('{'); if (firstBraceIdx >= 0) { return object.description.substring(0, firstBraceIdx) + '{ … }'; diff --git a/src/debugAdapterInterfaces.d.ts b/src/debugAdapterInterfaces.d.ts index e184e61f0..09126e63b 100644 --- a/src/debugAdapterInterfaces.d.ts +++ b/src/debugAdapterInterfaces.d.ts @@ -11,6 +11,10 @@ import { Protocol as Crdp } from 'devtools-protocol'; import { ITelemetryPropertyCollector } from './telemetry'; import { IStringDictionary } from './utils'; import { ITargetFilter } from './chrome/chromeConnection'; +import { LocationInScript } from './chrome/internal/locations/location'; +import { IScript } from './chrome/internal/scripts/script'; +import { ILoadedSource } from './chrome/internal/sources/loadedSource'; +import { IResourceIdentifier } from './chrome/internal/sources/resourceIdentifier'; export type ISourceMapPathOverrides = IStringDictionary; export type IPathMapping = IStringDictionary; @@ -47,6 +51,8 @@ export interface ICommonRequestArgs { breakOnLoadStrategy?: BreakOnLoadStrategy; _suppressConsoleOutput?: boolean; + + port?: number; } export interface IInitializeRequestArgs extends DebugProtocol.InitializeRequestArguments { @@ -73,7 +79,10 @@ export interface IAttachRequestArgs extends DebugProtocol.AttachRequestArguments websocketUrl?: string; } +export interface ISetBreakpointsRequestArgs extends DebugProtocol.SetBreakpointsArguments {} + export interface IToggleSkipFileStatusArgs { + /** This requests comes from the debug extension, so it's on a pseudo-vscode protocol format which can be both path or source reference */ path?: string; sourceReference?: number; } @@ -101,14 +110,6 @@ export type IThreadsResponseBody = DebugProtocol.ThreadsResponse['body']; export type IStackTraceResponseBody = DebugProtocol.StackTraceResponse['body']; -export interface IInternalStackTraceResponseBody extends IStackTraceResponseBody { - stackFrames: IInternalStackFrame[]; -} - -export interface IInternalStackFrame extends DebugProtocol.StackFrame { - isSourceMapped?: boolean; -} - export type IScopesResponseBody = DebugProtocol.ScopesResponse['body']; export type IVariablesResponseBody = DebugProtocol.VariablesResponse['body']; @@ -142,17 +143,32 @@ export interface TimeTravelRuntime extends Crdp.ProtocolApi { TimeTravel: TimeTravelClient; } +export interface IUninitializedDebugAdapter { + initialize(args: DebugProtocol.InitializeRequestArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; +} + +export interface IUninitializedDebugAdapterState { + initialize(args: DebugProtocol.InitializeRequestArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot<{capabilities: DebugProtocol.Capabilities, newState: IDebugAdapterState}>; +} + +export interface IUnconnectedDebugAdapter { + launch(args: ILaunchRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; + attach(args: IAttachRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; +} + +export interface IUnconnectedDebugAdapterState { + launch(args: ILaunchRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; + attach(args: IAttachRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; +} + /** * All methods returning PromiseOrNot can either return a Promise or a value, and if they reject the Promise, it can be with an Error or a * DebugProtocol.Message object, which will be sent to sendErrorResponse. */ -export interface IDebugAdapter { +export interface IConnectedDebugAdapter { // From DebugSession shutdown(): void; - initialize(args: DebugProtocol.InitializeRequestArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; - launch(args: ILaunchRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; - attach(args: IAttachRequestArgs, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; disconnect(args: DebugProtocol.DisconnectArguments): PromiseOrNot; setBreakpoints(args: DebugProtocol.SetBreakpointsArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; setExceptionBreakpoints(args: DebugProtocol.SetExceptionBreakpointsArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; @@ -163,6 +179,7 @@ export interface IDebugAdapter { stepIn(): PromiseOrNot; stepOut(): PromiseOrNot; pause(): PromiseOrNot; + restartFrame(args: DebugProtocol.RestartFrameRequest): Promise; stackTrace(args: DebugProtocol.StackTraceArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; scopes(args: DebugProtocol.ScopesArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; @@ -170,13 +187,24 @@ export interface IDebugAdapter { source(args: DebugProtocol.SourceArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; threads(): PromiseOrNot; evaluate(args: DebugProtocol.EvaluateArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; + + exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): Promise; + loadedSources(args: DebugProtocol.LoadedSourcesArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; + + setFunctionBreakpoints(args: DebugProtocol.SetFunctionBreakpointsArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; + setVariable(args: DebugProtocol.SetVariableArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; } +export type IDebugAdapter = IConnectedDebugAdapter & IUnconnectedDebugAdapter & IUninitializedDebugAdapter; +export type IClientCapabilities = IInitializeRequestArgs; + +export type IDebugAdapterState = IConnectedDebugAdapter & IUnconnectedDebugAdapterState & IUninitializedDebugAdapterState; + export interface IDebugTransformer { initialize?(args: DebugProtocol.InitializeRequestArguments, requestSeq?: number): PromiseOrNot; launch?(args: ILaunchRequestArgs, requestSeq?: number): PromiseOrNot; attach?(args: IAttachRequestArgs, requestSeq?: number): PromiseOrNot; - setBreakpoints?(args: DebugProtocol.SetBreakpointsArguments, requestSeq?: number): PromiseOrNot; + setBreakpoints?(args: ISetBreakpointsRequestArgs, requestSeq?: number): PromiseOrNot; setExceptionBreakpoints?(args: DebugProtocol.SetExceptionBreakpointsArguments, requestSeq?: number): PromiseOrNot; stackTrace?(args: DebugProtocol.StackTraceArguments, requestSeq?: number): PromiseOrNot; diff --git a/src/index.ts b/src/index.ts index d39132409..d754477f6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,11 +2,13 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ +import 'reflect-metadata'; // We need to import this before any inject attempts to use it + /** Normally, a consumer could require and use this and get the same instance. But if -core is npm linked, there may be two instances of file in play. */ import { logger } from 'vscode-debugadapter'; import * as chromeConnection from './chrome/chromeConnection'; -import { ChromeDebugAdapter, LoadedSourceEventReason, IOnPausedResult } from './chrome/chromeDebugAdapter'; +import { ChromeDebugLogic, LoadedSourceEventReason } from './chrome/chromeDebugAdapter'; import { ChromeDebugSession, IChromeDebugSessionOpts } from './chrome/chromeDebugSession'; import * as chromeTargetDiscoveryStrategy from './chrome/chromeTargetDiscoveryStrategy'; import * as chromeUtils from './chrome/chromeUtils'; @@ -29,10 +31,26 @@ import * as executionTimingsReporter from './executionTimingsReporter'; import { Protocol as Crdp } from 'devtools-protocol'; import { Version, TargetVersions } from './chrome/chromeTargetDiscoveryStrategy'; +import { IOnPausedResult } from './chrome/internal/breakpoints/breakpointsLogic'; +import { parseResourceIdentifier } from './chrome/internal/sources/resourceIdentifier'; +import { ChromeDebugAdapter } from './chrome/client/chromeDebugAdapter/chromeDebugAdapterV2'; +import { IExtensibilityPoints, OnlyProvideCustomLauncherExtensibilityPoints } from './chrome/extensibility/extensibilityPoints'; +import { IDebuggeeLauncher, ILaunchResult, IDebuggeeRunner } from './chrome/debugee/debugeeLauncher'; +import { inject, injectable, postConstruct } from 'inversify'; +import { ConnectedCDAConfiguration } from './chrome/client/chromeDebugAdapter/cdaConfiguration'; +import { IComponent } from './chrome/internal/features/feature'; +import { TYPES } from './chrome/dependencyInjection.ts/types'; +import { IInspectDebugeeState } from './chrome/target/inspectDebugeeState'; +import { CDTPEventsEmitterDiagnosticsModule } from './chrome/target/cdtpDiagnosticsModule'; +import { INetworkCacheConfiguration, IDebugeeVersionProvider, IPausedOverlay, IBrowserNavigation } from './chrome/target/cdtpSmallerModules'; +import { ICommunicator } from './chrome/communication/communicator'; +import { ISupportedDomains } from './chrome/internal/domains/supportedDomains'; +import { Internal } from './chrome/communication/internalChannels'; +import { ISession } from './chrome/client/session'; export { chromeConnection, - ChromeDebugAdapter, + ChromeDebugLogic, ChromeDebugSession, IOnPausedResult, IChromeDebugSessionOpts, @@ -44,19 +62,52 @@ export { InternalSourceBreakpoint, ErrorWithMessage, + ChromeDebugAdapter, + IExtensibilityPoints, + OnlyProvideCustomLauncherExtensibilityPoints, + + IDebuggeeLauncher, + IDebuggeeRunner, + ILaunchResult, + ConnectedCDAConfiguration, + inject, + injectable, + IComponent, + + postConstruct, + UrlPathTransformer, BasePathTransformer, LineColTransformer, BaseSourceMapTransformer, + CDTPEventsEmitterDiagnosticsModule, utils, telemetry, variables, NullLogger, executionTimingsReporter, + ISupportedDomains, + IPausedOverlay, + Version, TargetVersions, + ICommunicator, + + Internal, + + INetworkCacheConfiguration, + IDebugeeVersionProvider, + + parseResourceIdentifier, + IBrowserNavigation, + + ISession, + TYPES, + + IInspectDebugeeState, + Crdp }; diff --git a/src/nullLogger.ts b/src/nullLogger.ts index 51f87787c..b07b171b9 100644 --- a/src/nullLogger.ts +++ b/src/nullLogger.ts @@ -8,19 +8,19 @@ import { Logger } from 'vscode-debugadapter'; * Implements ILogger as a no-op */ export class NullLogger implements Logger.ILogger { - log(msg: string, level?: Logger.LogLevel): void { + log(_msg: string, _level?: Logger.LogLevel): void { // no-op } - verbose(msg: string): void { + verbose(_msg: string): void { // no-op } - warn(msg: string): void { + warn(_msg: string): void { // no-op } - error(msg: string): void { + error(_msg: string): void { // no-op } diff --git a/src/sourceMaps/sourceMap.ts b/src/sourceMaps/sourceMap.ts index 776525671..ccfa112bc 100644 --- a/src/sourceMaps/sourceMap.ts +++ b/src/sourceMaps/sourceMap.ts @@ -100,7 +100,7 @@ export class SourceMap { // sm.sources are initially relative paths, file:/// urls, made-up urls like webpack:///./app.js, or paths that start with /. // resolve them to file:/// urls, using computedSourceRoot, to be simpler and unambiguous, since // it needs to look them up later in exactly the same format. - this._sources = sm.sources.map(sourcePath => { + this._sources = sm.sources.map((sourcePath: string) => { if (sourceMapPathOverrides) { const fullSourceEntry = sourceMapUtils.getFullSourceEntry(this._originalSourceRoot, sourcePath); const mappedFullSourceEntry = sourceMapUtils.applySourceMapPathOverrides(fullSourceEntry, sourceMapPathOverrides, isVSClient); @@ -159,7 +159,7 @@ export class SourceMap { * Finds the nearest source location for the given location in the generated file. * Will return null instead of a mapping on the next line (different from generatedPositionFor). */ - public authoredPositionFor(line: number, column: number): MappedPosition { + public authoredPositionFor(line: number, column: number): MappedPosition | null { // source-map lib uses 1-indexed lines. line++; @@ -196,7 +196,7 @@ export class SourceMap { * Finds the nearest location in the generated file for the given source location. * Will return a mapping on the next line, if there is no subsequent mapping on the expected line. */ - public generatedPositionFor(source: string, line: number, column: number): MappedPosition { + public generatedPositionFor(source: string, line: number, column: number): MappedPosition | null { // source-map lib uses 1-indexed lines. line++; diff --git a/src/sourceMaps/sourceMapFactory.ts b/src/sourceMaps/sourceMapFactory.ts index ca1aeb6c9..448b52eb5 100644 --- a/src/sourceMaps/sourceMapFactory.ts +++ b/src/sourceMaps/sourceMapFactory.ts @@ -112,13 +112,13 @@ export class SourceMapFactory { let contentsP: Promise; if (utils.isURL(mapPathOrURL) && !utils.isFileUrl(mapPathOrURL)) { logger.log(`SourceMaps.loadSourceMapContents: Downloading sourcemap file from ${mapPathOrURL}`); - contentsP = this.downloadSourceMapContents(mapPathOrURL).catch(e => { + contentsP = this.downloadSourceMapContents(mapPathOrURL).catch(_e => { logger.log(`SourceMaps.loadSourceMapContents: Could not download sourcemap from ${mapPathOrURL}`); return null; }); } else { mapPathOrURL = utils.canonicalizeUrl(mapPathOrURL); - contentsP = new Promise((resolve, reject) => { + contentsP = new Promise((resolve) => { logger.log(`SourceMaps.loadSourceMapContents: Reading local sourcemap file from ${mapPathOrURL}`); fs.readFile(mapPathOrURL, (err, data) => { if (err) { diff --git a/src/sourceMaps/sourceMaps.ts b/src/sourceMaps/sourceMaps.ts index 63931a956..2d7cf2587 100644 --- a/src/sourceMaps/sourceMaps.ts +++ b/src/sourceMaps/sourceMaps.ts @@ -69,11 +69,14 @@ export class SourceMaps { /** * Given a new path to a new script file, finds and loads the sourcemap for that file */ - public async processNewSourceMap(pathToGenerated: string, sourceMapURL: string, isVSClient = false): Promise { + public async processNewSourceMap(pathToGenerated: string, sourceMapURL: string, isVSClient = false): Promise { const sourceMap = await this._sourceMapFactory.getMapForGeneratedPath(pathToGenerated, sourceMapURL, isVSClient); if (sourceMap) { this._generatedPathToSourceMap.set(pathToGenerated.toLowerCase(), sourceMap); sourceMap.authoredSources.forEach(authoredSource => this._authoredPathToSourceMap.set(authoredSource.toLowerCase(), sourceMap)); + return sourceMap; + } else { + return null; } } } diff --git a/src/telemetry.ts b/src/telemetry.ts index f5d31d12f..fd6b1b6f7 100644 --- a/src/telemetry.ts +++ b/src/telemetry.ts @@ -106,7 +106,7 @@ export class AsyncGlobalPropertiesTelemetryReporter implements ITelemetryReporte } export class NullTelemetryReporter implements ITelemetryReporter { - reportEvent(name: string, data?: any): void { + reportEvent(_name: string, _data?: any): void { // no-op } @@ -181,23 +181,25 @@ export class BatchTelemetryReporter { */ private static transfromBucketData(bucketForEventType: any[]): {[groupedPropertyValue: string]: string} { const allPropertyNamesInTheBucket = BatchTelemetryReporter.collectPropertyNamesFromAllEvents(bucketForEventType); - let properties = {}; + let propertiesAsArray: {[groupedPropertyValue: string]: string[]} = {}; // Create a holder for all potential property names. for (const key of allPropertyNamesInTheBucket) { - properties[`aggregated.${key}`] = []; + propertiesAsArray[`aggregated.${key}`] = []; } // Run through all the events in the bucket, collect the values for each property name. for (const event of bucketForEventType) { for (const propertyName of allPropertyNamesInTheBucket) { - properties[`aggregated.${propertyName}`].push(event[propertyName] === undefined ? null : event[propertyName]); + propertiesAsArray[`aggregated.${propertyName}`].push(event[propertyName] === undefined ? null : event[propertyName]); } } + let properties: {[groupedPropertyValue: string]: string} = {}; + // Serialize each array as the final aggregated property value. for (const propertyName of allPropertyNamesInTheBucket) { - properties[`aggregated.${propertyName}`] = JSON.stringify(properties[`aggregated.${propertyName}`]); + properties[`aggregated.${propertyName}`] = JSON.stringify(propertiesAsArray[`aggregated.${propertyName}`]); } return properties; @@ -220,7 +222,7 @@ export class BatchTelemetryReporter { * will return ['p1', 'p2', 'p3'] */ private static collectPropertyNamesFromAllEvents(bucket: any[]): string[] { - let propertyNamesSet = {}; + let propertyNamesSet: {[property: string]: boolean} = {}; for (const entry of bucket) { for (const key of Object.keys(entry)) { propertyNamesSet[key] = true; diff --git a/src/transformers/basePathTransformer.ts b/src/transformers/basePathTransformer.ts index 1b1b8c71b..9f795771b 100644 --- a/src/transformers/basePathTransformer.ts +++ b/src/transformers/basePathTransformer.ts @@ -4,46 +4,41 @@ import { DebugProtocol } from 'vscode-debugprotocol'; -import { ISetBreakpointsArgs, ILaunchRequestArgs, IAttachRequestArgs, IStackTraceResponseBody } from '../debugAdapterInterfaces'; +import { IResourceIdentifier } from '../chrome/internal/sources/resourceIdentifier'; +import { StackTracePresentation } from '../chrome/internal/stackTraces/stackTracePresentation'; +import { IComponent } from '../chrome/internal/features/feature'; +import { injectable } from 'inversify'; /** * Converts a local path from Code to a path on the target. */ -export class BasePathTransformer { - public launch(args: ILaunchRequestArgs): Promise { - return Promise.resolve(); - } - - public attach(args: IAttachRequestArgs): Promise { - return Promise.resolve(); - } - - public setBreakpoints(args: ISetBreakpointsArgs): ISetBreakpointsArgs { - return args; +@injectable() +export class BasePathTransformer implements IComponent { + public async install(): Promise { } public clearTargetContext(): void { } - public scriptParsed(scriptPath: string): Promise { + public scriptParsed(scriptPath: IResourceIdentifier): Promise { return Promise.resolve(scriptPath); } - public breakpointResolved(bp: DebugProtocol.Breakpoint, targetPath: string): string { + public breakpointResolved(_bp: DebugProtocol.Breakpoint, targetPath: IResourceIdentifier): IResourceIdentifier { return this.getClientPathFromTargetPath(targetPath) || targetPath; } - public stackTraceResponse(response: IStackTraceResponseBody): void { + public stackTraceResponse(_response: StackTracePresentation): void { } - public async fixSource(source: DebugProtocol.Source): Promise { + public async fixSource(_source: DebugProtocol.Source): Promise { } - public getTargetPathFromClientPath(clientPath: string): string { + public getTargetPathFromClientPath(clientPath: IResourceIdentifier): IResourceIdentifier { return clientPath; } - public getClientPathFromTargetPath(targetPath: string): string { + public getClientPathFromTargetPath(targetPath: IResourceIdentifier): IResourceIdentifier { return targetPath; } } diff --git a/src/transformers/baseSourceMapTransformer.ts b/src/transformers/baseSourceMapTransformer.ts index bf62aa0f6..f1fc10edf 100644 --- a/src/transformers/baseSourceMapTransformer.ts +++ b/src/transformers/baseSourceMapTransformer.ts @@ -2,19 +2,20 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import * as path from 'path'; import { DebugProtocol } from 'vscode-debugprotocol'; -import { ISetBreakpointsArgs, ILaunchRequestArgs, IAttachRequestArgs, - ISetBreakpointsResponseBody, IInternalStackTraceResponseBody, IScopesResponseBody, IInternalStackFrame } from '../debugAdapterInterfaces'; -import { MappedPosition, ISourcePathDetails } from '../sourceMaps/sourceMap'; +import { ILaunchRequestArgs, IAttachRequestArgs, + ISetBreakpointsResponseBody, IScopesResponseBody } from '../debugAdapterInterfaces'; +import { MappedPosition, ISourcePathDetails, SourceMap } from '../sourceMaps/sourceMap'; import { SourceMaps } from '../sourceMaps/sourceMaps'; -import * as utils from '../utils'; import { logger } from 'vscode-debugadapter'; -import { ISourceContainer } from '../chrome/chromeDebugAdapter'; -import * as nls from 'vscode-nls'; -const localize = nls.loadMessageBundle(); +import { ILoadedSource } from '../chrome/internal/sources/loadedSource'; +import { IComponent } from '../chrome/internal/features/feature'; +import { TYPES } from '../chrome/dependencyInjection.ts/types'; +import { ConnectedCDAConfiguration, IConnectedCDAConfiguration } from '../chrome/client/chromeDebugAdapter/cdaConfiguration'; +// import { injectable, inject } from 'inversify'; +import { inject } from 'inversify'; interface ISavedSetBreakpointsArgs { generatedPath: string; @@ -23,7 +24,7 @@ interface ISavedSetBreakpointsArgs { } export interface ISourceLocation { - source: DebugProtocol.Source; + source: ILoadedSource; line: number; column: number; isSourceMapped?: boolean; // compat with stack frame @@ -32,15 +33,12 @@ export interface ISourceLocation { /** * If sourcemaps are enabled, converts from source files on the client side to runtime files on the target side */ -export class BaseSourceMapTransformer { +export class BaseSourceMapTransformer implements IComponent { protected _sourceMaps: SourceMaps; - protected _sourceHandles: utils.ReverseHandles; private _enableSourceMapCaching: boolean; private _requestSeqToSetBreakpointsArgs: Map; private _allRuntimeScriptPaths: Set; - private _authoredPathsToMappedBPs: Map; - private _authoredPathsToClientBreakpointIds: Map; protected _preLoad = Promise.resolve(); private _processingNewSourceMap: Promise = Promise.resolve(); @@ -49,8 +47,14 @@ export class BaseSourceMapTransformer { protected _isVSClient = false; - constructor(sourceHandles: utils.ReverseHandles) { - this._sourceHandles = sourceHandles; + constructor(@inject(TYPES.ConnectedCDAConfiguration) configuration: IConnectedCDAConfiguration) { + this._enableSourceMapCaching = configuration.args.enableSourceMapCaching; + this.init(configuration.args); + this.isVSClient = configuration._clientCapabilities.clientID === 'visualstudio'; + } + + public install(_configuration: ConnectedCDAConfiguration): this { + return this; } public get sourceMaps(): SourceMaps { @@ -61,22 +65,14 @@ export class BaseSourceMapTransformer { this._isVSClient = newValue; } - public launch(args: ILaunchRequestArgs): void { - this.init(args); - } - - public attach(args: IAttachRequestArgs): void { - this.init(args); - } - protected init(args: ILaunchRequestArgs | IAttachRequestArgs): void { - if (args.sourceMaps) { + // Enable sourcemaps and async callstacks by default + const areSourceMapsEnabled = typeof args.sourceMaps === 'undefined' || args.sourceMaps; + if (areSourceMapsEnabled) { this._enableSourceMapCaching = args.enableSourceMapCaching; this._sourceMaps = new SourceMaps(args.pathMapping, args.sourceMapPathOverrides, this._enableSourceMapCaching); this._requestSeqToSetBreakpointsArgs = new Map(); this._allRuntimeScriptPaths = new Set(); - this._authoredPathsToMappedBPs = new Map(); - this._authoredPathsToClientBreakpointIds = new Map(); } } @@ -84,94 +80,6 @@ export class BaseSourceMapTransformer { this._allRuntimeScriptPaths = new Set(); } - /** - * Apply sourcemapping to the setBreakpoints request path/lines. - * Returns true if completed successfully, and setBreakpoint should continue. - */ - public setBreakpoints(args: ISetBreakpointsArgs, requestSeq: number, ids?: number[]): { args: ISetBreakpointsArgs, ids: number[] } { - if (!this._sourceMaps) { - return { args, ids }; - } - - const originalBPs = JSON.parse(JSON.stringify(args.breakpoints)); - - if (args.source.sourceReference) { - // If the source contents were inlined, then args.source has no path, but we - // stored it in the handle - const handle = this._sourceHandles.get(args.source.sourceReference); - if (handle && handle.mappedPath) { - args.source.path = handle.mappedPath; - } - } - - if (args.source.path) { - const argsPath = args.source.path; - const mappedPath = this._sourceMaps.getGeneratedPathFromAuthoredPath(argsPath); - if (mappedPath) { - logger.log(`SourceMaps.setBP: Mapped ${argsPath} to ${mappedPath}`); - args.authoredPath = argsPath; - args.source.path = mappedPath; - - // DebugProtocol doesn't send cols yet, but they need to be added from sourcemaps - args.breakpoints.forEach(bp => { - const { line, column = 0 } = bp; - const mapped = this._sourceMaps.mapToGenerated(argsPath, line, column); - if (mapped) { - logger.log(`SourceMaps.setBP: Mapped ${argsPath}:${line + 1}:${column + 1} to ${mappedPath}:${mapped.line + 1}:${mapped.column + 1}`); - bp.line = mapped.line; - bp.column = mapped.column; - } else { - logger.log(`SourceMaps.setBP: Mapped ${argsPath} but not line ${line + 1}, column 1`); - bp.column = column; // take 0 default if needed - } - }); - - this._authoredPathsToMappedBPs.set(argsPath, args.breakpoints); - - // Store the client breakpoint Ids for the mapped BPs as well - if (ids) { - this._authoredPathsToClientBreakpointIds.set(argsPath, ids); - } - - // Include BPs from other files that map to the same file. Ensure the current file's breakpoints go first - this._sourceMaps.allMappedSources(mappedPath).forEach(sourcePath => { - if (sourcePath === argsPath) { - return; - } - - const sourceBPs = this._authoredPathsToMappedBPs.get(sourcePath); - if (sourceBPs) { - // Don't modify the cached array - args.breakpoints = args.breakpoints.concat(sourceBPs); - - // We need to assign the client IDs we generated for the mapped breakpoints becuase the runtime IDs may change - // So make sure we concat the client ids to the ids array so that they get mapped to the respective breakpoints later - const clientBreakpointIds = this._authoredPathsToClientBreakpointIds.get(sourcePath); - if (ids) { - ids = ids.concat(clientBreakpointIds); - } - } - }); - } else if (this.isRuntimeScript(argsPath)) { - // It's a generated file which is loaded - logger.log(`SourceMaps.setBP: SourceMaps are enabled but ${argsPath} is a runtime script`); - } else { - // Source (or generated) file which is not loaded. - logger.log(`SourceMaps.setBP: ${argsPath} can't be resolved to a loaded script. It may just not be loaded yet.`); - } - } else { - // No source.path - } - - this._requestSeqToSetBreakpointsArgs.set(requestSeq, { - originalBPs, - authoredPath: args.authoredPath, - generatedPath: args.source.path - }); - - return { args, ids }; - } - /** * Apply sourcemapping back to authored files from the response */ @@ -200,67 +108,7 @@ export class BaseSourceMapTransformer { } } - /** - * Apply sourcemapping to the stacktrace response - */ - public async stackTraceResponse(response: IInternalStackTraceResponseBody): Promise { - if (this._sourceMaps) { - await this._processingNewSourceMap; - for (let stackFrame of response.stackFrames) { - await this.fixSourceLocation(stackFrame); - } - } - } - - public async fixSourceLocation(sourceLocation: ISourceLocation|IInternalStackFrame): Promise { - if (!this._sourceMaps) { - return; - } - - if (!sourceLocation.source) { - return; - } - - await this._processingNewSourceMap; - - const mapped = this._sourceMaps.mapToAuthored(sourceLocation.source.path, sourceLocation.line, sourceLocation.column); - if (mapped && utils.existsSync(mapped.source)) { - // Script was mapped to a valid path - sourceLocation.source.path = mapped.source; - sourceLocation.source.sourceReference = undefined; - sourceLocation.source.name = path.basename(mapped.source); - sourceLocation.line = mapped.line; - sourceLocation.column = mapped.column; - sourceLocation.isSourceMapped = true; - } else { - const inlinedSource = mapped && this._sourceMaps.sourceContentFor(mapped.source); - if (mapped && inlinedSource) { - // Clear the path and set the sourceReference - the client will ask for - // the source later and it will be returned from the sourcemap - sourceLocation.source.name = path.basename(mapped.source); - sourceLocation.source.path = mapped.source; - sourceLocation.source.sourceReference = this.getSourceReferenceForScriptPath(mapped.source, inlinedSource); - sourceLocation.source.origin = localize('origin.inlined.source.map', 'read-only inlined content from source map'); - sourceLocation.line = mapped.line; - sourceLocation.column = mapped.column; - sourceLocation.isSourceMapped = true; - } else if (utils.existsSync(sourceLocation.source.path)) { - // Script could not be mapped, but does exist on disk. Keep it and clear the sourceReference. - sourceLocation.source.sourceReference = undefined; - sourceLocation.source.origin = undefined; - } - } - } - - /** - * Get the existing handle for this script, identified by runtime scriptId, or create a new one - */ - private getSourceReferenceForScriptPath(mappedPath: string, contents: string): number { - return this._sourceHandles.lookupF(container => container.mappedPath === mappedPath) || - this._sourceHandles.create({ contents, mappedPath }); - } - - public async scriptParsed(pathToGenerated: string, sourceMapURL: string): Promise { + public async scriptParsed(pathToGenerated: string, sourceMapURL: string | undefined): Promise { if (this._sourceMaps) { this._allRuntimeScriptPaths.add(this.fixPathCasing(pathToGenerated)); @@ -276,7 +124,7 @@ export class BaseSourceMapTransformer { logger.log(`SourceMaps.scriptParsed: ${pathToGenerated} was just loaded and has mapped sources: ${JSON.stringify(sources) }`); } - return sources; + return processNewSourceMapP; } else { return null; } diff --git a/src/transformers/eagerSourceMapTransformer.ts b/src/transformers/eagerSourceMapTransformer.ts index c4ea62aad..4c5d6a3fa 100644 --- a/src/transformers/eagerSourceMapTransformer.ts +++ b/src/transformers/eagerSourceMapTransformer.ts @@ -19,7 +19,9 @@ export class EagerSourceMapTransformer extends BaseSourceMapTransformer { protected init(args: ILaunchRequestArgs | IAttachRequestArgs): void { super.init(args); - if (args.sourceMaps) { + // Enable sourcemaps and async callstacks by default + const areSourceMapsEnabled = typeof args.sourceMaps === 'undefined' || args.sourceMaps; + if (areSourceMapsEnabled) { const generatedCodeGlobs = args.outFiles ? args.outFiles : args.outDir ? @@ -43,10 +45,10 @@ export class EagerSourceMapTransformer extends BaseSourceMapTransformer { private discoverSourceMapForGeneratedScript(generatedScriptPath: string): Promise { return this.findSourceMapUrlInFile(generatedScriptPath) - .then(uri => { + .then(async uri => { if (uri) { logger.log(`SourceMaps: sourcemap url parsed from end of generated content: ${uri}`); - return this._sourceMaps.processNewSourceMap(generatedScriptPath, uri, this._isVSClient); + await this._sourceMaps.processNewSourceMap(generatedScriptPath, uri, this._isVSClient); } else { logger.log(`SourceMaps: no sourcemap url found in generated script: ${generatedScriptPath}`); return undefined; diff --git a/src/transformers/fallbackToClientPathTransformer.ts b/src/transformers/fallbackToClientPathTransformer.ts index b5bfe010a..854384297 100644 --- a/src/transformers/fallbackToClientPathTransformer.ts +++ b/src/transformers/fallbackToClientPathTransformer.ts @@ -4,20 +4,26 @@ import { logger } from 'vscode-debugadapter'; import { UrlPathTransformer } from './urlPathTransformer'; -import { ChromeDebugSession } from '../chrome/chromeDebugSession'; import * as ChromeUtils from '../chrome/chromeUtils'; +import { IResourceIdentifier } from '../chrome/internal/sources/resourceIdentifier'; +import { IConnectedCDAConfiguration } from '../chrome/client/chromeDebugAdapter/cdaConfiguration'; +import { inject } from 'inversify'; +import { TYPES } from '../chrome/dependencyInjection.ts/types'; /** * Converts a local path from Code to a path on the target. Uses the UrlPathTransforme logic and fallbacks to asking the client if neccesary */ export class FallbackToClientPathTransformer extends UrlPathTransformer { private static ASK_CLIENT_TO_MAP_URL_TO_FILE_PATH_TIMEOUT = 500; + private readonly _session = this.configuration._session; - constructor(private _session: ChromeDebugSession) { - super(); + constructor( + @inject(TYPES.ConnectedCDAConfiguration) private readonly configuration: IConnectedCDAConfiguration, + ) { + super(configuration); } - protected async targetUrlToClientPath(scriptUrl: string): Promise { + protected async targetUrlToClientPath(scriptUrl: IResourceIdentifier): Promise { // First try the default UrlPathTransformer transformation return super.targetUrlToClientPath(scriptUrl).then(filePath => { // If it returns a valid non empty file path then that should be a valid result, so we use that @@ -32,8 +38,8 @@ export class FallbackToClientPathTransformer extends UrlPathTransformer { }); } - private async requestClientToMapURLToFilePath(url: string): Promise { - return new Promise((resolve, reject) => { + private async requestClientToMapURLToFilePath(url: IResourceIdentifier): Promise { + return new Promise((resolve, reject) => { this._session.sendRequest('mapURLToFilePath', {url: url}, FallbackToClientPathTransformer.ASK_CLIENT_TO_MAP_URL_TO_FILE_PATH_TIMEOUT, response => { if (response.success) { logger.log(`The client responded that the url "${url}" maps to the file path "${response.body.filePath}"`); diff --git a/src/transformers/lineNumberTransformer.ts b/src/transformers/lineNumberTransformer.ts index c841dbc4f..441523ca8 100644 --- a/src/transformers/lineNumberTransformer.ts +++ b/src/transformers/lineNumberTransformer.ts @@ -4,25 +4,23 @@ import { DebugProtocol } from 'vscode-debugprotocol'; -import { ChromeDebugSession } from '../chrome/chromeDebugSession'; -import { IDebugTransformer, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody } from '../debugAdapterInterfaces'; +import { IDebugTransformer, ISetBreakpointsResponseBody, IScopesResponseBody, IStackTraceResponseBody } from '../debugAdapterInterfaces'; +import { ComponentConfiguration } from '../chrome/internal/features/feature'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../chrome/dependencyInjection.ts/types'; /** * Converts from 1 based lines/cols on the client side to 0 based lines/cols on the target side */ -export class LineColTransformer implements IDebugTransformer { - columnBreakpointsEnabled: boolean; - - constructor(private _session: ChromeDebugSession) { - } - - public setBreakpoints(args: DebugProtocol.SetBreakpointsArguments): DebugProtocol.SetBreakpointsArguments { - args.breakpoints.forEach(bp => this.convertClientLocationToDebugger(bp)); - if (!this.columnBreakpointsEnabled) { - args.breakpoints.forEach(bp => bp.column = undefined); - } - - return args; +@injectable() +export class LineColTransformer implements IDebugTransformer { + private columnBreakpointsEnabled: boolean; + private _clientToDebuggerLineNumberDifference: number; // Client line number - debugger line number. 0 if client line number is 0-based, 1 otherwise + private _clientToDebuggerColumnsDifference: number; // Similar to line numbers + + constructor(@inject(TYPES.ConnectedCDAConfiguration) configuration: ComponentConfiguration) { + this._clientToDebuggerLineNumberDifference = configuration._clientCapabilities.linesStartAt1 ? 1 : 0; + this._clientToDebuggerColumnsDifference = configuration._clientCapabilities.columnsStartAt1 ? 1 : 0; } public setBreakpointsResponse(response: ISetBreakpointsResponseBody): void { @@ -47,10 +45,6 @@ export class LineColTransformer implements IDebugTransformer { scopeResponse.scopes.forEach(scope => this.mapScopeLocations(scope)); } - public mappedExceptionStack(location: { line: number; column: number }): void { - this.convertDebuggerLocationToClient(location); - } - private mapScopeLocations(scope: DebugProtocol.Scope): void { this.convertDebuggerLocationToClient(scope); @@ -83,18 +77,18 @@ export class LineColTransformer implements IDebugTransformer { } public convertClientLineToDebugger(line: number): number { - return (this._session).convertClientLineToDebugger(line); + return line - this._clientToDebuggerLineNumberDifference; } public convertDebuggerLineToClient(line: number): number { - return (this._session).convertDebuggerLineToClient(line); + return line + this._clientToDebuggerLineNumberDifference; } public convertClientColumnToDebugger(column: number): number { - return (this._session).convertClientColumnToDebugger(column); + return column - this._clientToDebuggerColumnsDifference; } public convertDebuggerColumnToClient(column: number): number { - return (this._session).convertDebuggerColumnToClient(column); + return column + this._clientToDebuggerColumnsDifference; } } diff --git a/src/transformers/remotePathTransformer.ts b/src/transformers/remotePathTransformer.ts index 98123caa1..e159f9a8c 100644 --- a/src/transformers/remotePathTransformer.ts +++ b/src/transformers/remotePathTransformer.ts @@ -6,13 +6,17 @@ import * as fs from 'fs'; import * as path from 'path'; import { logger } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; -import { IAttachRequestArgs, ICommonRequestArgs, ILaunchRequestArgs, IStackTraceResponseBody } from '../debugAdapterInterfaces'; +import { ICommonRequestArgs } from '../debugAdapterInterfaces'; import * as errors from '../errors'; import { UrlPathTransformer } from '../transformers/urlPathTransformer'; import * as utils from '../utils'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); +import { IResourceIdentifier, parseResourceIdentifier } from '../chrome/internal/sources/resourceIdentifier'; +import { inject } from 'inversify'; +import { TYPES } from '../chrome/dependencyInjection.ts/types'; +import { ConnectedCDAConfiguration } from '../chrome/client/chromeDebugAdapter/cdaConfiguration'; /** * Converts a local path from Code to a path on the target. @@ -21,14 +25,9 @@ export class RemotePathTransformer extends UrlPathTransformer { private _localRoot: string; private _remoteRoot: string; - public async launch(args: ILaunchRequestArgs): Promise { - await super.launch(args); - return this.init(args); - } - - public async attach(args: IAttachRequestArgs): Promise { - await super.attach(args); - return this.init(args); + constructor(@inject(TYPES.ConnectedCDAConfiguration) configuration: ConnectedCDAConfiguration) { + super(configuration); + this.init(configuration.args); } private async init(args: ICommonRequestArgs): Promise { @@ -62,61 +61,57 @@ export class RemotePathTransformer extends UrlPathTransformer { return localRootP; } - public async scriptParsed(scriptPath: string): Promise { + public async scriptParsed(scriptPath: IResourceIdentifier): Promise { scriptPath = await super.scriptParsed(scriptPath); scriptPath = this.getClientPathFromTargetPath(scriptPath) || scriptPath; return scriptPath; } - public async stackTraceResponse(response: IStackTraceResponseBody): Promise { - await Promise.all(response.stackFrames.map(stackFrame => this.fixSource(stackFrame.source))); - } - public async fixSource(source: DebugProtocol.Source): Promise { await super.fixSource(source); - const remotePath = source && source.path; - if (remotePath) { + if (source && source.path) { + const remotePath = parseResourceIdentifier(source && source.path); const localPath = this.getClientPathFromTargetPath(remotePath) || remotePath; - if (utils.existsSync(localPath)) { - source.path = localPath; + if (utils.existsSync(localPath.canonicalized)) { + source.path = localPath.canonicalized; source.sourceReference = undefined; source.origin = undefined; } } } - private shouldMapPaths(remotePath: string): boolean { + private shouldMapPaths(remotePath: IResourceIdentifier): boolean { // Map paths only if localRoot/remoteRoot are set, and the remote path is absolute on some system - return !!this._localRoot && !!this._remoteRoot && (path.posix.isAbsolute(remotePath) || path.win32.isAbsolute(remotePath)); + return !!this._localRoot && !!this._remoteRoot && (path.posix.isAbsolute(remotePath.canonicalized) || path.win32.isAbsolute(remotePath.canonicalized)); } - public getClientPathFromTargetPath(remotePath: string): string { + public getClientPathFromTargetPath(remotePath: IResourceIdentifier): IResourceIdentifier { remotePath = super.getClientPathFromTargetPath(remotePath) || remotePath; // Map as non-file-uri because remoteRoot won't expect a file uri - remotePath = utils.fileUrlToPath(remotePath); - if (!this.shouldMapPaths(remotePath)) return ''; + remotePath = parseResourceIdentifier(utils.fileUrlToPath(remotePath.canonicalized)); + if (!this.shouldMapPaths(remotePath)) return parseResourceIdentifier(''); - const relPath = relative(this._remoteRoot, remotePath); + const relPath = relative(this._remoteRoot, remotePath.canonicalized); let localPath = join(this._localRoot, relPath); localPath = utils.fixDriveLetterAndSlashes(localPath); logger.log(`Mapped remoteToLocal: ${remotePath} -> ${localPath}`); - return localPath; + return parseResourceIdentifier(localPath); } - public getTargetPathFromClientPath(localPath: string): string { + public getTargetPathFromClientPath(localPath: IResourceIdentifier): IResourceIdentifier { localPath = super.getTargetPathFromClientPath(localPath) || localPath; if (!this.shouldMapPaths(localPath)) return localPath; - const relPath = relative(this._localRoot, localPath); + const relPath = relative(this._localRoot, localPath.canonicalized); let remotePath = join(this._remoteRoot, relPath); remotePath = utils.fixDriveLetterAndSlashes(remotePath, /*uppercaseDriveLetter=*/true); logger.log(`Mapped localToRemote: ${localPath} -> ${remotePath}`); - return remotePath; + return parseResourceIdentifier(remotePath); } } diff --git a/src/transformers/urlPathTransformer.ts b/src/transformers/urlPathTransformer.ts index 12dbac7dd..f913d4ed5 100644 --- a/src/transformers/urlPathTransformer.ts +++ b/src/transformers/urlPathTransformer.ts @@ -4,73 +4,48 @@ import { BasePathTransformer } from './basePathTransformer'; -import { ISetBreakpointsArgs, ILaunchRequestArgs, IAttachRequestArgs, IStackTraceResponseBody, IPathMapping } from '../debugAdapterInterfaces'; -import * as utils from '../utils'; +import { IPathMapping } from '../debugAdapterInterfaces'; import { logger } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; import * as ChromeUtils from '../chrome/chromeUtils'; import * as path from 'path'; +import { newResourceIdentifierMap, IResourceIdentifier } from '../chrome/internal/sources/resourceIdentifier'; +import { parseResourceIdentifier } from '..'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../chrome/dependencyInjection.ts/types'; +import { IConnectedCDAConfiguration } from '../chrome/client/chromeDebugAdapter/cdaConfiguration'; /** * Converts a local path from Code to a path on the target. */ +@injectable() export class UrlPathTransformer extends BasePathTransformer { private _pathMapping: IPathMapping; - private _clientPathToTargetUrl = new Map(); - private _targetUrlToClientPath = new Map(); + private _clientPathToTargetUrl = newResourceIdentifierMap(); + private _targetUrlToClientPath = newResourceIdentifierMap(); - public launch(args: ILaunchRequestArgs): Promise { - this._pathMapping = args.pathMapping; - return super.launch(args); - } - - public attach(args: IAttachRequestArgs): Promise { - this._pathMapping = args.pathMapping; - return super.attach(args); - } - - public setBreakpoints(args: ISetBreakpointsArgs): ISetBreakpointsArgs { - if (!args.source.path) { - // sourceReference script, nothing to do - return args; - } - - if (utils.isURL(args.source.path)) { - // already a url, use as-is - logger.log(`Paths.setBP: ${args.source.path} is already a URL`); - return args; - } - - const path = utils.canonicalizeUrl(args.source.path); - const url = this.getTargetPathFromClientPath(path); - if (url) { - args.source.path = url; - logger.log(`Paths.setBP: Resolved ${path} to ${args.source.path}`); - return args; - } else { - logger.log(`Paths.setBP: No target url cached yet for client path: ${path}.`); - args.source.path = path; - return args; - } + constructor(@inject(TYPES.ConnectedCDAConfiguration) configuration: IConnectedCDAConfiguration) { + super(); + this._pathMapping = configuration.args.pathMapping; } public clearTargetContext(): void { - this._clientPathToTargetUrl = new Map(); - this._targetUrlToClientPath = new Map(); + this._clientPathToTargetUrl = newResourceIdentifierMap(); + this._targetUrlToClientPath = newResourceIdentifierMap(); } - public async scriptParsed(scriptUrl: string): Promise { + public async scriptParsed(scriptUrl: IResourceIdentifier): Promise { const clientPath = await this.targetUrlToClientPath(scriptUrl); if (!clientPath) { // It's expected that eval scripts (eval://) won't be resolved - if (!scriptUrl.startsWith(ChromeUtils.EVAL_NAME_PREFIX)) { + if (!scriptUrl.canonicalized.startsWith(ChromeUtils.EVAL_NAME_PREFIX)) { logger.log(`Paths.scriptParsed: could not resolve ${scriptUrl} to a file with pathMapping/webRoot: ${JSON.stringify(this._pathMapping)}. It may be external or served directly from the server's memory (and that's OK).`); } } else { logger.log(`Paths.scriptParsed: resolved ${scriptUrl} to ${clientPath}. pathMapping/webroot: ${JSON.stringify(this._pathMapping)}`); - const canonicalizedClientPath = utils.canonicalizeUrl(clientPath); + const canonicalizedClientPath = clientPath; this._clientPathToTargetUrl.set(canonicalizedClientPath, scriptUrl); this._targetUrlToClientPath.set(scriptUrl, clientPath); @@ -80,43 +55,40 @@ export class UrlPathTransformer extends BasePathTransformer { return Promise.resolve(scriptUrl); } - public async stackTraceResponse(response: IStackTraceResponseBody): Promise { - await Promise.all(response.stackFrames.map(frame => this.fixSource(frame.source))); - } - public async fixSource(source: DebugProtocol.Source): Promise { + // TODO DIEGO: Delete this method if (source && source.path) { // Try to resolve the url to a path in the workspace. If it's not in the workspace, // just use the script.url as-is. It will be resolved or cleared by the SourceMapTransformer. - const clientPath = this.getClientPathFromTargetPath(source.path) || - await this.targetUrlToClientPath(source.path); + const clientPath = this.getClientPathFromTargetPath(parseResourceIdentifier(source.path)) || + await this.targetUrlToClientPath(parseResourceIdentifier(source.path)); // Incoming stackFrames have sourceReference and path set. If the path was resolved to a file in the workspace, // clear the sourceReference since it's not needed. if (clientPath) { - source.path = clientPath; + source.path = clientPath.canonicalized; source.sourceReference = undefined; source.origin = undefined; - source.name = path.basename(clientPath); + source.name = path.basename(clientPath.canonicalized); } } } - public getTargetPathFromClientPath(clientPath: string): string { + public getTargetPathFromClientPath(clientPath: IResourceIdentifier): IResourceIdentifier { // If it's already a URL, skip the Map - return path.isAbsolute(clientPath) ? - this._clientPathToTargetUrl.get(utils.canonicalizeUrl(clientPath)) : + return path.isAbsolute(clientPath.canonicalized) ? + this._clientPathToTargetUrl.get(clientPath) : clientPath; } - public getClientPathFromTargetPath(targetPath: string): string { - return this._targetUrlToClientPath.get(targetPath); + public getClientPathFromTargetPath(targetPath: IResourceIdentifier): IResourceIdentifier { + return this._targetUrlToClientPath.tryGetting(targetPath); } /** * Overridable for VS to ask Client to resolve path */ - protected async targetUrlToClientPath(scriptUrl: string): Promise { - return Promise.resolve(ChromeUtils.targetUrlToClientPath(scriptUrl, this._pathMapping)); + protected async targetUrlToClientPath(scriptUrl: IResourceIdentifier): Promise { + return Promise.resolve(parseResourceIdentifier(ChromeUtils.targetUrlToClientPath(scriptUrl.canonicalized, this._pathMapping))); } } diff --git a/src/typeUtils.ts b/src/typeUtils.ts new file mode 100644 index 000000000..f7bec1363 --- /dev/null +++ b/src/typeUtils.ts @@ -0,0 +1,27 @@ +export type MakePropertyRequired = T & { [P in K]-?: T[K] }; +export type RemoveProperty = Pick>; +export type AllRequired = { [P in keyof T]-?: T[P] }; +export type AllOptional = { [P in keyof T]+?: T[P] }; + +// export type Omit = Pick>; + +// interface A { +// a?: string; +// b?: number; +// c: object; +// } + +// const laaf: MakePropertyRequired; +// laaf. + +// const lala: RemoveProperty; +// lala. +// let obj: A = null as A; +// obj.b++; + +// let objc: Record<'a' | 'b', A>; +// objc. + +export function isIterable(possiblyIterable: any): possiblyIterable is Iterable { + return possiblyIterable && typeof possiblyIterable[Symbol.iterator] === 'function'; +} \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 56185f6da..4a8b93a54 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -45,7 +45,7 @@ export function existsSync(path: string): boolean { * Checks asynchronously if a path exists on the disk. */ export function existsAsync(path: string): Promise { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { try { fs.access(path, (err) => { resolve(err ? false : true); @@ -93,7 +93,7 @@ export function retryAsync(fn: () => Promise, timeoutMs: number, intervalDe return fn().catch( e => { if (Date.now() - startTime < (timeoutMs - intervalDelay)) { - return promiseTimeout(null, intervalDelay).then(tryUntilTimeout); + return promiseTimeout(undefined, intervalDelay).then(tryUntilTimeout); } else { return errP(e); } @@ -448,7 +448,7 @@ export function multiGlob(patterns: string[], opts?: any): Promise { } } - let array = []; + let array: string[] = []; set.forEach(v => array.push(fixDriveLetterAndSlashes(v))); return array; }); @@ -509,7 +509,7 @@ export function pathToRegex(aPath: string): string { // If we should resolve paths in a case-sensitive way, we still need to set the BP for either an // upper or lowercased drive letter if (caseSensitivePaths) { - aPath = aPath.replace(/(^|file:\\\/\\\/\\\/)([a-zA-Z]):/g, (match, prefix, letter) => { + aPath = aPath.replace(/(^|file:\\\/\\\/\\\/)([a-zA-Z]):/g, (_match, prefix, letter) => { const u = letter.toUpperCase(); const l = letter.toLowerCase(); return `${prefix}[${u}${l}]:`; @@ -590,7 +590,7 @@ export function getLine(msg: string, n = 0): string { return msg.split('\n')[n]; } -export function firstLine(msg: string): string { +export function firstLine(msg: string | undefined): string { return getLine(msg || ''); } @@ -603,7 +603,7 @@ export function toVoidP(p: Promise): Promise { } export interface PromiseDefer { - promise: Promise; + readonly promise: Promise; resolve: (value?: T | PromiseLike) => void; reject: (reason?: any) => void; } @@ -611,7 +611,7 @@ export interface PromiseDefer { export function promiseDefer(): PromiseDefer { let resolveCallback; let rejectCallback; - const promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { resolveCallback = resolve; rejectCallback = reject; }); @@ -655,3 +655,19 @@ export function fillErrorDetails(properties: IExecutionResultTelemetryProperties properties.exceptionId = e.id.toString(); } } + +export function makeUnique(elements: T[]): T[] { + return Array.from(new Set(elements)); +} + +export function adaptToSinglIntoToMulti(thisObject: object, toSingle: (single: T) => R): (multi: T[]) => R[] { + return (multi: T[]) => multi.map(single => toSingle.call(thisObject, single)); +} + +export function asyncAdaptToSinglIntoToMulti(thisObject: object, toSingle: (single: T) => Promise): (multi: T[]) => Promise { + return (multi: T[]) => Promise.all(multi.map(single => toSingle.call(thisObject, single))); +} + +export function defaultIfUndefined(value: T | undefined, defaultValue: T): T { + return value !== undefined ? value : defaultValue; +} \ No newline at end of file diff --git a/src/validation.ts b/src/validation.ts new file mode 100644 index 000000000..0d2ee692a --- /dev/null +++ b/src/validation.ts @@ -0,0 +1,14 @@ +export function zeroOrPositive(name: string, value: number) { + if (value < 0) { + breakWhileDebugging(); + throw new Error(`Expected ${name} to be either zero or a positive number and instead it was ${value}`); + } +} + +/** Used for debugging while developing to automatically break when something unexpected happened */ +export function breakWhileDebugging() { + if (process.env.BREAK_WHILE_DEBUGGING === 'true') { + // tslint:disable-next-line:no-debugger + debugger; + } +} \ No newline at end of file diff --git a/test/chrome/chromeDebugAdapter.test.ts b/test/chrome/chromeDebugAdapter.test.ts index 644ef3202..f7054261a 100644 --- a/test/chrome/chromeDebugAdapter.test.ts +++ b/test/chrome/chromeDebugAdapter.test.ts @@ -25,7 +25,7 @@ import * as utils from '../../src/utils'; import * as fs from 'fs'; /** Not mocked - use for type only */ -import {ChromeDebugAdapter as _ChromeDebugAdapter } from '../../src/chrome/chromeDebugAdapter'; +import {ChromeDebugLogic as _ChromeDebugAdapter } from '../../src/chrome/chromeDebugAdapter'; import { InitializedEvent, LoadedSourceEvent, Source, BreakpointEvent } from 'vscode-debugadapter/lib/debugSession'; import { Version, TargetVersions } from '../../src'; diff --git a/test/testDebug/testDebug.ts b/test/testDebug/testDebug.ts new file mode 100644 index 000000000..7e93daaf9 --- /dev/null +++ b/test/testDebug/testDebug.ts @@ -0,0 +1,40 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + +import { ChromeDebugSession, logger, UrlPathTransformer, BaseSourceMapTransformer, telemetry } from '../../src/index'; +import * as path from 'path'; +import * as os from 'os'; + +import { TestDebugAdapter } from './testDebugAdapter'; +import { OnlyProvideCustomLauncherExtensibilityPoints } from '../../src/chrome/extensibility/extensibilityPoints'; +import { TestDebugeeLauncher } from './testDebugeeLauncher'; +import { TestDebugeeRunner } from './testDebugeeRunner'; + +const EXTENSION_NAME = 'debugger-for-chrome'; + +// Start a ChromeDebugSession configured to only match 'page' targets, which are Chrome tabs. +// Cast because DebugSession is declared twice - in this repo's vscode-debugadapter, and that of -core... TODO +const logFilePath = path.resolve(os.tmpdir(), 'vscode-chrome-debug.txt'); +ChromeDebugSession.run(ChromeDebugSession.getSession( + { + adapter: TestDebugAdapter, + extensionName: EXTENSION_NAME, + extensibilityPoints: new OnlyProvideCustomLauncherExtensibilityPoints(TestDebugeeLauncher, TestDebugeeRunner, logFilePath), + logFilePath: logFilePath, + // targetFilter: defaultTargetFilter, + + pathTransformer: UrlPathTransformer, + sourceMapTransformer: BaseSourceMapTransformer, + })); + +/* tslint:disable:no-var-requires */ +const debugAdapterVersion = require('../../../package.json').version; +logger.log(EXTENSION_NAME + ': ' + debugAdapterVersion); + +/* __GDPR__FRAGMENT__ + "DebugCommonProperties" : { + "Versions.DebugAdapter" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } +*/ +telemetry.telemetry.addCustomGlobalProperty({ 'Versions.DebugAdapter': debugAdapterVersion }); diff --git a/test/testDebug/testDebugAdapter.ts b/test/testDebug/testDebugAdapter.ts new file mode 100644 index 000000000..2710e3b97 --- /dev/null +++ b/test/testDebug/testDebugAdapter.ts @@ -0,0 +1,4 @@ +import { ChromeDebugAdapter as CoreDebugAdapter } from '../../src/index'; + +export class TestDebugAdapter extends CoreDebugAdapter { +} \ No newline at end of file diff --git a/test/testDebug/testDebugeeLauncher.ts b/test/testDebug/testDebugeeLauncher.ts new file mode 100644 index 000000000..354a3e428 --- /dev/null +++ b/test/testDebug/testDebugeeLauncher.ts @@ -0,0 +1,12 @@ +import { IDebuggeeLauncher, ILaunchRequestArgs, ILaunchResult, ITelemetryPropertyCollector } from '../../src'; + +export class TestDebugeeLauncher implements IDebuggeeLauncher { + public async launch(_args: ILaunchRequestArgs, _telemetryPropertyCollector: ITelemetryPropertyCollector): Promise { + return { + + }; + } + + public async waitForDebugeeToBeReady(): Promise { + } +} \ No newline at end of file diff --git a/test/testDebug/testDebugeeRunner.ts b/test/testDebug/testDebugeeRunner.ts new file mode 100644 index 000000000..2c76f5eaa --- /dev/null +++ b/test/testDebug/testDebugeeRunner.ts @@ -0,0 +1,10 @@ +import { ITelemetryPropertyCollector } from '../../src'; +import { IDebuggeeRunner } from '../../src/chrome/debugee/debugeeLauncher'; +import { CDTPDiagnostics } from '../../src/chrome/target/cdtpDiagnostics'; + +export class TestDebugeeRunner implements IDebuggeeRunner { + public async run(_telemetryPropertyCollector: ITelemetryPropertyCollector): Promise { + } + + constructor(readonly _chrome: CDTPDiagnostics) { } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 65d4a95a0..98d82aad4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,24 +2,33 @@ "compilerOptions": { "module": "commonjs", "moduleResolution": "node", - "target": "es2015", + "target": "ES6", "sourceMap": true, "outDir": "out", "declaration": true, - + "types": [ + "reflect-metadata" + ], + "experimentalDecorators": true, + "emitDecoratorMetadata": true, "noUnusedLocals": true, "noImplicitThis": true, "noFallthroughCasesInSwitch": true, "noImplicitReturns": true, + "noUnusedParameters": true, + "strictFunctionTypes": true, + "noImplicitAny": true, + "strictNullChecks": false, + "strictPropertyInitialization": false, "lib": [ - "es2015" - ], - - "experimentalDecorators": true + "es6", + "dom" + ] }, "include": [ "src/**/*.ts", - "test/**/*.ts", + "test/testDebug/**/*.ts", + "test-DoNot-/**/*.ts", "node_modules/@types/**/*.ts" ] -} +} \ No newline at end of file From 7b2c43dd6e73aeb1482e8b0d44394a34463c4dc6 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 8 Jan 2019 21:05:26 -0800 Subject: [PATCH 02/23] Loaded Scripts should show the runtime source, not the dev source on disk --- src/chrome/client/eventSender.ts | 1 - .../internal/sources/features/notifyClientOfLoadedSources.ts | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/chrome/client/eventSender.ts b/src/chrome/client/eventSender.ts index fae86a964..dafe57c50 100644 --- a/src/chrome/client/eventSender.ts +++ b/src/chrome/client/eventSender.ts @@ -64,7 +64,6 @@ export class EventSender implements IEventsToClientReporter { } public async sendSourceWasLoaded(params: SourceWasLoadedParameters): Promise { - // TODO DIEGO: Should we be using the source tree instead of the source here? const clientSource = await this._internalToClient.toSource(params.source); const event = new LoadedSourceEvent(params.reason, clientSource); diff --git a/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts index da00dc7a9..e2b62f907 100644 --- a/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts +++ b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts @@ -64,10 +64,7 @@ export class NotifyClientOfLoadedSources implements IComponent { telemetry.reportEvent('LoadedSourceEventError', { issue: 'Unknown reason', reason: loadedSourceEventReason }); } - // TODO DIEGO: Should we be using the source tree here? - // const sourceTree = this._sourcesLogic.getLoadedSourcesTree(script.script); - - this._eventsToClientReporter.sendSourceWasLoaded({ reason: loadedSourceEventReason, source: script.developmentSource }); + this._eventsToClientReporter.sendSourceWasLoaded({ reason: loadedSourceEventReason, source: script.runtimeSource }); } constructor( From 2d478a8d0cafa9910647e3922b25bac555823fa7 Mon Sep 17 00:00:00 2001 From: D Date: Thu, 10 Jan 2019 10:25:02 -0800 Subject: [PATCH 03/23] Disable logger --- src/chrome/dependencyInjection.ts/bind.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chrome/dependencyInjection.ts/bind.ts b/src/chrome/dependencyInjection.ts/bind.ts index 46594fa47..cd0fb8cc5 100644 --- a/src/chrome/dependencyInjection.ts/bind.ts +++ b/src/chrome/dependencyInjection.ts/bind.ts @@ -35,7 +35,6 @@ import { ChromeDebugLogic } from '../chromeDebugAdapter'; import { CDTPOnScriptParsedEventProvider, IScriptParsedProvider } from '../target/cdtpOnScriptParsedEventProvider'; import { CDTPDebuggerEventsProvider, ICDTPDebuggerEventsProvider } from '../target/cdtpDebuggerEventsProvider'; import { ITargetBreakpoints, CDTPTargetBreakpoints } from '../target/cdtpTargetBreakpoints'; -import { MethodsCalledLogger } from '../logging/methodsCalledLogger'; export function bindAll(di: Container) { bind(di, TYPES.IDOMInstrumentationBreakpoints, CDTPDOMDebugger); @@ -87,6 +86,7 @@ export function bindAll(di: Container) { function bind(container: Container, serviceIdentifier: interfaces.ServiceIdentifier, newable: interfaces.Newable): void { container.bind(serviceIdentifier).to(newable).inSingletonScope().onActivation((_context, object) => { - return new MethodsCalledLogger(object, serviceIdentifier.toString()).wrapped(); + return object; + /// return new MethodsCalledLogger(object, serviceIdentifier.toString()).wrapped(); }); } From ab9c62a088e1a2c159d50063220460dc6eeb21c7 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 11 Jan 2019 18:13:46 +0000 Subject: [PATCH 04/23] Fix .scripts command --- src/chrome/chromeDebugAdapter.ts | 2 +- .../sources/features/dotScriptsCommand.ts | 42 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/chrome/chromeDebugAdapter.ts b/src/chrome/chromeDebugAdapter.ts index 7d87cd2e3..815ed6962 100644 --- a/src/chrome/chromeDebugAdapter.ts +++ b/src/chrome/chromeDebugAdapter.ts @@ -47,7 +47,7 @@ import { CodeFlowStackTrace } from './internal/stackTraces/stackTrace'; import { IResourceIdentifier } from './internal/sources/resourceIdentifier'; import { FormattedExceptionParser } from './internal/formattedExceptionParser'; import { DeleteMeScriptsRegistry } from './internal/scripts/scriptsRegistry'; -import { ExceptionThrownEventProvider } from './target/ExceptionThrownEventProvider'; +import { ExceptionThrownEventProvider } from './target/exceptionThrownEventProvider'; import { ExecutionContextEventsProvider } from './target/executionContextEventsProvider'; import { IInspectDebugeeState } from './target/inspectDebugeeState'; import { IUpdateDebugeeState } from './target/updateDebugeeState'; diff --git a/src/chrome/internal/sources/features/dotScriptsCommand.ts b/src/chrome/internal/sources/features/dotScriptsCommand.ts index 8e7e5eb2b..db0cf0b54 100644 --- a/src/chrome/internal/sources/features/dotScriptsCommand.ts +++ b/src/chrome/internal/sources/features/dotScriptsCommand.ts @@ -1,17 +1,21 @@ -import { IScript } from '../../scripts/script'; - +import { inject, injectable } from 'inversify'; import { parseResourceIdentifier } from '../../../..'; - +import { BaseSourceMapTransformer } from '../../../../transformers/baseSourceMapTransformer'; import { IEventsToClientReporter } from '../../../client/eventSender'; import { determineOrderingOfStrings } from '../../../collections/utilities'; -import { inject, injectable } from 'inversify'; -import { BaseSourceMapTransformer } from '../../../../transformers/baseSourceMapTransformer'; -import { DeleteMeScriptsRegistry } from '../../scripts/scriptsRegistry'; import { TYPES } from '../../../dependencyInjection.ts/types'; import { IScriptSources } from '../../../target/cdtpDebugger'; +import { CDTPScriptsRegistry } from '../../../target/cdtpScriptsRegistry'; +import { IScript } from '../../scripts/script'; @injectable() export class DotScriptCommand { + constructor( + @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, + @inject(TYPES.IScriptSources) private readonly _scriptSources: IScriptSources, + @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter, + @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry) { } + /** * Handle the .scripts command, which can be used as `.scripts` to return a list of all script details, * or `.scripts ` to show the contents of the given script. @@ -20,7 +24,7 @@ export class DotScriptCommand { let outputStringP: Promise; if (scriptsRest) { // `.scripts ` was used, look up the script by url - const requestedScript = this._scriptsLogic.getScriptsByPath(parseResourceIdentifier(scriptsRest)); + const requestedScript = this._scriptsRegistry.getScriptsByPath(parseResourceIdentifier(scriptsRest)); if (requestedScript) { outputStringP = this._scriptSources.getScriptSource(requestedScript[0]) .then(result => { @@ -42,27 +46,25 @@ export class DotScriptCommand { } private async getAllScriptsString(): Promise { - const scripts = (await this._scriptsLogic.getAllScripts()).sort((left, script) => determineOrderingOfStrings(left.url, script.url)); + const scripts = (await Promise.all([ + ...this._scriptsRegistry.getAllScripts() + ])).sort((left, script) => determineOrderingOfStrings(left.url, script.url)); + const scriptsPrinted = await Promise.all(scripts.map(script => this.getOneScriptString(script))); return scriptsPrinted.join('\n'); } - private getOneScriptString(script: IScript): Promise { + private async getOneScriptString(script: IScript): Promise { let result = '› ' + script.runtimeSource.identifier.textRepresentation; const clientPath = script.developmentSource.identifier.textRepresentation; if (script.developmentSource !== script.runtimeSource) result += ` (${clientPath})`; - return this._sourceMapTransformer.allSourcePathDetails(script.developmentSource.identifier.canonicalized).then(sourcePathDetails => { - let mappedSourcesStr = sourcePathDetails.map(details => ` - ${details.originalPath} (${details.inferredPath})`).join('\n'); - if (sourcePathDetails.length) mappedSourcesStr = '\n' + mappedSourcesStr; + const sourcePathDetails = await this._sourceMapTransformer.allSourcePathDetails(script.runtimeSource.identifier.canonicalized); + let mappedSourcesStr = sourcePathDetails.map(details => ` - ${details.originalPath} (${details.inferredPath})`).join('\n'); + if (sourcePathDetails.length) { + mappedSourcesStr = '\n' + mappedSourcesStr; + } - return result + mappedSourcesStr; - }); + return result + mappedSourcesStr; } - - constructor( - @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, - @inject(TYPES.DeleteMeScriptsRegistry) private readonly _scriptsLogic: DeleteMeScriptsRegistry, - @inject(TYPES.IScriptSources) private readonly _scriptSources: IScriptSources, - @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter) { } } From 6b49077ddc7e2eb87656cd5a7163a199c8213b52 Mon Sep 17 00:00:00 2001 From: digeff Date: Wed, 9 Jan 2019 09:43:03 -0800 Subject: [PATCH 05/23] Refactor the target/CDTP model --- package-lock.json | 1692 ++++++++--------- src/chrome/breakOnLoadHelper.ts | 18 +- src/chrome/cdtpDebuggee/cdtpPrimitives.ts | 11 + .../cdtpConsoleEventsProvider.ts | 79 + .../cdtpDebuggeeExecutionEventsProvider.ts | 101 + .../cdtpExceptionThrownEventsProvider.ts | 67 + .../cdtpExecutionContextEventsProvider.ts | 28 + .../eventsProviders/cdtpLogEventsProvider.ts | 62 + .../cdtpOnScriptParsedEventProvider.ts | 116 ++ .../cdtpDebuggee/features/CDTPSchema.ts | 9 + .../features/cdtpAsyncDebuggingConfigurer.ts | 21 + .../cdtpBlackboxPatternsConfigurer.ts | 30 + .../cdtpBreakpointFeaturesSupport.ts} | 20 +- .../features/cdtpBrowserNavigator.ts | 35 + .../cdtpDOMInstrumentationBreakpoints.ts | 26 + .../cdtpDebugeeExecutionController.ts | 23 + .../cdtpDebugeeRuntimeVersionProvider.ts | 26 + .../features/cdtpDebugeeSteppingController.ts | 43 + .../features/cdtpDebuggeeBreakpoints.ts | 136 ++ .../features/cdtpInspectDebugeeState.ts | 78 + .../features/cdtpNetworkCacheConfiguration.ts | 22 + .../cdtpPauseOnExceptionsConfigurer.ts | 36 + .../features/cdtpPausedOverlay.ts | 24 + .../cdtpDebuggee/features/cdtpRuntime.ts | 25 + .../features/cdtpScriptSourcesRetriever.ts | 25 + .../features/cdtpUpdateDebugeeState.ts | 35 + .../infrastructure}/cdtpDiagnosticsModule.ts | 21 +- .../infrastructure/cdtpDomainsEnabler.ts | 103 + .../protocolParsers/cdtpLocationParser.ts | 28 + .../protocolParsers/cdtpStackTraceParser.ts | 33 + .../registries/cdtpBreakpointIdsRegistry.ts | 30 + .../registries/cdtpCallFrameRegistry.ts | 18 + .../registries/cdtpScriptsRegistry.ts | 86 + src/chrome/chromeConnection.ts | 7 +- src/chrome/chromeDebugAdapter.ts | 102 +- src/chrome/chromeTargetDiscoveryStrategy.ts | 24 +- src/chrome/chromeUtils.ts | 10 +- .../client/chromeDebugAdapter/connectedCDA.ts | 12 +- .../chromeDebugAdapter/unconnectedCDA.ts | 7 +- src/chrome/client/eventSender.ts | 4 +- src/chrome/collections/mapUsingProjection.ts | 5 + src/chrome/collections/utilities.ts | 8 + src/chrome/collections/validatedMap.ts | 11 +- src/chrome/communication/internalChannels.ts | 2 +- src/chrome/communication/targetChannels.ts | 3 +- src/chrome/consoleHelper.ts | 12 +- .../debugeeLauncher.ts | 0 src/chrome/dependencyInjection.ts/bind.ts | 122 +- src/chrome/dependencyInjection.ts/types.ts | 11 +- .../extensibility/extensibilityPoints.ts | 2 +- src/chrome/internal/breakpoints/bpRecipie.ts | 51 +- ...gic.ts => bpRecipieAtLoadedSourceLogic.ts} | 30 +- .../internal/breakpoints/bpRecipieStatus.ts | 6 +- src/chrome/internal/breakpoints/bpRecipies.ts | 2 +- .../internal/breakpoints/breakpointsLogic.ts | 14 +- .../breakpoints/breakpointsRegistry.ts | 8 +- .../clientCurrentBPRecipiesRegistry.ts | 2 +- .../features/hitCountBreakpoints.ts | 11 +- .../features/pauseScriptLoadsToSetBPs.ts | 21 +- .../features/reAddBPsWhenSourceIsLoaded.ts | 4 +- .../internal/domains/supportedDomains.ts | 7 +- .../internal/exceptions/pauseOnException.ts | 6 +- src/chrome/internal/features/skipFiles.ts | 20 +- src/chrome/internal/features/smartStep.ts | 2 +- .../features/takeProperActionOnPausedEvent.ts | 10 +- src/chrome/internal/scripts/script.ts | 13 +- .../internal/scripts/scriptsRegistry.ts | 23 +- .../sources/features/dotScriptsCommand.ts | 4 +- .../features/notifyClientOfLoadedSources.ts | 2 +- .../sources/resourceIdentifierSubtypes.ts | 3 + src/chrome/internal/sources/sourceResolver.ts | 2 +- .../internal/sources/sourcesTextLogic.ts | 4 +- .../internal/sources/sourcesTreeNodeLogic.ts | 2 +- src/chrome/internal/stackTraces/callFrame.ts | 17 +- src/chrome/internal/stackTraces/scopes.ts | 4 +- .../internal/stackTraces/stackTracesLogic.ts | 6 +- .../stepping/features/asyncStepping.ts | 11 +- .../stepping/features/syncStepping.ts | 9 +- src/chrome/stoppedEvent.ts | 4 +- src/chrome/target/addSourceUriToExpression.ts | 15 - src/chrome/target/breakpointIdRegistry.ts | 31 - src/chrome/target/callFrameRegistry.ts | 14 - src/chrome/target/cdtpDebugger.ts | 65 - .../target/cdtpDebuggerEventsProvider.ts | 77 - src/chrome/target/cdtpDiagnostics.ts | 57 - src/chrome/target/cdtpLocationParser.ts | 32 - .../target/cdtpOnScriptParsedEventProvider.ts | 85 - src/chrome/target/cdtpRuntime.ts | 32 - src/chrome/target/cdtpScriptsRegistry.ts | 103 - src/chrome/target/cdtpSmallerModules.ts | 138 -- src/chrome/target/cdtpStackTraceParser.ts | 36 - src/chrome/target/cdtpTargetBreakpoints.ts | 137 -- src/chrome/target/controlDebugeeExecution.ts | 57 - src/chrome/target/events.ts | 102 - .../target/exceptionThrownEventProvider.ts | 44 - .../target/executionContextEventsProvider.ts | 24 - src/chrome/target/inspectDebugeeState.ts | 50 - src/chrome/target/requests.ts | 25 - src/chrome/target/updateDebugeeState.ts | 26 - src/chrome/utils/lazy.ts | 24 + src/chrome/utils/version.ts | 17 + src/chrome/variables.ts | 36 +- src/debugAdapterInterfaces.d.ts | 8 +- src/index.ts | 22 +- src/transformers/remotePathTransformer.ts | 15 - src/transformers/urlPathTransformer.ts | 28 +- test/chrome/chromeDebugAdapter.test.ts | 42 +- test/chrome/consoleHelper.test.ts | 20 +- test/chrome/variables.test.ts | 14 +- test/mocks/debugProtocolMocks.ts | 26 +- test/testDebug/testDebugeeRunner.ts | 5 +- 111 files changed, 2692 insertions(+), 2462 deletions(-) create mode 100644 src/chrome/cdtpDebuggee/cdtpPrimitives.ts create mode 100644 src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts create mode 100644 src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts create mode 100644 src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts create mode 100644 src/chrome/cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider.ts create mode 100644 src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts create mode 100644 src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts create mode 100644 src/chrome/cdtpDebuggee/features/CDTPSchema.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts rename src/chrome/{target/breakpointFeaturesSupport.ts => cdtpDebuggee/features/cdtpBreakpointFeaturesSupport.ts} (68%) create mode 100644 src/chrome/cdtpDebuggee/features/cdtpBrowserNavigator.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpDebugeeExecutionController.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpNetworkCacheConfiguration.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpPausedOverlay.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpRuntime.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpScriptSourcesRetriever.ts create mode 100644 src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts rename src/chrome/{target => cdtpDebuggee/infrastructure}/cdtpDiagnosticsModule.ts (62%) create mode 100644 src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts create mode 100644 src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts create mode 100644 src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts create mode 100644 src/chrome/cdtpDebuggee/registries/cdtpBreakpointIdsRegistry.ts create mode 100644 src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts create mode 100644 src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts rename src/chrome/{debugee => debugeeStartup}/debugeeLauncher.ts (100%) rename src/chrome/internal/breakpoints/{bpRecipieInLoadedSourceLogic.ts => bpRecipieAtLoadedSourceLogic.ts} (79%) delete mode 100644 src/chrome/target/addSourceUriToExpression.ts delete mode 100644 src/chrome/target/breakpointIdRegistry.ts delete mode 100644 src/chrome/target/callFrameRegistry.ts delete mode 100644 src/chrome/target/cdtpDebugger.ts delete mode 100644 src/chrome/target/cdtpDebuggerEventsProvider.ts delete mode 100644 src/chrome/target/cdtpDiagnostics.ts delete mode 100644 src/chrome/target/cdtpLocationParser.ts delete mode 100644 src/chrome/target/cdtpOnScriptParsedEventProvider.ts delete mode 100644 src/chrome/target/cdtpRuntime.ts delete mode 100644 src/chrome/target/cdtpScriptsRegistry.ts delete mode 100644 src/chrome/target/cdtpSmallerModules.ts delete mode 100644 src/chrome/target/cdtpStackTraceParser.ts delete mode 100644 src/chrome/target/cdtpTargetBreakpoints.ts delete mode 100644 src/chrome/target/controlDebugeeExecution.ts delete mode 100644 src/chrome/target/events.ts delete mode 100644 src/chrome/target/exceptionThrownEventProvider.ts delete mode 100644 src/chrome/target/executionContextEventsProvider.ts delete mode 100644 src/chrome/target/inspectDebugeeState.ts delete mode 100644 src/chrome/target/requests.ts delete mode 100644 src/chrome/target/updateDebugeeState.ts create mode 100644 src/chrome/utils/lazy.ts create mode 100644 src/chrome/utils/version.ts diff --git a/package-lock.json b/package-lock.json index 50ccc2f13..6882c2d72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,8 @@ "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", "dev": true, "requires": { - "normalize-path": "^2.0.1", - "through2": "^2.0.3" + "normalize-path": "2.1.1", + "through2": "2.0.3" }, "dependencies": { "core-util-is": { @@ -38,7 +38,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "^1.0.1" + "remove-trailing-separator": "1.1.0" } }, "process-nextick-args": { @@ -53,13 +53,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "remove-trailing-separator": { @@ -80,7 +80,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "through2": { @@ -89,8 +89,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" + "readable-stream": "2.3.5", + "xtend": "4.0.1" } }, "util-deprecate": { @@ -113,7 +113,7 @@ "integrity": "sha512-5qqtNia+m2I0/85+pd2YzAXaTyKO8j+svirO5aN+XaQJ5+eZ8nx0jPtEWZLxCi50xwYsX10xUHetFzfb1WEs4Q==", "dev": true, "requires": { - "@types/color-convert": "*" + "@types/color-convert": "1.9.0" } }, "@types/color-convert": { @@ -122,7 +122,7 @@ "integrity": "sha512-OKGEfULrvSL2VRbkl/gnjjgbbF7ycIlpSsX7Nkab4MOWi5XxmgBYvuiQ7lcCFY5cPDz7MUNaKgxte2VRmtr4Fg==", "dev": true, "requires": { - "@types/color-name": "*" + "@types/color-name": "1.1.0" } }, "@types/color-name": { @@ -149,9 +149,9 @@ "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==", "dev": true, "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" + "@types/events": "1.2.0", + "@types/minimatch": "2.0.29", + "@types/node": "8.0.58" } }, "@types/inversify-inject-decorators": { @@ -160,7 +160,7 @@ "integrity": "sha1-mlC5tHOluL1RpkV1QNEt293N8l4=", "dev": true, "requires": { - "inversify-inject-decorators": "*" + "inversify-inject-decorators": "3.1.0" } }, "@types/lodash": { @@ -210,8 +210,8 @@ "integrity": "sha512-i/dVaSjmTM92EFFFhmGL6AmHzvJ70XpAXmMLvNKh3JrRTGOiXvejfxe5+OSxcJK0paGOYHDaRLS8nXW6/FxSxg==", "dev": true, "requires": { - "@types/events": "*", - "@types/node": "*" + "@types/events": "1.2.0", + "@types/node": "8.0.58" } }, "acorn": { @@ -232,7 +232,7 @@ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { - "ansi-wrap": "^0.1.0" + "ansi-wrap": "0.1.0" } }, "ansi-cyan": { @@ -286,7 +286,7 @@ "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", "dev": true, "requires": { - "buffer-equal": "^1.0.0" + "buffer-equal": "1.0.0" } }, "archy": { @@ -301,7 +301,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "sprintf-js": "1.0.3" } }, "arr-diff": { @@ -346,7 +346,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "^1.0.1" + "array-uniq": "1.0.3" } }, "array-uniq": { @@ -390,9 +390,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" }, "dependencies": { "esutils": { @@ -414,13 +414,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" }, "dependencies": { "define-property": { @@ -429,7 +429,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -438,7 +438,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -447,7 +447,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -456,9 +456,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -474,7 +474,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -484,16 +484,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -502,7 +502,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -531,15 +531,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" } }, "camelcase": { @@ -554,11 +554,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" }, "dependencies": { "ansi-regex": { @@ -579,7 +579,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } } } @@ -596,10 +596,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" }, "dependencies": { "arr-union": { @@ -614,7 +614,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -625,9 +625,9 @@ "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" } }, "clone": { @@ -654,9 +654,9 @@ "integrity": "sha512-DNNEq6JdqBFPzS29TaoqZFPNLn5Xn3XyPFqLIhyBT8Xou4lHQEWzD6FinXoJUfhIfWX3aE1JkRa3cbWCHFbt1g==", "dev": true, "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" + "inherits": "2.0.3", + "process-nextick-args": "2.0.0", + "readable-stream": "2.3.5" }, "dependencies": { "isarray": { @@ -677,13 +677,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -692,7 +692,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } } } @@ -709,8 +709,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "map-visit": "1.0.0", + "object-visit": "1.0.1" } }, "color": { @@ -718,8 +718,8 @@ "resolved": "https://registry.npmjs.org/color/-/color-3.1.0.tgz", "integrity": "sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==", "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" + "color-convert": "1.9.1", + "color-string": "1.5.3" } }, "color-convert": { @@ -727,7 +727,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "requires": { - "color-name": "^1.1.1" + "color-name": "1.1.3" } }, "color-name": { @@ -740,8 +740,8 @@ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "color-name": "1.1.3", + "simple-swizzle": "0.2.2" } }, "color-support": { @@ -779,7 +779,7 @@ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { - "safe-buffer": "~5.1.1" + "safe-buffer": "5.1.1" } }, "copy-descriptor": { @@ -800,9 +800,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" }, "dependencies": { "lru-cache": { @@ -811,8 +811,8 @@ "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } } } @@ -823,10 +823,10 @@ "integrity": "sha512-0W171WccAjQGGTKLhw4m2nnl0zPHUlTO/I8td4XzJgIB8Hg3ZZx71qT4G4eX8OVsSiaAKiUMy73E3nsbPlg2DQ==", "dev": true, "requires": { - "inherits": "^2.0.1", - "source-map": "^0.1.38", - "source-map-resolve": "^0.5.1", - "urix": "^0.1.0" + "inherits": "2.0.3", + "source-map": "0.1.43", + "source-map-resolve": "0.5.1", + "urix": "0.1.0" }, "dependencies": { "source-map": { @@ -835,7 +835,7 @@ "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -861,8 +861,8 @@ "integrity": "sha1-+gccXYdIRoVCSAdCHKSxawsaB2M=", "dev": true, "requires": { - "debug": "2.X", - "lazy-debug-legacy": "0.0.X", + "debug": "2.6.9", + "lazy-debug-legacy": "0.0.1", "object-assign": "4.1.0" }, "dependencies": { @@ -892,7 +892,7 @@ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { - "clone": "^1.0.2" + "clone": "1.0.4" } }, "define-properties": { @@ -901,8 +901,8 @@ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" + "foreach": "2.0.5", + "object-keys": "1.0.11" } }, "define-property": { @@ -911,8 +911,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "1.0.2", + "isobject": "3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -921,7 +921,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -930,7 +930,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -939,9 +939,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -952,13 +952,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" } }, "deprecated": { @@ -996,7 +996,7 @@ "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=", "dev": true, "requires": { - "esutils": "^1.1.6", + "esutils": "1.1.6", "isarray": "0.0.1" } }, @@ -1012,7 +1012,7 @@ "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", "dev": true, "requires": { - "readable-stream": "~1.1.9" + "readable-stream": "1.1.14" } }, "duplexify": { @@ -1021,10 +1021,10 @@ "integrity": "sha512-JzYSLYMhoVVBe8+mbHQ4KgpvHpm0DZpJuL8PY93Vyv1fW7jYJ90LoXa1di/CVbJM+TgMs91rbDapE/RNIfnJsA==", "dev": true, "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.1", + "inherits": "2.0.3", + "readable-stream": "2.3.5", + "stream-shift": "1.0.0" }, "dependencies": { "end-of-stream": { @@ -1033,7 +1033,7 @@ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "once": "^1.4.0" + "once": "1.4.0" } }, "isarray": { @@ -1054,13 +1054,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -1069,7 +1069,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } } } @@ -1080,7 +1080,7 @@ "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", "dev": true, "requires": { - "once": "~1.3.0" + "once": "1.3.3" }, "dependencies": { "once": { @@ -1089,7 +1089,7 @@ "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } } } @@ -1118,13 +1118,13 @@ "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", + "duplexer": "0.1.1", + "from": "0.1.7", + "map-stream": "0.1.0", "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" + "split": "0.3.3", + "stream-combiner": "0.0.4", + "through": "2.3.8" }, "dependencies": { "through": { @@ -1141,13 +1141,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" } }, "expand-brackets": { @@ -1156,13 +1156,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -1171,7 +1171,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -1180,7 +1180,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1191,7 +1191,7 @@ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "requires": { - "homedir-polyfill": "^1.0.1" + "homedir-polyfill": "1.0.1" } }, "extend": { @@ -1206,7 +1206,7 @@ "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", "dev": true, "requires": { - "kind-of": "^1.1.0" + "kind-of": "1.1.0" }, "dependencies": { "kind-of": { @@ -1223,14 +1223,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -1239,7 +1239,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -1248,7 +1248,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -1257,7 +1257,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -1266,7 +1266,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -1275,9 +1275,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -1288,9 +1288,9 @@ "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", "dev": true, "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "time-stamp": "^1.0.0" + "ansi-gray": "0.1.1", + "color-support": "1.1.3", + "time-stamp": "1.1.0" }, "dependencies": { "time-stamp": { @@ -1307,10 +1307,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -1319,7 +1319,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1336,7 +1336,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "^2.0.0" + "locate-path": "2.0.0" } }, "findup-sync": { @@ -1345,10 +1345,10 @@ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", "dev": true, "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" + "detect-file": "1.0.0", + "is-glob": "3.1.0", + "micromatch": "3.1.10", + "resolve-dir": "1.0.1" } }, "fined": { @@ -1357,11 +1357,11 @@ "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" + "expand-tilde": "2.0.2", + "is-plain-object": "2.0.4", + "object.defaults": "1.1.0", + "object.pick": "1.3.0", + "parse-filepath": "1.0.2" } }, "first-chunk-stream": { @@ -1382,8 +1382,8 @@ "integrity": "sha1-yBuQ2HRnZvGmCaRoCZRsRd2K5Bc=", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" + "inherits": "2.0.3", + "readable-stream": "2.3.5" }, "dependencies": { "isarray": { @@ -1404,13 +1404,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -1419,7 +1419,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } } } @@ -1436,7 +1436,7 @@ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "requires": { - "for-in": "^1.0.1" + "for-in": "1.0.2" } }, "foreach": { @@ -1451,7 +1451,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "^0.2.2" + "map-cache": "0.2.2" } }, "from": { @@ -1466,8 +1466,8 @@ "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" + "graceful-fs": "4.1.11", + "through2": "2.0.3" }, "dependencies": { "graceful-fs": { @@ -1495,7 +1495,7 @@ "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", "dev": true, "requires": { - "globule": "~0.1.0" + "globule": "0.1.0" } }, "get-caller-file": { @@ -1521,12 +1521,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "glob-stream": { @@ -1535,12 +1535,12 @@ "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", "dev": true, "requires": { - "glob": "^4.3.1", - "glob2base": "^0.0.12", - "minimatch": "^2.0.1", - "ordered-read-streams": "^0.1.0", - "through2": "^0.6.1", - "unique-stream": "^1.0.0" + "glob": "4.5.3", + "glob2base": "0.0.12", + "minimatch": "2.0.10", + "ordered-read-streams": "0.1.0", + "through2": "0.6.5", + "unique-stream": "1.0.0" }, "dependencies": { "glob": { @@ -1549,10 +1549,10 @@ "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" } }, "minimatch": { @@ -1561,19 +1561,19 @@ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", "dev": true, "requires": { - "brace-expansion": "^1.0.0" + "brace-expansion": "1.1.11" } }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", + "core-util-is": "1.0.2", + "inherits": "2.0.3", "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "string_decoder": "0.10.31" } }, "through2": { @@ -1582,8 +1582,8 @@ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" + "readable-stream": "1.0.34", + "xtend": "4.0.1" } } } @@ -1594,7 +1594,7 @@ "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", "dev": true, "requires": { - "gaze": "^0.5.1" + "gaze": "0.5.2" } }, "glob2base": { @@ -1603,7 +1603,7 @@ "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", "dev": true, "requires": { - "find-index": "^0.1.1" + "find-index": "0.1.1" } }, "global-modules": { @@ -1612,9 +1612,9 @@ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "global-prefix": "1.0.2", + "is-windows": "1.0.2", + "resolve-dir": "1.0.1" } }, "global-prefix": { @@ -1623,11 +1623,11 @@ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "expand-tilde": "2.0.2", + "homedir-polyfill": "1.0.1", + "ini": "1.3.5", + "is-windows": "1.0.2", + "which": "1.3.1" } }, "globby": { @@ -1636,12 +1636,12 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.3", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "globule": { @@ -1650,9 +1650,9 @@ "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", "dev": true, "requires": { - "glob": "~3.1.21", - "lodash": "~1.0.1", - "minimatch": "~0.2.11" + "glob": "3.1.21", + "lodash": "1.0.2", + "minimatch": "0.2.14" }, "dependencies": { "glob": { @@ -1661,9 +1661,9 @@ "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", "dev": true, "requires": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" + "graceful-fs": "1.2.3", + "inherits": "1.0.2", + "minimatch": "0.2.14" } }, "graceful-fs": { @@ -1690,8 +1690,8 @@ "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", "dev": true, "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "lru-cache": "2.7.3", + "sigmund": "1.0.1" } } } @@ -1702,7 +1702,7 @@ "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==", "dev": true, "requires": { - "sparkles": "^1.0.0" + "sparkles": "1.0.0" } }, "graceful-fs": { @@ -1711,7 +1711,7 @@ "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", "dev": true, "requires": { - "natives": "^1.1.0" + "natives": "1.1.5" } }, "growl": { @@ -1726,19 +1726,19 @@ "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", "dev": true, "requires": { - "archy": "^1.0.0", - "chalk": "^1.0.0", - "deprecated": "^0.0.1", - "gulp-util": "^3.0.0", - "interpret": "^1.0.0", - "liftoff": "^2.1.0", - "minimist": "^1.1.0", - "orchestrator": "^0.3.0", - "pretty-hrtime": "^1.0.0", - "semver": "^4.1.0", - "tildify": "^1.0.0", - "v8flags": "^2.0.2", - "vinyl-fs": "^0.3.0" + "archy": "1.0.0", + "chalk": "1.1.3", + "deprecated": "0.0.1", + "gulp-util": "3.0.8", + "interpret": "1.1.0", + "liftoff": "2.5.0", + "minimist": "1.2.0", + "orchestrator": "0.3.8", + "pretty-hrtime": "1.0.3", + "semver": "4.3.6", + "tildify": "1.2.0", + "v8flags": "2.1.1", + "vinyl-fs": "0.3.14" }, "dependencies": { "semver": { @@ -1755,13 +1755,13 @@ "integrity": "sha1-L1/l9kvNH0zxicFg4IDIrQZUMJQ=", "dev": true, "requires": { - "chalk": "^1.0.0", - "gulp-util": "^3.0.0", - "object-assign": "^4.0.1", - "plur": "^2.0.0", - "stringify-object": "^2.3.0", - "through2": "^2.0.0", - "tildify": "^1.1.2" + "chalk": "1.1.3", + "gulp-util": "3.0.8", + "object-assign": "4.1.1", + "plur": "2.1.2", + "stringify-object": "2.4.0", + "through2": "2.0.3", + "tildify": "1.2.0" }, "dependencies": { "ansi-regex": { @@ -1782,11 +1782,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "core-util-is": { @@ -1807,7 +1807,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "inherits": { @@ -1834,13 +1834,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -1855,7 +1855,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "strip-ansi": { @@ -1864,7 +1864,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "supports-color": { @@ -1879,8 +1879,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" + "readable-stream": "2.3.5", + "xtend": "4.0.1" } }, "util-deprecate": { @@ -1903,10 +1903,10 @@ "integrity": "sha512-L/LJftsbKoHbVj6dN5pvMsyJn9jYI0wT0nMg3G6VZhDac4NesezecYTi8/48rHi+yEic3sUpw6jlSc7qNWh32A==", "dev": true, "requires": { - "chalk": "^1.1.3", - "fancy-log": "^1.3.2", - "plugin-error": "^0.1.2", - "through2": "^2.0.3" + "chalk": "1.1.3", + "fancy-log": "1.3.2", + "plugin-error": "0.1.2", + "through2": "2.0.3" }, "dependencies": { "ansi-regex": { @@ -1927,11 +1927,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "core-util-is": { @@ -1952,7 +1952,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "inherits": { @@ -1979,13 +1979,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -2000,7 +2000,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "strip-ansi": { @@ -2009,7 +2009,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "supports-color": { @@ -2024,8 +2024,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" + "readable-stream": "2.3.5", + "xtend": "4.0.1" } }, "util-deprecate": { @@ -2048,17 +2048,17 @@ "integrity": "sha1-tDfR89mAzyboEYSCNxjOFa5ll7Y=", "dev": true, "requires": { - "@gulp-sourcemaps/map-sources": "1.X", - "acorn": "4.X", - "convert-source-map": "1.X", - "css": "2.X", - "debug-fabulous": "0.0.X", - "detect-newline": "2.X", - "graceful-fs": "4.X", - "source-map": "~0.6.0", - "strip-bom": "2.X", - "through2": "2.X", - "vinyl": "1.X" + "@gulp-sourcemaps/map-sources": "1.0.0", + "acorn": "4.0.13", + "convert-source-map": "1.5.1", + "css": "2.2.3", + "debug-fabulous": "0.0.4", + "detect-newline": "2.1.0", + "graceful-fs": "4.1.11", + "source-map": "0.6.1", + "strip-bom": "2.0.0", + "through2": "2.0.3", + "vinyl": "1.2.0" }, "dependencies": { "convert-source-map": { @@ -2109,13 +2109,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -2130,7 +2130,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "strip-bom": { @@ -2139,7 +2139,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "is-utf8": "0.2.1" } }, "through2": { @@ -2148,8 +2148,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" + "readable-stream": "2.3.5", + "xtend": "4.0.1" } }, "util-deprecate": { @@ -2164,8 +2164,8 @@ "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", + "clone": "1.0.4", + "clone-stats": "0.0.1", "replace-ext": "0.0.1" } }, @@ -2186,9 +2186,9 @@ "@types/fancy-log": "1.3.0", "chalk": "2.3.1", "fancy-log": "1.3.2", - "map-stream": "~0.0.7", + "map-stream": "0.0.7", "plugin-error": "1.0.1", - "through": "~2.3.8" + "through": "2.3.8" }, "dependencies": { "ansi-styles": { @@ -2197,7 +2197,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "arr-diff": { @@ -2218,9 +2218,9 @@ "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.2.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" } }, "extend-shallow": { @@ -2229,8 +2229,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "fancy-log": { @@ -2239,9 +2239,9 @@ "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", "dev": true, "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "time-stamp": "^1.0.0" + "ansi-gray": "0.1.1", + "color-support": "1.1.3", + "time-stamp": "1.1.0" } }, "has-flag": { @@ -2256,7 +2256,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } }, "map-stream": { @@ -2271,10 +2271,10 @@ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" + "ansi-colors": "1.1.0", + "arr-diff": "4.0.0", + "arr-union": "3.1.0", + "extend-shallow": "3.0.2" } }, "supports-color": { @@ -2283,7 +2283,7 @@ "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -2294,12 +2294,12 @@ "integrity": "sha512-BGdaBC1R4SJosXEkkEieeZ21qCZHnfSV78k7zzDljqAxvzDeGRTUqF4geckVclKEeiS3EYOBwNlxoHjJtn20vg==", "dev": true, "requires": { - "ansi-colors": "^1.0.1", - "plugin-error": "^0.1.2", - "source-map": "^0.6.1", - "through2": "^2.0.3", - "vinyl": "^2.1.0", - "vinyl-fs": "^3.0.0" + "ansi-colors": "1.1.0", + "plugin-error": "0.1.2", + "source-map": "0.6.1", + "through2": "2.0.3", + "vinyl": "2.1.0", + "vinyl-fs": "3.0.2" }, "dependencies": { "clone": { @@ -2320,8 +2320,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" } }, "glob-stream": { @@ -2330,16 +2330,16 @@ "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", "dev": true, "requires": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" + "extend": "3.0.1", + "glob": "7.1.3", + "glob-parent": "3.1.0", + "is-negated-glob": "1.0.0", + "ordered-read-streams": "1.0.1", + "pumpify": "1.4.0", + "readable-stream": "2.3.5", + "remove-trailing-separator": "1.1.0", + "to-absolute-glob": "2.0.2", + "unique-stream": "2.2.1" }, "dependencies": { "remove-trailing-separator": { @@ -2368,7 +2368,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } }, "isarray": { @@ -2383,7 +2383,7 @@ "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", "dev": true, "requires": { - "readable-stream": "^2.0.1" + "readable-stream": "2.3.5" } }, "process-nextick-args": { @@ -2398,13 +2398,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "replace-ext": { @@ -2419,7 +2419,7 @@ "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "unique-stream": { @@ -2428,8 +2428,8 @@ "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", "dev": true, "requires": { - "json-stable-stringify": "^1.0.0", - "through2-filter": "^2.0.0" + "json-stable-stringify": "1.0.1", + "through2-filter": "2.0.0" } }, "vinyl": { @@ -2438,12 +2438,12 @@ "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", "dev": true, "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" + "clone": "2.1.1", + "clone-buffer": "1.0.0", + "clone-stats": "1.0.0", + "cloneable-readable": "1.1.1", + "remove-trailing-separator": "1.1.0", + "replace-ext": "1.0.0" }, "dependencies": { "remove-trailing-separator": { @@ -2460,23 +2460,23 @@ "integrity": "sha512-AUSFda1OukBwuLPBTbyuO4IRWgfXmqC4UTW0f8xrCa8Hkv9oyIU+NSqBlgfOLZRoUt7cHdo75hKQghCywpIyIw==", "dev": true, "requires": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" + "fs-mkdirp-stream": "1.0.0", + "glob-stream": "6.1.0", + "graceful-fs": "4.1.11", + "is-valid-glob": "1.0.0", + "lazystream": "1.0.0", + "lead": "1.0.0", + "object.assign": "4.1.0", + "pumpify": "1.4.0", + "readable-stream": "2.3.5", + "remove-bom-buffer": "3.0.0", + "remove-bom-stream": "1.2.0", + "resolve-options": "1.1.0", + "through2": "2.0.3", + "to-through": "2.0.0", + "value-or-function": "3.0.0", + "vinyl": "2.1.0", + "vinyl-sourcemap": "1.1.0" } } } @@ -2487,24 +2487,24 @@ "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", "dev": true, "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", + "array-differ": "1.0.0", + "array-uniq": "1.0.3", + "beeper": "1.1.1", + "chalk": "1.1.3", + "dateformat": "2.2.0", + "fancy-log": "1.3.2", + "gulplog": "1.0.0", + "has-gulplog": "0.1.0", + "lodash._reescape": "3.0.0", + "lodash._reevaluate": "3.0.0", + "lodash._reinterpolate": "3.0.0", + "lodash.template": "3.6.2", + "minimist": "1.2.0", + "multipipe": "0.1.2", + "object-assign": "3.0.0", "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" + "through2": "2.0.3", + "vinyl": "0.5.3" }, "dependencies": { "ansi-regex": { @@ -2525,11 +2525,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "core-util-is": { @@ -2550,7 +2550,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "inherits": { @@ -2583,13 +2583,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -2604,7 +2604,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "strip-ansi": { @@ -2613,7 +2613,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "supports-color": { @@ -2628,8 +2628,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" + "readable-stream": "2.3.5", + "xtend": "4.0.1" } }, "util-deprecate": { @@ -2652,7 +2652,7 @@ "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", "dev": true, "requires": { - "glogg": "^1.0.0" + "glogg": "1.0.1" } }, "has-ansi": { @@ -2661,7 +2661,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" }, "dependencies": { "ansi-regex": { @@ -2684,7 +2684,7 @@ "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", "dev": true, "requires": { - "sparkles": "^1.0.0" + "sparkles": "1.0.0" } }, "has-symbols": { @@ -2699,9 +2699,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" } }, "has-values": { @@ -2710,8 +2710,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { "kind-of": { @@ -2720,7 +2720,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" }, "dependencies": { "is-buffer": { @@ -2745,7 +2745,7 @@ "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", "dev": true, "requires": { - "parse-passwd": "^1.0.0" + "parse-passwd": "1.0.0" } }, "iconv-lite": { @@ -2754,7 +2754,7 @@ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": "2.1.2" } }, "inflight": { @@ -2762,8 +2762,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" }, "dependencies": { "once": { @@ -2771,7 +2771,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "wrappy": { @@ -2832,8 +2832,8 @@ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" + "is-relative": "1.0.0", + "is-windows": "1.0.2" } }, "is-accessor-descriptor": { @@ -2842,7 +2842,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -2851,7 +2851,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" }, "dependencies": { "is-buffer": { @@ -2881,7 +2881,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -2890,7 +2890,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" }, "dependencies": { "is-buffer": { @@ -2909,9 +2909,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" }, "dependencies": { "kind-of": { @@ -2946,7 +2946,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } }, "is-negated-glob": { @@ -2961,7 +2961,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -2970,7 +2970,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" }, "dependencies": { "is-buffer": { @@ -2995,7 +2995,7 @@ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { - "is-path-inside": "^1.0.0" + "is-path-inside": "1.0.1" } }, "is-path-inside": { @@ -3004,7 +3004,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "^1.0.1" + "path-is-inside": "1.0.2" } }, "is-plain-obj": { @@ -3019,7 +3019,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "is-regexp": { @@ -3034,7 +3034,7 @@ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { - "is-unc-path": "^1.0.0" + "is-unc-path": "1.0.0" } }, "is-stream": { @@ -3049,7 +3049,7 @@ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { - "unc-path-regex": "^0.1.2" + "unc-path-regex": "0.1.2" } }, "is-utf8": { @@ -3100,8 +3100,8 @@ "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "1.0.10", + "esprima": "4.0.0" } }, "json-stable-stringify": { @@ -3110,7 +3110,7 @@ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "~0.0.0" + "jsonify": "0.0.0" } }, "jsonify": { @@ -3137,7 +3137,7 @@ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", "dev": true, "requires": { - "readable-stream": "^2.0.5" + "readable-stream": "2.3.5" }, "dependencies": { "isarray": { @@ -3158,13 +3158,13 @@ "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -3173,7 +3173,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } } } @@ -3184,7 +3184,7 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "^1.0.0" + "invert-kv": "1.0.0" } }, "lead": { @@ -3193,7 +3193,7 @@ "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", "dev": true, "requires": { - "flush-write-stream": "^1.0.2" + "flush-write-stream": "1.0.2" } }, "liftoff": { @@ -3202,14 +3202,14 @@ "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", "dev": true, "requires": { - "extend": "^3.0.0", - "findup-sync": "^2.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" + "extend": "3.0.1", + "findup-sync": "2.0.0", + "fined": "1.1.0", + "flagged-respawn": "1.0.0", + "is-plain-object": "2.0.4", + "object.map": "1.0.1", + "rechoir": "0.6.2", + "resolve": "1.8.1" } }, "locate-path": { @@ -3218,8 +3218,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "2.0.0", + "path-exists": "3.0.0" } }, "lodash": { @@ -3287,7 +3287,7 @@ "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", "dev": true, "requires": { - "lodash._root": "^3.0.0" + "lodash._root": "3.0.1" } }, "lodash.isarguments": { @@ -3308,9 +3308,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" } }, "lodash.restparam": { @@ -3325,15 +3325,15 @@ "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", "dev": true, "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" + "lodash._basecopy": "3.0.1", + "lodash._basetostring": "3.0.1", + "lodash._basevalues": "3.0.0", + "lodash._isiterateecall": "3.0.9", + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0", + "lodash.keys": "3.1.2", + "lodash.restparam": "3.6.1", + "lodash.templatesettings": "3.1.1" } }, "lodash.templatesettings": { @@ -3342,8 +3342,8 @@ "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", "dev": true, "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0" } }, "lru-cache": { @@ -3358,7 +3358,7 @@ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { - "kind-of": "^6.0.2" + "kind-of": "6.0.2" } }, "map-cache": { @@ -3379,7 +3379,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "^1.0.0" + "object-visit": "1.0.1" } }, "mem": { @@ -3388,7 +3388,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "1.2.0" } }, "merge2": { @@ -3403,19 +3403,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -3424,8 +3424,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "is-extendable": { @@ -3434,7 +3434,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -3450,7 +3450,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -3465,8 +3465,8 @@ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "for-in": "1.0.2", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -3475,7 +3475,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -3535,12 +3535,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "supports-color": { @@ -3549,7 +3549,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3581,17 +3581,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -3600,8 +3600,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "is-extendable": { @@ -3610,7 +3610,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -3641,7 +3641,7 @@ "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=", "dev": true, "requires": { - "once": "^1.3.2" + "once": "1.4.0" } }, "npm-run-path": { @@ -3650,7 +3650,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "2.0.1" } }, "number-is-nan": { @@ -3671,9 +3671,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" }, "dependencies": { "define-property": { @@ -3682,7 +3682,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "kind-of": { @@ -3691,7 +3691,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" }, "dependencies": { "is-buffer": { @@ -3716,7 +3716,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "^3.0.0" + "isobject": "3.0.1" } }, "object.assign": { @@ -3725,10 +3725,10 @@ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "has-symbols": "1.0.0", + "object-keys": "1.0.11" } }, "object.defaults": { @@ -3737,10 +3737,10 @@ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", "dev": true, "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" + "array-each": "1.0.1", + "array-slice": "1.1.0", + "for-own": "1.0.0", + "isobject": "3.0.1" } }, "object.map": { @@ -3749,8 +3749,8 @@ "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", "dev": true, "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" + "for-own": "1.0.0", + "make-iterator": "1.0.1" } }, "object.pick": { @@ -3759,7 +3759,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "once": { @@ -3776,8 +3776,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "minimist": "0.0.10", + "wordwrap": "0.0.3" }, "dependencies": { "minimist": { @@ -3794,9 +3794,9 @@ "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", "dev": true, "requires": { - "end-of-stream": "~0.1.5", - "sequencify": "~0.0.7", - "stream-consume": "~0.1.0" + "end-of-stream": "0.1.5", + "sequencify": "0.0.7", + "stream-consume": "0.1.1" } }, "ordered-read-streams": { @@ -3817,9 +3817,9 @@ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" } }, "p-finally": { @@ -3834,7 +3834,7 @@ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "1.0.0" } }, "p-locate": { @@ -3843,7 +3843,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "1.3.0" } }, "p-try": { @@ -3858,9 +3858,9 @@ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", "dev": true, "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" + "is-absolute": "1.0.0", + "map-cache": "0.2.2", + "path-root": "0.1.1" } }, "parse-passwd": { @@ -3916,7 +3916,7 @@ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", "dev": true, "requires": { - "path-root-regex": "^0.1.0" + "path-root-regex": "0.1.2" } }, "path-root-regex": { @@ -3931,7 +3931,7 @@ "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "dev": true, "requires": { - "through": "~2.3" + "through": "2.3.8" }, "dependencies": { "through": { @@ -3960,7 +3960,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, "plugin-error": { @@ -3969,11 +3969,11 @@ "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", "dev": true, "requires": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" + "ansi-cyan": "0.1.1", + "ansi-red": "0.1.1", + "arr-diff": "1.1.0", + "arr-union": "2.1.0", + "extend-shallow": "1.1.4" }, "dependencies": { "arr-diff": { @@ -3982,8 +3982,8 @@ "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", "dev": true, "requires": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" + "arr-flatten": "1.1.0", + "array-slice": "0.2.3" } }, "array-slice": { @@ -4000,7 +4000,7 @@ "integrity": "sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo=", "dev": true, "requires": { - "irregular-plurals": "^1.0.0" + "irregular-plurals": "1.4.0" } }, "posix-character-classes": { @@ -4033,8 +4033,8 @@ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.1", + "once": "1.4.0" }, "dependencies": { "end-of-stream": { @@ -4043,7 +4043,7 @@ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "once": "^1.4.0" + "once": "1.4.0" } } } @@ -4054,9 +4054,9 @@ "integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==", "dev": true, "requires": { - "duplexify": "^3.5.3", - "inherits": "^2.0.3", - "pump": "^2.0.0" + "duplexify": "3.5.4", + "inherits": "2.0.3", + "pump": "2.0.1" } }, "readable-stream": { @@ -4065,10 +4065,10 @@ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", + "core-util-is": "1.0.2", + "inherits": "2.0.3", "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "string_decoder": "0.10.31" }, "dependencies": { "core-util-is": { @@ -4091,7 +4091,7 @@ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "resolve": "^1.1.6" + "resolve": "1.8.1" } }, "reflect-metadata": { @@ -4105,8 +4105,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" }, "dependencies": { "extend-shallow": { @@ -4115,8 +4115,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "is-extendable": { @@ -4125,7 +4125,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -4136,8 +4136,8 @@ "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", "dev": true, "requires": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" + "is-buffer": "1.1.6", + "is-utf8": "0.2.1" } }, "remove-bom-stream": { @@ -4146,9 +4146,9 @@ "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", "dev": true, "requires": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" + "remove-bom-buffer": "3.0.0", + "safe-buffer": "5.1.1", + "through2": "2.0.3" } }, "remove-trailing-separator": { @@ -4193,7 +4193,7 @@ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "1.0.5" } }, "resolve-dir": { @@ -4202,8 +4202,8 @@ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "dev": true, "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "expand-tilde": "2.0.2", + "global-modules": "1.0.0" } }, "resolve-options": { @@ -4212,7 +4212,7 @@ "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", "dev": true, "requires": { - "value-or-function": "^3.0.0" + "value-or-function": "3.0.0" } }, "resolve-url": { @@ -4233,7 +4233,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "7.1.3" } }, "run-sequence": { @@ -4242,8 +4242,8 @@ "integrity": "sha1-UJWgvr6YczsBQL0I3YDsAw3azes=", "dev": true, "requires": { - "chalk": "*", - "gulp-util": "*" + "chalk": "1.1.3", + "gulp-util": "3.0.8" } }, "safe-buffer": { @@ -4258,7 +4258,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "~0.1.10" + "ret": "0.1.15" } }, "safer-buffer": { @@ -4296,10 +4296,10 @@ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" }, "dependencies": { "extend-shallow": { @@ -4308,7 +4308,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -4319,7 +4319,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "1.0.0" } }, "shebang-regex": { @@ -4345,7 +4345,7 @@ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "requires": { - "is-arrayish": "^0.3.1" + "is-arrayish": "0.3.2" } }, "snapdragon": { @@ -4354,14 +4354,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.1", + "use": "3.1.1" }, "dependencies": { "define-property": { @@ -4370,7 +4370,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -4379,7 +4379,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "source-map": { @@ -4396,9 +4396,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" }, "dependencies": { "define-property": { @@ -4407,7 +4407,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -4416,7 +4416,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -4425,7 +4425,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -4434,9 +4434,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -4447,7 +4447,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "^3.2.0" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4456,7 +4456,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" }, "dependencies": { "is-buffer": { @@ -4480,11 +4480,11 @@ "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", "dev": true, "requires": { - "atob": "^2.0.0", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "atob": "2.1.0", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" } }, "source-map-url": { @@ -4505,7 +4505,7 @@ "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", "dev": true, "requires": { - "through": "2" + "through": "2.3.8" }, "dependencies": { "through": { @@ -4522,7 +4522,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "extend-shallow": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -4531,8 +4531,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "is-extendable": { @@ -4541,7 +4541,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -4558,8 +4558,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "define-property": "0.2.5", + "object-copy": "0.1.0" }, "dependencies": { "define-property": { @@ -4568,7 +4568,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -4579,7 +4579,7 @@ "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", "dev": true, "requires": { - "duplexer": "~0.1.1" + "duplexer": "0.1.1" } }, "stream-consume": { @@ -4600,8 +4600,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" } }, "string_decoder": { @@ -4616,8 +4616,8 @@ "integrity": "sha1-xi0RAj6yH+LZsIe+A5om3zsioJ0=", "dev": true, "requires": { - "is-plain-obj": "^1.0.0", - "is-regexp": "^1.0.0" + "is-plain-obj": "1.1.0", + "is-regexp": "1.0.0" } }, "strip-ansi": { @@ -4626,7 +4626,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } }, "strip-bom": { @@ -4635,8 +4635,8 @@ "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", "dev": true, "requires": { - "first-chunk-stream": "^1.0.0", - "is-utf8": "^0.2.0" + "first-chunk-stream": "1.0.0", + "is-utf8": "0.2.1" } }, "strip-eof": { @@ -4663,8 +4663,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" + "readable-stream": "2.3.6", + "xtend": "4.0.1" }, "dependencies": { "isarray": { @@ -4679,13 +4679,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" }, "dependencies": { "process-nextick-args": { @@ -4702,7 +4702,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } } } @@ -4713,8 +4713,8 @@ "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", "dev": true, "requires": { - "through2": "~2.0.0", - "xtend": "~4.0.0" + "through2": "2.0.3", + "xtend": "4.0.1" }, "dependencies": { "xtend": { @@ -4731,7 +4731,7 @@ "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", "dev": true, "requires": { - "os-homedir": "^1.0.0" + "os-homedir": "1.0.2" } }, "time-stamp": { @@ -4746,8 +4746,8 @@ "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", "dev": true, "requires": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" + "is-absolute": "1.0.0", + "is-negated-glob": "1.0.0" }, "dependencies": { "is-absolute": { @@ -4756,8 +4756,8 @@ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" + "is-relative": "1.0.0", + "is-windows": "1.0.2" } }, "is-relative": { @@ -4766,7 +4766,7 @@ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { - "is-unc-path": "^1.0.0" + "is-unc-path": "1.0.0" } }, "is-unc-path": { @@ -4775,7 +4775,7 @@ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { - "unc-path-regex": "^0.1.2" + "unc-path-regex": "0.1.2" } }, "is-windows": { @@ -4792,7 +4792,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4801,7 +4801,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" }, "dependencies": { "is-buffer": { @@ -4820,10 +4820,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" }, "dependencies": { "extend-shallow": { @@ -4832,8 +4832,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "is-extendable": { @@ -4842,7 +4842,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -4853,8 +4853,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "3.0.0", + "repeat-string": "1.6.1" } }, "to-through": { @@ -4863,7 +4863,7 @@ "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", "dev": true, "requires": { - "through2": "^2.0.3" + "through2": "2.0.3" } }, "tslib": { @@ -4878,18 +4878,18 @@ "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", "dev": true, "requires": { - "babel-code-frame": "^6.22.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^3.2.0", - "glob": "^7.1.1", - "js-yaml": "^3.7.0", - "minimatch": "^3.0.4", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.27.2" + "babel-code-frame": "6.26.0", + "builtin-modules": "1.1.1", + "chalk": "2.4.1", + "commander": "2.15.1", + "diff": "3.5.0", + "glob": "7.1.3", + "js-yaml": "3.11.0", + "minimatch": "3.0.4", + "resolve": "1.8.1", + "semver": "5.5.1", + "tslib": "1.9.0", + "tsutils": "2.29.0" }, "dependencies": { "ansi-styles": { @@ -4898,7 +4898,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "chalk": { @@ -4907,9 +4907,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" } }, "semver": { @@ -4924,7 +4924,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, "tsutils": { @@ -4933,7 +4933,7 @@ "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", "dev": true, "requires": { - "tslib": "^1.8.1" + "tslib": "1.9.0" } } } @@ -4944,8 +4944,8 @@ "integrity": "sha1-OekvMZVq0qZsAGHDUfqWwICK4Pg=", "dev": true, "requires": { - "doctrine": "^0.7.2", - "tslint": "^3.15.1" + "doctrine": "0.7.2", + "tslint": "3.15.1" }, "dependencies": { "balanced-match": { @@ -4960,7 +4960,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -4982,7 +4982,7 @@ "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", "dev": true, "requires": { - "glob": "~5.0.0" + "glob": "5.0.15" }, "dependencies": { "glob": { @@ -4991,11 +4991,11 @@ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } } } @@ -5012,7 +5012,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "once": { @@ -5021,7 +5021,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "path-parse": { @@ -5036,7 +5036,7 @@ "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "1.0.5" } }, "tslint": { @@ -5045,13 +5045,13 @@ "integrity": "sha1-2hZcqT2P3CwIa1EWXuG6y0jJjqU=", "dev": true, "requires": { - "colors": "^1.1.2", - "diff": "^2.2.1", - "findup-sync": "~0.3.0", - "glob": "^7.0.3", - "optimist": "~0.6.0", - "resolve": "^1.1.7", - "underscore.string": "^3.3.4" + "colors": "1.2.1", + "diff": "2.2.3", + "findup-sync": "0.3.0", + "glob": "7.1.3", + "optimist": "0.6.1", + "resolve": "1.6.0", + "underscore.string": "3.3.4" } }, "wrappy": { @@ -5068,7 +5068,7 @@ "integrity": "sha512-5AnfTGlfpUzpRHLmoojPBKFTTmbjnwgdaTHMdllausa4GBPya5u36i9ddrTX4PhetGZvd4JUYIpAmgHqVnsctg==", "dev": true, "requires": { - "tsutils": "^2.12.1" + "tsutils": "2.22.2" } }, "tsutils": { @@ -5077,7 +5077,7 @@ "integrity": "sha512-u06FUSulCJ+Y8a2ftuqZN6kIGqdP2yJjUPEngXqmdPND4UQfb04igcotH+dw+IFr417yP6muCLE8/5/Qlfnx0w==", "dev": true, "requires": { - "tslib": "^1.8.1" + "tslib": "1.9.0" } }, "typemoq": { @@ -5086,9 +5086,9 @@ "integrity": "sha512-DtRNLb7x8yCTv/KHlwes+NI+aGb4Vl1iPC63Hhtcvk1DpxSAZzKWQv0RQFY0jX2Uqj0SDBNl8Na4e6MV6TNDgw==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "lodash": "^4.17.4", - "postinstall-build": "^5.0.1" + "circular-json": "0.3.3", + "lodash": "4.17.10", + "postinstall-build": "5.0.1" }, "dependencies": { "lodash": { @@ -5117,8 +5117,8 @@ "integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=", "dev": true, "requires": { - "sprintf-js": "^1.0.3", - "util-deprecate": "^1.0.2" + "sprintf-js": "1.0.3", + "util-deprecate": "1.0.2" }, "dependencies": { "util-deprecate": { @@ -5135,10 +5135,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" }, "dependencies": { "arr-union": { @@ -5153,7 +5153,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "set-value": { @@ -5162,10 +5162,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" } } } @@ -5182,8 +5182,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" }, "dependencies": { "has-value": { @@ -5192,9 +5192,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" }, "dependencies": { "isobject": { @@ -5252,7 +5252,7 @@ "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", "dev": true, "requires": { - "user-home": "^1.1.1" + "user-home": "1.1.1" } }, "value-or-function": { @@ -5267,8 +5267,8 @@ "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", "dev": true, "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", + "clone": "1.0.4", + "clone-stats": "0.0.1", "replace-ext": "0.0.1" } }, @@ -5278,14 +5278,14 @@ "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", "dev": true, "requires": { - "defaults": "^1.0.0", - "glob-stream": "^3.1.5", - "glob-watcher": "^0.0.6", - "graceful-fs": "^3.0.0", - "mkdirp": "^0.5.0", - "strip-bom": "^1.0.0", - "through2": "^0.6.1", - "vinyl": "^0.4.0" + "defaults": "1.0.3", + "glob-stream": "3.1.18", + "glob-watcher": "0.0.6", + "graceful-fs": "3.0.11", + "mkdirp": "0.5.1", + "strip-bom": "1.0.0", + "through2": "0.6.5", + "vinyl": "0.4.6" }, "dependencies": { "clone": { @@ -5296,14 +5296,14 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", + "core-util-is": "1.0.2", + "inherits": "2.0.3", "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "string_decoder": "0.10.31" } }, "through2": { @@ -5312,8 +5312,8 @@ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" + "readable-stream": "1.0.34", + "xtend": "4.0.1" } }, "vinyl": { @@ -5322,8 +5322,8 @@ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" + "clone": "0.2.0", + "clone-stats": "0.0.1" } } } @@ -5334,13 +5334,13 @@ "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", "dev": true, "requires": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" + "append-buffer": "1.0.2", + "convert-source-map": "1.6.0", + "graceful-fs": "4.1.11", + "normalize-path": "2.1.1", + "now-and-later": "2.0.0", + "remove-bom-buffer": "3.0.0", + "vinyl": "2.1.0" }, "dependencies": { "clone": { @@ -5373,12 +5373,12 @@ "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", "dev": true, "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" + "clone": "2.1.1", + "clone-buffer": "1.0.0", + "clone-stats": "1.0.0", + "cloneable-readable": "1.1.1", + "remove-trailing-separator": "1.1.0", + "replace-ext": "1.0.0" } } } @@ -5388,7 +5388,7 @@ "resolved": "https://registry.npmjs.org/vscode-debugadapter/-/vscode-debugadapter-1.33.0-pre.3.tgz", "integrity": "sha512-/mhE1DUIPLdAbYzRa1jkloGnrmhpdv2gqrwZzGg0XW4Y4+vJI4IqiUY2DJGpV7ztXLx1DC8Z2RkY0ZN9HLVpeg==", "requires": { - "mkdirp": "^0.5.1", + "mkdirp": "0.5.1", "vscode-debugprotocol": "1.33.0-pre.0" }, "dependencies": { @@ -5415,17 +5415,17 @@ "integrity": "sha512-6XyESZOyNowLza/fV6Kfmwx0+0iNwa4OkTsBRepwP+eaR7JYnf/ohPaFDX7Egqe4330swtRDCbqr+7i3Q9/TvA==", "dev": true, "requires": { - "clone": "^2.1.1", - "event-stream": "^3.3.4", - "glob": "^7.1.2", - "gulp-util": "^3.0.8", - "iconv-lite": "^0.4.19", - "is": "^3.2.1", - "source-map": "^0.6.1", - "typescript": "^2.6.2", - "vinyl": "^2.1.0", - "xml2js": "^0.4.19", - "yargs": "^10.1.1" + "clone": "2.1.2", + "event-stream": "3.3.4", + "glob": "7.1.3", + "gulp-util": "3.0.8", + "iconv-lite": "0.4.24", + "is": "3.2.1", + "source-map": "0.6.1", + "typescript": "2.9.2", + "vinyl": "2.2.0", + "xml2js": "0.4.19", + "yargs": "10.1.2" }, "dependencies": { "clone": { @@ -5458,12 +5458,12 @@ "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" + "clone": "2.1.2", + "clone-buffer": "1.0.0", + "clone-stats": "1.0.0", + "cloneable-readable": "1.1.1", + "remove-trailing-separator": "1.1.0", + "replace-ext": "1.0.0" } } } @@ -5474,7 +5474,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, "which-module": { @@ -5491,12 +5491,12 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "string-width": "1.0.2", + "strip-ansi": "3.0.1" }, "dependencies": { "ansi-regex": { @@ -5511,7 +5511,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "string-width": { @@ -5520,9 +5520,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "strip-ansi": { @@ -5531,7 +5531,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } } } @@ -5546,7 +5546,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-6.0.0.tgz", "integrity": "sha512-c2UlYcAZp1VS8AORtpq6y4RJIkJ9dQz18W32SpR/qXGfLDZ2jU4y4wKvvZwqbi7U6gxFQTeE+urMbXU/tsDy4w==", "requires": { - "async-limiter": "~1.0.0" + "async-limiter": "1.0.0" } }, "xml2js": { @@ -5555,8 +5555,8 @@ "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", "dev": true, "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" + "sax": "1.2.4", + "xmlbuilder": "9.0.7" } }, "xmlbuilder": { @@ -5589,18 +5589,18 @@ "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^8.1.0" + "cliui": "4.1.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.3", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "8.1.0" } }, "yargs-parser": { @@ -5609,7 +5609,7 @@ "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" } } } diff --git a/src/chrome/breakOnLoadHelper.ts b/src/chrome/breakOnLoadHelper.ts index 3c69d2a68..64a41bdaa 100644 --- a/src/chrome/breakOnLoadHelper.ts +++ b/src/chrome/breakOnLoadHelper.ts @@ -5,16 +5,17 @@ import { logger } from 'vscode-debugadapter'; import { ISetBreakpointResult, BreakOnLoadStrategy } from '../debugAdapterInterfaces'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; import { ChromeDebugLogic } from './chromeDebugAdapter'; import * as ChromeUtils from './chromeUtils'; import * as assert from 'assert'; import { InternalSourceBreakpoint } from './internalSourceBreakpoint'; import { Version, parseResourceIdentifier } from '..'; -import { PausedEvent } from './target/events'; import { LocationInScript } from './internal/locations/location'; import { BreakpointsLogic } from './internal/breakpoints/breakpointsLogic'; import { IResourceIdentifier, newResourceIdentifierMap } from './internal/sources/resourceIdentifier'; +import { PausedEvent } from './cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; +import { IDOMInstrumentationBreakpoints } from './cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints'; export interface UrlRegexAndFileSet { urlRegex: string; @@ -35,7 +36,8 @@ export class BreakOnLoadHelper { private _breakOnLoadStrategy: BreakOnLoadStrategy; public constructor(chromeDebugAdapter: ChromeDebugLogic, breakOnLoadStrategy: BreakOnLoadStrategy, - public readonly _breakpointsLogic: BreakpointsLogic) { + public readonly _breakpointsLogic: BreakpointsLogic, + private readonly _domInstrumentationBreakpoints: IDOMInstrumentationBreakpoints) { this.validateStrategy(breakOnLoadStrategy); this._chromeDebugAdapter = chromeDebugAdapter; this._breakOnLoadStrategy = breakOnLoadStrategy; @@ -62,7 +64,7 @@ export class BreakOnLoadHelper { public async setBrowserVersion(version: Version): Promise { // On version 69 Chrome stopped sending an extra event for DOM Instrumentation: See https://bugs.chromium.org/p/chromium/issues/detail?id=882909 // On Chrome 68 we were relying on that event to make Break on load work on breakpoints on the first line of a file. On Chrome 69 we need an alternative way to make it work. - this._doesDOMInstrumentationRecieveExtraEvent = !version.isAtLeastVersion(69, 0); + this._doesDOMInstrumentationRecieveExtraEvent = !version.isAtLeastVersion('69.0.0'); } /** @@ -240,12 +242,12 @@ export class BreakOnLoadHelper { * Takes the action based on the strategy */ public async handleAddBreakpoints(url: IResourceIdentifier, breakpoints: InternalSourceBreakpoint[]): Promise<{ - breakpointId?: Crdp.Debugger.BreakpointId; + breakpointId?: CDTP.Debugger.BreakpointId; actualLocation?: LocationInScript; }[]> { // If the strategy is set to regex, we try to match the file where user put the breakpoint through a regex and tell Chrome to put a stop on entry breakpoint there if (this._breakOnLoadStrategy === 'regex') { - await this.addStopOnEntryBreakpoint(url); + await this.addStopOnEntryBreakpoint(url); } else if (this._breakOnLoadStrategy === 'instrument') { // Else if strategy is to use Chrome's experimental instrumentation API, we stop on all the scripts at the first statement before execution if (!this.instrumentationBreakpointSet) { @@ -262,12 +264,12 @@ export class BreakOnLoadHelper { * Only used when using instrument approach for break on load */ private async setInstrumentationBreakpoint(): Promise { - await this._chromeDebugAdapter.chrome.DOMDebugger.setInstrumentationBreakpoint({eventName: 'scriptFirstStatement'}); + await this._domInstrumentationBreakpoints.setInstrumentationBreakpoint({ eventName: 'scriptFirstStatement' }); this._instrumentationBreakpointSet = true; } // Sets a breakpoint on (0,0) for the files matching the given regex - private async setStopOnEntryBreakpoint(_urlRegex: string): Promise { + private async setStopOnEntryBreakpoint(_urlRegex: string): Promise { // DIEGO TODO: Re-enable this code // let result = await this._chromeDebugAdapter.chrome.Debugger.setBreakpointByUrl({ urlRegex, lineNumber: 0, columnNumber: 0 }); // return result; diff --git a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts new file mode 100644 index 000000000..15b41a189 --- /dev/null +++ b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts @@ -0,0 +1,11 @@ +import { IScript } from '../internal/scripts/script'; +import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; +import { URLRegexp } from '../internal/locations/subtypes'; +import { AlwaysBreak, ConditionalBreak } from '../internal/breakpoints/bpActionWhenHit'; +import { URL } from '../internal/sources/resourceIdentifier'; +import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; + +export type integer = number; +export type CDTPSupportedResources = IScript | URL | URLRegexp; +export type CDTPSupportedHitActions = AlwaysBreak | ConditionalBreak; +export type CDTPBPRecipie = IBPRecipie; \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts new file mode 100644 index 000000000..0478fd4c4 --- /dev/null +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts @@ -0,0 +1,79 @@ +import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; +import { Protocol as CDTP } from 'devtools-protocol'; +import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; +import { inject, injectable } from 'inversify'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { IScript } from '../../internal/scripts/script'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; + +export type ConsoleAPIEventType = 'log' | 'debug' | 'info' | 'error' | 'warning' | 'dir' | 'dirxml' | 'table' | 'trace' | 'clear' | 'startGroup' | 'startGroupCollapsed' | 'endGroup' | 'assert' | 'profile' | 'profileEnd' | 'count' | 'timeEnd'; + +export interface ConsoleAPICalledEvent { + readonly type: ConsoleAPIEventType; + readonly args: CDTP.Runtime.RemoteObject[]; + readonly executionContextId: CDTP.Runtime.ExecutionContextId; + readonly timestamp: CDTP.Runtime.Timestamp; + readonly stackTrace?: CodeFlowStackTrace; + readonly context?: string; +} + +export type onMessageAddedListener = (message: CDTP.Console.MessageAddedEvent) => void; +export type onConsoleAPICalled = (message: ConsoleAPICalledEvent) => void; + +export interface IConsoleEventsProvider { + onMessageAdded(listener: onMessageAddedListener): void; + onConsoleAPICalled(listener: onConsoleAPICalled): void; +} + +class CDTPConsoleEventsFromConsoleProvider extends CDTPEventsEmitterDiagnosticsModule { + protected readonly api = this._protocolApi.Console; + + public readonly onMessageAdded = this.addApiListener('messageAdded', (params: CDTP.Console.MessageAddedEvent) => params); + + constructor( + private readonly _protocolApi: CDTP.ProtocolApi, + domainsEnabler: CDTPDomainsEnabler) { + super(domainsEnabler); + } +} + +class CDTPConsoleEventsFromRuntimeProvider extends CDTPEventsEmitterDiagnosticsModule { + protected readonly api = this._protocolApi.Runtime; + private readonly _stackTraceParser = new CDTPStackTraceParser(this._scriptsRegistry); + + public readonly onConsoleAPICalled = this.addApiListener('consoleAPICalled', async (params: CDTP.Runtime.ConsoleAPICalledEvent) => + ({ + args: params.args, + context: params.context, + executionContextId: params.executionContextId, + timestamp: params.timestamp, + type: params.type, + stackTrace: params.stackTrace && await this._stackTraceParser.toStackTraceCodeFlow(params.stackTrace) + })); + + constructor( + private readonly _protocolApi: CDTP.ProtocolApi, + private _scriptsRegistry: CDTPScriptsRegistry, + domainsEnabler: CDTPDomainsEnabler, + ) { + super(domainsEnabler); + } +} + +@injectable() +export class CDTPConsoleEventsProvider implements IConsoleEventsProvider { + private readonly _consoleEventsFromConsoleProvider = new CDTPConsoleEventsFromConsoleProvider(this._protocolApi, this._domainsEnabler); + private readonly _consoleEventsFromRuntimeProvider = new CDTPConsoleEventsFromRuntimeProvider(this._protocolApi, this._scriptsRegistry, this._domainsEnabler); + + public readonly onMessageAdded = (listener: onMessageAddedListener) => this._consoleEventsFromConsoleProvider.onMessageAdded(listener); + public readonly onConsoleAPICalled = (listener: onConsoleAPICalled) => this._consoleEventsFromRuntimeProvider.onConsoleAPICalled(listener); + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: CDTP.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) private _scriptsRegistry: CDTPScriptsRegistry, + @inject(TYPES.IDomainsEnabler) private readonly _domainsEnabler: CDTPDomainsEnabler, + ) { + } +} diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts new file mode 100644 index 000000000..3f8e456aa --- /dev/null +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts @@ -0,0 +1,101 @@ +import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; +import { asyncMap } from '../../collections/async'; +import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; +import { adaptToSinglIntoToMulti } from '../../../utils'; +import { AnyBPRecipie } from '../../internal/breakpoints/bpRecipie'; +import { CDTPBreakpointIdsRegistry } from '../registries/cdtpBreakpointIdsRegistry'; +import { ScriptCallFrame, ICallFrame, CodeFlowFrame } from '../../internal/stackTraces/callFrame'; +import { asyncUndefinedOnFailure } from '../../utils/failures'; +import { CDTPLocationParser } from '../protocolParsers/cdtpLocationParser'; +import { Scope } from '../../internal/stackTraces/scopes'; +import { IScript } from '../../internal/scripts/script'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { Protocol as CDTP } from 'devtools-protocol'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; +import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; + +export type PauseEventReason = 'XHR' | 'DOM' | 'EventListener' | 'exception' | 'assert' | 'debugCommand' | 'promiseRejection' | 'OOM' | 'other' | 'ambiguous'; + +export class PausedEvent { + constructor( + public readonly callFrames: ICallFrame[], + public readonly reason: PauseEventReason, + public readonly data: any, + public readonly hitBreakpoints: AnyBPRecipie[], + public readonly asyncStackTrace: CodeFlowStackTrace | undefined, + public readonly asyncStackTraceId: CDTP.Runtime.StackTraceId | undefined, + public readonly asyncCallStackTraceId: CDTP.Runtime.StackTraceId | undefined) { } +} + +export interface ICDTDebuggeeExecutionEventsProvider { + onPaused(listener: (event: PausedEvent) => void): void; + onResumed(listener: () => void): void; +} + +@injectable() +export class CDTDebuggeeExecutionEventsProvider extends CDTPEventsEmitterDiagnosticsModule implements ICDTDebuggeeExecutionEventsProvider { + protected readonly api = this._protocolApi.Debugger; + + private readonly _cdtpLocationParser = new CDTPLocationParser(this._scriptsRegistry); + private readonly _stackTraceParser = new CDTPStackTraceParser(this._scriptsRegistry); + + private getBPsFromIDs = adaptToSinglIntoToMulti(this, this.getBPFromID); + + public readonly onPaused = this.addApiListener('paused', async (params: CDTP.Debugger.PausedEvent) => { + if (params.callFrames.length === 0) { + throw new Error(`Expected a pause event to have at least a single call frame: ${JSON.stringify(params)}`); + } + + const callFrames = await asyncMap(params.callFrames, (callFrame, index) => this.toCallFrame(index, callFrame)); + + return new PausedEvent(callFrames, params.reason, params.data, this.getBPsFromIDs(params.hitBreakpoints), + params.asyncStackTrace && await this._stackTraceParser.toStackTraceCodeFlow(params.asyncStackTrace), + params.asyncStackTraceId, params.asyncCallStackTraceId); + }); + + public readonly onResumed = this.addApiListener('resumed', (params: void) => params); + + public readonly onScriptFailedToParse = this.addApiListener('resumed', (params: CDTP.Debugger.ScriptFailedToParseEvent) => params); + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: CDTP.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) private _scriptsRegistry: CDTPScriptsRegistry, + @inject(CDTPBreakpointIdsRegistry) private readonly _breakpointIdRegistry: CDTPBreakpointIdsRegistry, + @inject(CDTPCallFrameRegistry) private readonly _callFrameRegistry: CDTPCallFrameRegistry, + @inject(TYPES.IDomainsEnabler) domainsEnabler: CDTPDomainsEnabler, + ) { + super(domainsEnabler); + } + + private getBPFromID(hitBreakpoint: CDTP.Debugger.BreakpointId): AnyBPRecipie { + return this._breakpointIdRegistry.getRecipieByBreakpointId(hitBreakpoint); + } + + private async toCallFrame(index: number, callFrame: CDTP.Debugger.CallFrame): Promise> { + const frame = new ScriptCallFrame(await this.toCodeFlowFrame(index, callFrame), + await asyncMap(callFrame.scopeChain, scope => this.toScope(scope)), + callFrame.this, callFrame.returnValue); + + this._callFrameRegistry.registerFrameId(callFrame.callFrameId, frame); + + return frame; + } + + private toCodeFlowFrame(index: number, callFrame: CDTP.Debugger.CallFrame): Promise> { + return this._stackTraceParser.toCodeFlowFrame(index, callFrame, callFrame.location); + } + + private async toScope(scope: CDTP.Debugger.Scope): Promise { + return { + type: scope.type, + object: scope.object, + name: scope.name, + // TODO FILE BUG: Chrome sometimes returns line -1 when the doc says it's 0 based + startLocation: await asyncUndefinedOnFailure(async () => scope.startLocation && await this._cdtpLocationParser.getLocationInScript(scope.startLocation)), + endLocation: await asyncUndefinedOnFailure(async () => scope.endLocation && await this._cdtpLocationParser.getLocationInScript(scope.endLocation)) + }; + } +} \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts new file mode 100644 index 000000000..434523e26 --- /dev/null +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts @@ -0,0 +1,67 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; +import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { integer } from '../cdtpPrimitives'; +import { IScript } from '../../internal/scripts/script'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; + +export interface ExceptionThrownEvent { + readonly timestamp: CDTP.Runtime.Timestamp; + readonly exceptionDetails: ExceptionDetails; +} + +export interface ExceptionDetails { + readonly exceptionId: integer; + readonly text: string; + readonly lineNumber: integer; + readonly columnNumber: integer; + readonly script?: IScript; + readonly url?: string; + readonly stackTrace?: CodeFlowStackTrace; + readonly exception?: CDTP.Runtime.RemoteObject; + readonly executionContextId?: CDTP.Runtime.ExecutionContextId; +} + +export interface IExceptionThrownEventProvider { + onExceptionThrown(listener: (event: ExceptionThrownEvent) => void): void; +} + +@injectable() +export class CDTPExceptionThrownEventsProvider extends CDTPEventsEmitterDiagnosticsModule implements IExceptionThrownEventProvider { + protected readonly api = this.protocolApi.Runtime; + + private readonly _stackTraceParser = new CDTPStackTraceParser(this._scriptsRegistry); + + public readonly onExceptionThrown = this.addApiListener('exceptionThrown', async (params: CDTP.Runtime.ExceptionThrownEvent) => + ({ + timestamp: params.timestamp, + exceptionDetails: await this.toExceptionDetails(params.exceptionDetails) + })); + + constructor( + @inject(TYPES.CDTPClient) private readonly protocolApi: CDTP.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) private _scriptsRegistry: CDTPScriptsRegistry, + @inject(TYPES.IDomainsEnabler) domainsEnabler: CDTPDomainsEnabler, + ) { + super(domainsEnabler); + } + + private async toExceptionDetails(exceptionDetails: CDTP.Runtime.ExceptionDetails): Promise { + return { + exceptionId: exceptionDetails.exceptionId, + text: exceptionDetails.text, + lineNumber: exceptionDetails.lineNumber, + columnNumber: exceptionDetails.columnNumber, + script: exceptionDetails.scriptId ? await this._scriptsRegistry.getScriptByCdtpId(exceptionDetails.scriptId) : undefined, + url: exceptionDetails.url, + stackTrace: exceptionDetails.stackTrace && await this._stackTraceParser.toStackTraceCodeFlow(exceptionDetails.stackTrace), + exception: exceptionDetails.exception, + executionContextId: exceptionDetails.executionContextId, + }; + } +} \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider.ts new file mode 100644 index 000000000..8ee9db842 --- /dev/null +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider.ts @@ -0,0 +1,28 @@ +import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; +import { Protocol as CDTP } from 'devtools-protocol'; + +import { inject, injectable } from 'inversify'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; + +@injectable() +export class CDTPExecutionContextEventsProvider extends CDTPEventsEmitterDiagnosticsModule { + protected readonly api = this._protocolApi.Runtime; + + public readonly onExecutionContextsCleared = this.addApiListener('executionContextsCleared', (params: void) => params); + + public readonly onExecutionContextDestroyed = this.addApiListener('executionContextDestroyed', async (params: CDTP.Runtime.ExecutionContextDestroyedEvent) => + this._scriptsRegistry.markExecutionContextAsDestroyed(params.executionContextId)); + + public readonly onExecutionContextCreated = this.addApiListener('executionContextCreated', async (params: CDTP.Runtime.ExecutionContextCreatedEvent) => + this._scriptsRegistry.registerExecutionContext(params.context.id)); + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: CDTP.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry, + @inject(TYPES.IDomainsEnabler) domainsEnabler: CDTPDomainsEnabler, + ) { + super(domainsEnabler); + } +} \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts new file mode 100644 index 000000000..1552a9b86 --- /dev/null +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts @@ -0,0 +1,62 @@ +import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; +import { Protocol as CDTP } from 'devtools-protocol'; + +import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; +import { integer } from '../cdtpPrimitives'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { IScript } from '../../internal/scripts/script'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { inject } from 'inversify'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; + +export type LogEntrySource = 'xml' | 'javascript' | 'network' | 'storage' | 'appcache' | 'rendering' | 'security' | 'deprecation' | 'worker' | 'violation' | 'intervention' | 'recommendation' | 'other'; +export type LogLevel = 'verbose' | 'info' | 'warning' | 'error'; + +export interface LogEntry { + readonly source: LogEntrySource; + readonly level: LogLevel; + readonly text: string; + readonly timestamp: CDTP.Runtime.Timestamp; + readonly url?: string; + readonly lineNumber?: integer; + readonly stackTrace?: CodeFlowStackTrace; + readonly networkRequestId?: CDTP.Network.RequestId; + readonly workerId?: string; + readonly args?: CDTP.Runtime.RemoteObject[]; +} + +export interface ILogEventsProvider { + onEntryAdded(listener: (entry: LogEntry) => void): void; +} + +export class CDTPLogEventsProvider extends CDTPEventsEmitterDiagnosticsModule implements ILogEventsProvider { + protected readonly api = this._protocolApi.Log; + + private readonly _stackTraceParser = new CDTPStackTraceParser(this._scriptsRegistry); + + public readonly onEntryAdded = this.addApiListener('entryAdded', async (params: CDTP.Log.EntryAddedEvent) => await this.toLogEntry(params.entry)); + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: CDTP.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) private _scriptsRegistry: CDTPScriptsRegistry, + @inject(TYPES.IDomainsEnabler) domainsEnabler: CDTPDomainsEnabler, + ) { + super(domainsEnabler); + } + + private async toLogEntry(entry: CDTP.Log.LogEntry): Promise { + return { + source: entry.source, + level: entry.level, + text: entry.text, + timestamp: entry.timestamp, + url: entry.url, + lineNumber: entry.lineNumber, + networkRequestId: entry.networkRequestId, + workerId: entry.workerId, + args: entry.args, + stackTrace: entry.stackTrace && await this._stackTraceParser.toStackTraceCodeFlow(entry.stackTrace), + }; + } +} diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts new file mode 100644 index 000000000..b62aaa4e8 --- /dev/null +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts @@ -0,0 +1,116 @@ +import { CDTP, parseResourceIdentifier, BasePathTransformer, BaseSourceMapTransformer } from '../../..'; +import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { IScript, Script } from '../../internal/scripts/script'; +import { createCDTPScriptUrl } from '../../internal/sources/resourceIdentifierSubtypes'; +import { SourcesMapper, NoSourceMapping as NoSourcesMapper } from '../../internal/scripts/sourcesMapper'; +import { ResourceName } from '../../internal/sources/resourceIdentifier'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; +import { inject } from 'inversify'; +import { integer } from '../cdtpPrimitives'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { IExecutionContext } from '../../internal/scripts/executionContext'; +import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; + +/** + * A new JavaScript Script has been parsed by the debugee and it's about to be executed + */ +export interface ScriptParsedEvent { + readonly script: IScript; + readonly url: string; + readonly startLine: integer; + readonly startColumn: integer; + readonly endLine: integer; + readonly endColumn: integer; + readonly executionContext: IExecutionContext; + readonly hash: string; + readonly executionContextAuxData?: any; + readonly isLiveEdit?: boolean; + readonly sourceMapURL?: string; + readonly hasSourceURL?: boolean; + readonly isModule?: boolean; + readonly length?: integer; + readonly stackTrace?: CodeFlowStackTrace; +} + +export type ScriptParsedListener = (params: ScriptParsedEvent) => void; + +export interface IScriptParsedProvider { + onScriptParsed(listener: (event: ScriptParsedEvent) => void): void; +} + +export class CDTPOnScriptParsedEventProvider extends CDTPEventsEmitterDiagnosticsModule implements IScriptParsedProvider { + protected readonly api = this._protocolApi.Debugger; + + private readonly _stackTraceParser = new CDTPStackTraceParser(this._scriptsRegistry); + + public onScriptParsed = this.addApiListener('scriptParsed', async (params: CDTP.Debugger.ScriptParsedEvent) => { + await this.createAndRegisterScript(params); + + return await this.toScriptParsedEvent(params); + }); + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: CDTP.ProtocolApi, + @inject(TYPES.BasePathTransformer) private readonly _pathTransformer: BasePathTransformer, + @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, + @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry, + @inject(TYPES.IDomainsEnabler) domainsEnabler: CDTPDomainsEnabler, + ) { + super(domainsEnabler); + } + + private async createAndRegisterScript(params: CDTP.Debugger.ScriptParsedEvent): Promise { + // The stack trace and hash can be large and the DA doesn't need it. + delete params.stackTrace; + delete params.hash; + + const executionContext = this._scriptsRegistry.getExecutionContextById(params.executionContextId); + + const script = await this._scriptsRegistry.registerScript(params.scriptId, async () => { + if (params.url !== undefined && params.url !== '') { + const runtimeSourceLocation = parseResourceIdentifier(createCDTPScriptUrl(params.url)); + const developmentSourceLocation = await this._pathTransformer.scriptParsed(runtimeSourceLocation); + const sourceMap = await this._sourceMapTransformer.scriptParsed(runtimeSourceLocation.canonicalized, params.sourceMapURL); + const sourceMapper = sourceMap + ? new SourcesMapper(sourceMap) + : new NoSourcesMapper(); + + const runtimeScript = Script.create(executionContext, runtimeSourceLocation, developmentSourceLocation, sourceMapper); + return runtimeScript; + } else { + const sourceMap = await this._sourceMapTransformer.scriptParsed('', params.sourceMapURL); + const sourceMapper = sourceMap + ? new SourcesMapper(sourceMap) + : new NoSourcesMapper(); + const runtimeScript = Script.createEval(executionContext, new ResourceName(createCDTPScriptUrl(params.scriptId)), sourceMapper); + return runtimeScript; + } + }); + + return script; + } + + private async toScriptParsedEvent(params: CDTP.Debugger.ScriptParsedEvent): Promise { + const executionContext = this._scriptsRegistry.getExecutionContextById(params.executionContextId); + + return { + url: params.url, + startLine: params.startLine, + startColumn: params.startColumn, + endLine: params.endLine, + endColumn: params.endColumn, + executionContext: executionContext, + hash: params.hash, + executionContextAuxData: params.executionContextAuxData, + isLiveEdit: params.isLiveEdit, + sourceMapURL: params.sourceMapURL, + hasSourceURL: params.hasSourceURL, + isModule: params.isModule, + length: params.length, + script: await this._scriptsRegistry.getScriptByCdtpId(params.scriptId), + stackTrace: params.stackTrace && await this._stackTraceParser.toStackTraceCodeFlow(params.stackTrace) + }; + } +} \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/features/CDTPSchema.ts b/src/chrome/cdtpDebuggee/features/CDTPSchema.ts new file mode 100644 index 000000000..920845245 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/CDTPSchema.ts @@ -0,0 +1,9 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +export class CDTPSchema { + constructor(protected api: CDTP.SchemaApi) { } + + public async getDomains(): Promise { + return (await this.api.getDomains()).domains; + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer.ts b/src/chrome/cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer.ts new file mode 100644 index 000000000..6ce247294 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer.ts @@ -0,0 +1,21 @@ +import { Protocol as CDTP } from 'devtools-protocol'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; + +export interface IAsyncDebuggingConfigurer { + setAsyncCallStackDepth(maxDepth: CDTP.integer): Promise; +} + +@injectable() +export class CDTPAsyncDebuggingConfigurer implements IAsyncDebuggingConfigurer { + protected readonly api = this._protocolApi.Debugger; + + constructor( + @inject(TYPES.CDTPClient) + private readonly _protocolApi: CDTP.ProtocolApi) { + } + + public setAsyncCallStackDepth(maxDepth: CDTP.integer): Promise { + return this.api.setAsyncCallStackDepth({ maxDepth }); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts b/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts new file mode 100644 index 000000000..c973a29ee --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts @@ -0,0 +1,30 @@ +import { Protocol as CDTP } from 'devtools-protocol'; +import { IScript } from '../../internal/scripts/script'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; + +export interface IBlackboxPatternsConfigurer { + setBlackboxPatterns(params: CDTP.Debugger.SetBlackboxPatternsRequest): Promise; + setBlackboxedRanges(script: IScript, positions: CDTP.Debugger.ScriptPosition[]): Promise; +} + +@injectable() +export class CDTPBlackboxPatternsConfigurer implements IBlackboxPatternsConfigurer { + protected readonly api = this._protocolApi.Debugger; + + constructor( + @inject(TYPES.CDTPClient) + private readonly _protocolApi: CDTP.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) + private readonly _scriptsRegistry: CDTPScriptsRegistry) { + } + + public setBlackboxedRanges(script: IScript, positions: CDTP.Debugger.ScriptPosition[]): Promise { + return this.api.setBlackboxedRanges({ scriptId: this._scriptsRegistry.getCdtpId(script), positions: positions }); + } + + public setBlackboxPatterns(params: CDTP.Debugger.SetBlackboxPatternsRequest): Promise { + return this.api.setBlackboxPatterns(params); + } +} diff --git a/src/chrome/target/breakpointFeaturesSupport.ts b/src/chrome/cdtpDebuggee/features/cdtpBreakpointFeaturesSupport.ts similarity index 68% rename from src/chrome/target/breakpointFeaturesSupport.ts rename to src/chrome/cdtpDebuggee/features/cdtpBreakpointFeaturesSupport.ts index 5d976b8dd..df6853739 100644 --- a/src/chrome/target/breakpointFeaturesSupport.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpBreakpointFeaturesSupport.ts @@ -1,18 +1,24 @@ -import { Crdp, utils } from '../..'; import { injectable, inject } from 'inversify'; -import { TYPES } from '../dependencyInjection.ts/types'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { Protocol as CDTP } from 'devtools-protocol'; +import * as utils from '../../../utils'; export interface IBreakpointFeaturesSupport { supportsColumnBreakpoints: Promise; } @injectable() -export class BreakpointFeaturesSupport implements IBreakpointFeaturesSupport { +export class CDTPBreakpointFeaturesSupport implements IBreakpointFeaturesSupport { private result = utils.promiseDefer(); public supportsColumnBreakpoints = this.result.promise; - private async onScriptParsed(params: Crdp.Debugger.ScriptParsedEvent): Promise { + constructor( + @inject(TYPES.CDTPClient) private readonly api: CDTP.ProtocolApi) { + api.Debugger.on('scriptParsed', params => this.onScriptParsed(params)); + } + + private async onScriptParsed(params: CDTP.Debugger.ScriptParsedEvent): Promise { const scriptId = params.scriptId; try { @@ -21,14 +27,10 @@ export class BreakpointFeaturesSupport implements IBreakpointFeaturesSupport { end: { scriptId, lineNumber: 1, columnNumber: 0 }, restrictToFunction: false }); + this.result.resolve(true); } catch (e) { this.result.resolve(false); } } - - constructor( - @inject(TYPES.CDTPClient) protected readonly api: Crdp.ProtocolApi) { - api.Debugger.on('scriptParsed', params => this.onScriptParsed(params)); - } } \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/features/cdtpBrowserNavigator.ts b/src/chrome/cdtpDebuggee/features/cdtpBrowserNavigator.ts new file mode 100644 index 000000000..64eb07fe9 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpBrowserNavigator.ts @@ -0,0 +1,35 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; +import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; + +export interface IBrowserNavigator { + navigate(params: CDTP.Page.NavigateRequest): Promise; + reload(params: CDTP.Page.ReloadRequest): Promise; + onFrameNavigated(listener: (params: CDTP.Page.FrameNavigatedEvent) => void): void; +} + +@injectable() +export class CDTPBrowserNavigator extends CDTPEventsEmitterDiagnosticsModule implements IBrowserNavigator { + protected api = this._protocolApi.Page; + + public readonly onFrameNavigated = this.addApiListener('frameNavigated', (params: CDTP.Page.FrameNavigatedEvent) => params); + + constructor( + @inject(TYPES.CDTPClient) + protected _protocolApi: CDTP.ProtocolApi, + @inject(TYPES.IDomainsEnabler) domainsEnabler: CDTPDomainsEnabler, + ) { + super(domainsEnabler); + } + + public navigate(params: CDTP.Page.NavigateRequest): Promise { + return this.api.navigate(params); + } + + public reload(params: CDTP.Page.ReloadRequest): Promise { + return this.api.reload(params); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints.ts new file mode 100644 index 000000000..43f1202c2 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints.ts @@ -0,0 +1,26 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; + +export interface IDOMInstrumentationBreakpoints { + setInstrumentationBreakpoint(params: CDTP.DOMDebugger.SetInstrumentationBreakpointRequest): Promise; + removeInstrumentationBreakpoint(params: CDTP.DOMDebugger.SetInstrumentationBreakpointRequest): Promise; +} + +@injectable() +export class CDTPDOMDebugger implements IDOMInstrumentationBreakpoints { + protected api = this._protocolApi.DOMDebugger; + + constructor( + @inject(TYPES.CDTPClient) + protected _protocolApi: CDTP.ProtocolApi) { } + + public setInstrumentationBreakpoint(params: CDTP.DOMDebugger.SetInstrumentationBreakpointRequest): Promise { + return this.api.setInstrumentationBreakpoint(params); + } + + public removeInstrumentationBreakpoint(params: CDTP.DOMDebugger.SetInstrumentationBreakpointRequest): Promise { + return this.api.removeInstrumentationBreakpoint(params); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebugeeExecutionController.ts b/src/chrome/cdtpDebuggee/features/cdtpDebugeeExecutionController.ts new file mode 100644 index 000000000..6974880e2 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpDebugeeExecutionController.ts @@ -0,0 +1,23 @@ +import { Protocol as CDTP } from 'devtools-protocol'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; + +export interface IDebugeeExecutionController { + resume(): Promise; + pause(): Promise; +} + +@injectable() +export class CDTPDebugeeExecutionController implements IDebugeeExecutionController { + constructor( + @inject(TYPES.CDTPClient) protected readonly api: CDTP.ProtocolApi) { + } + + public resume(): Promise { + return this.api.Debugger.resume(); + } + + public pause(): Promise { + return this.api.Debugger.pause(); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts b/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts new file mode 100644 index 000000000..6fa8097f0 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts @@ -0,0 +1,26 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { Version } from '../../utils/Version'; + +export interface IDebugeeRuntimeVersionProvider { + version(): Promise; +} + +/// TODO: Move this to a browser-shared package +/// TODO: Update this so we automatically try to use ChromeConnection.version first, and then fallback to this if neccesary +@injectable() +export class CDTPDebugeeRuntimeVersionProvider implements IDebugeeRuntimeVersionProvider { + protected api = this._protocolApi.Browser; + + constructor( + @inject(TYPES.CDTPClient) + protected _protocolApi: CDTP.ProtocolApi) { + } + + public async version(): Promise { + // const version = productVersionText.replace(/Chrome\/([0-9]{2})\..*/, '$1'); + return Version.coerce((await this.api.getVersion()).product); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts b/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts new file mode 100644 index 000000000..60e76c87a --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts @@ -0,0 +1,43 @@ +import { Protocol as CDTP } from 'devtools-protocol'; +import { ICallFrame } from '../../internal/stackTraces/callFrame'; +import { IScript } from '../../internal/scripts/script'; +import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; + +export interface IDebugeeSteppingController { + stepOver(): Promise; + stepInto(params: { breakOnAsyncCall: boolean }): Promise; + stepOut(): Promise; + restartFrame(callFrame: ICallFrame): Promise; + pauseOnAsyncCall(params: CDTP.Debugger.PauseOnAsyncCallRequest): Promise; +} + +@injectable() +export class CDTPDebugeeSteppingController implements IDebugeeSteppingController { + constructor( + @inject(TYPES.CDTPClient) + protected readonly api: CDTP.ProtocolApi, + private readonly _callFrameRegistry: CDTPCallFrameRegistry) { + } + + public pauseOnAsyncCall(params: CDTP.Debugger.PauseOnAsyncCallRequest): Promise { + return this.api.Debugger.pauseOnAsyncCall(params); + } + + public stepOver(): Promise { + return this.api.Debugger.stepOver(); + } + + public stepInto(params: CDTP.Debugger.StepIntoRequest): Promise { + return this.api.Debugger.stepInto(params); + } + + public stepOut(): Promise { + return this.api.Debugger.stepOut(); + } + + public restartFrame(frame: ICallFrame): Promise { + return this.api.Debugger.restartFrame({ callFrameId: this._callFrameRegistry.getFrameId(frame) }); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts new file mode 100644 index 000000000..721e774a9 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts @@ -0,0 +1,136 @@ +import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp, BPRecipie, IBPRecipie } from '../../internal/breakpoints/bpRecipie'; +import { AlwaysBreak, ConditionalBreak } from '../../internal/breakpoints/bpActionWhenHit'; +import { BreakpointInScript, BreakpointInUrl, BreakpointInUrlRegexp, Breakpoint } from '../../internal/breakpoints/breakpoint'; +import { RangeInScript } from '../../internal/locations/rangeInScript'; +import { LocationInScript } from '../../internal/locations/location'; +import { Protocol as CDTP } from 'devtools-protocol'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { inject, injectable } from 'inversify'; +import { CDTPBreakpointIdsRegistry } from '../registries/cdtpBreakpointIdsRegistry'; +import { asyncMap } from '../../collections/async'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { CDTPLocationParser } from '../protocolParsers/cdtpLocationParser'; +import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; +import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; +import { Coordinates } from '../../internal/locations/location'; +import { singleOne } from '../../collections/utilities'; +import { CDTPSupportedResources, CDTPSupportedHitActions } from '../cdtpPrimitives'; + +type SetBPInCDTPCall = (resource: TResource, position: Coordinates, cdtpConditionField: string) => Promise; + +export interface IDebuggeeBreakpoints { + setBreakpoint(bpRecipie: BPRecipieInScript): Promise; + setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise; + setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise; + getPossibleBreakpoints(rangeInScript: RangeInScript): Promise; + removeBreakpoint(bpRecipie: BPRecipie): Promise; +} + +interface BreakpointClass { + new(recipie: IBPRecipie, actualLocation: LocationInScript): Breakpoint; +} + +@injectable() +export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule implements IDebuggeeBreakpoints { + protected readonly api = this.protocolApi.Debugger; + + private readonly _cdtpLocationParser = new CDTPLocationParser(this._scriptsRegistry); + + public readonly onBreakpointResolved = this.addApiListener('breakpointResolved', async (params: CDTP.Debugger.BreakpointResolvedEvent) => { + const bpRecipie = this._breakpointIdRegistry.getRecipieByBreakpointId(params.breakpointId); + const breakpoint = new Breakpoint(bpRecipie, + await this.toLocationInScript(params.location)); + return breakpoint; + }); + + constructor( + @inject(TYPES.CDTPClient) protected readonly protocolApi: CDTP.ProtocolApi, + @inject(CDTPBreakpointIdsRegistry) private readonly _breakpointIdRegistry: CDTPBreakpointIdsRegistry, + @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry, + @inject(TYPES.IDomainsEnabler) domainsEnabler: CDTPDomainsEnabler, + ) { + super(domainsEnabler); + } + + public async setBreakpoint(bpRecipie: BPRecipieInScript): Promise { + const breakpoints = await this.setBreakpointHelper(BreakpointInScript, bpRecipie, async (_resource, _position, cdtpConditionField) => { + const response = await this.api.setBreakpoint({ location: this.toCrdpLocation(bpRecipie.location), condition: cdtpConditionField }); + return { breakpointId: response.breakpointId, locations: [response.actualLocation] }; + }); + + return singleOne(breakpoints); + } + + public async setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise { + return this.setBreakpointHelper(BreakpointInUrl, bpRecipie, (resource, position, cdtpConditionField) => + this.api.setBreakpointByUrl({ + url: resource.textRepresentation, lineNumber: position.lineNumber, + columnNumber: position.columnNumber, condition: cdtpConditionField + })); + } + + public async setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise { + return this.setBreakpointHelper(BreakpointInUrlRegexp, bpRecipie, (resource, position, cdtpConditionField) => + this.api.setBreakpointByUrl({ + urlRegex: resource, lineNumber: position.lineNumber, + columnNumber: position.columnNumber, condition: cdtpConditionField + })); + } + + private async setBreakpointHelper + (classToUse: BreakpointClass, bpRecipie: IBPRecipie, + setBPInCDTPCall: SetBPInCDTPCall): Promise[]> { + const cdtpConditionField = this.getCDTPConditionField(bpRecipie); + const resource = bpRecipie.location.resource; // TODO: Figure out why the is needed and remove it + const coordinates = bpRecipie.location.coordinates; + + const response = await setBPInCDTPCall(resource, coordinates, cdtpConditionField); + + /* + * We need to call registerRecipie sync with the response, before any awaits so if we get an event with + * a breakpointId we'll be able to resolve it properly + */ + this._breakpointIdRegistry.registerRecipie(response.breakpointId, bpRecipie); + + return Promise.all(response.locations.map(cdtpLocation => this.toBreakpoinInResource(classToUse, bpRecipie, cdtpLocation))); + } + + public async getPossibleBreakpoints(rangeInScript: RangeInScript): Promise { + const response = await this.api.getPossibleBreakpoints({ + start: this.toCrdpLocation(rangeInScript.startInScript), + end: this.toCrdpLocation(rangeInScript.endInScript) + }); + + return asyncMap(response.locations, async location => await this.toLocationInScript(location)); + } + + public async removeBreakpoint(bpRecipie: BPRecipie): Promise { + await this.api.removeBreakpoint({ breakpointId: this._breakpointIdRegistry.getBreakpointId(bpRecipie) }); + this._breakpointIdRegistry.unregisterRecipie(bpRecipie); + } + + private getCDTPConditionField(bpRecipie: IBPRecipie): string | undefined { + return bpRecipie.bpActionWhenHit.basedOnTypeDo({ + alwaysBreak: () => undefined, + conditionalBreak: conditionalBreak => conditionalBreak.expressionOfWhenToBreak + }); + } + + private async toBreakpoinInResource(classToUse: BreakpointClass, + bpRecipie: IBPRecipie, actualLocation: CDTP.Debugger.Location): Promise> { + const breakpoint = new classToUse(bpRecipie, await this.toLocationInScript(actualLocation)); + return breakpoint; + } + + private toCrdpLocation(location: LocationInScript): CDTP.Debugger.Location { + return { + scriptId: this._scriptsRegistry.getCdtpId(location.script), + lineNumber: location.lineNumber, + columnNumber: location.columnNumber + }; + } + + public toLocationInScript(location: CDTP.Debugger.Location): Promise { + return this._cdtpLocationParser.getLocationInScript(location); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts b/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts new file mode 100644 index 000000000..814c711ba --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts @@ -0,0 +1,78 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; +import { injectable, inject } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { ICallFrame, ScriptOrLoadedSource } from '../../internal/stackTraces/callFrame'; + +export interface EvaluateOnCallFrameRequest { + readonly frame: ICallFrame; + readonly expression: string; + readonly objectGroup?: string; + readonly includeCommandLineAPI?: boolean; + readonly silent?: boolean; + readonly returnByValue?: boolean; + readonly generatePreview?: boolean; + readonly throwOnSideEffect?: boolean; + readonly timeout?: CDTP.Runtime.TimeDelta; +} + +export interface IInspectDebugeeState { + callFunctionOn(params: CDTP.Runtime.CallFunctionOnRequest): Promise; + getProperties(params: CDTP.Runtime.GetPropertiesRequest): Promise; + evaluate(params: CDTP.Runtime.EvaluateRequest): Promise; + evaluateOnCallFrame(params: EvaluateOnCallFrameRequest): Promise; +} + +export class AddSourceUriToExpession { + private nextEvaluateScriptId = 0; + + constructor(private readonly _prefix: string) { } + + public addURLIfMissing(expression: string): string { + const sourceUrlPrefix = '\n//# sourceURL='; + + if (expression.indexOf(sourceUrlPrefix) < 0) { + expression += `${sourceUrlPrefix}/${this._prefix}/id=${this.nextEvaluateScriptId++}`; + } + + return expression; + } +} + +@injectable() +export class CDTPInspectDebugeeState implements IInspectDebugeeState { + private addSourceUriToEvaluates = new AddSourceUriToExpession('evaluateOnFrame'); + + constructor( + @inject(TYPES.CDTPClient) protected readonly api: CDTP.ProtocolApi, + private readonly _callFrameRegistry: CDTPCallFrameRegistry) { + } + + public callFunctionOn(params: CDTP.Runtime.CallFunctionOnRequest): Promise { + return this.api.Runtime.callFunctionOn(params); + } + + public getProperties(params: CDTP.Runtime.GetPropertiesRequest): Promise { + return this.api.Runtime.getProperties(params); + } + + public evaluate(params: CDTP.Runtime.EvaluateRequest): Promise { + params.expression = this.addSourceUriToEvaluates.addURLIfMissing(params.expression); + return this.api.Runtime.evaluate(params); + } + + public evaluateOnCallFrame(params: EvaluateOnCallFrameRequest): Promise { + return this.api.Debugger.evaluateOnCallFrame({ + callFrameId: this._callFrameRegistry.getFrameId(params.frame.unmappedCallFrame), + expression: this.addSourceUriToEvaluates.addURLIfMissing(params.expression), + objectGroup: params.objectGroup, + includeCommandLineAPI: params.includeCommandLineAPI, + silent: params.silent, + returnByValue: params.returnByValue, + generatePreview: params.generatePreview, + throwOnSideEffect: params.throwOnSideEffect, + timeout: params.timeout, + }); + } +} \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/features/cdtpNetworkCacheConfiguration.ts b/src/chrome/cdtpDebuggee/features/cdtpNetworkCacheConfiguration.ts new file mode 100644 index 000000000..14c818396 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpNetworkCacheConfiguration.ts @@ -0,0 +1,22 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +export interface INetworkCacheConfiguration { + setCacheDisabled(params: CDTP.Network.SetCacheDisabledRequest): Promise; +} + +export class CDTPNetwork implements INetworkCacheConfiguration { + constructor(protected api: CDTP.NetworkApi) { + } + + public enable(parameters: CDTP.Network.EnableRequest): Promise { + return this.api.enable(parameters); + } + + public disable(): Promise { + return this.api.disable(); + } + + public setCacheDisabled(params: CDTP.Network.SetCacheDisabledRequest): Promise { + return this.api.setCacheDisabled(params); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts b/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts new file mode 100644 index 000000000..6299928b9 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts @@ -0,0 +1,36 @@ +import { Protocol as CDTP } from 'devtools-protocol'; +import { PauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions } from '../../internal/exceptions/strategies'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; + +export interface IPauseOnExceptionsConfigurer { + setPauseOnExceptions(strategy: PauseOnExceptionsStrategy): Promise; +} + +export type ExceptionCategories = 'none' | 'uncaught' | 'all'; + +@injectable() +export class CDTPPauseOnExceptionsConfigurer implements IPauseOnExceptionsConfigurer { + protected readonly api = this._protocolApi.Debugger; + + constructor( + @inject(TYPES.CDTPClient) + private readonly _protocolApi: CDTP.ProtocolApi) { + } + + public setPauseOnExceptions(strategy: PauseOnExceptionsStrategy): Promise { + let state: ExceptionCategories; + + if (strategy instanceof PauseOnAllExceptions) { + state = 'all'; + } else if (strategy instanceof PauseOnUnhandledExceptions) { + state = 'uncaught'; + } else if (strategy instanceof DoNotPauseOnAnyExceptions) { + state = 'none'; + } else { + throw new Error(`Can't pause on exception using an unknown strategy ${strategy}`); + } + + return this.api.setPauseOnExceptions({ state }); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpPausedOverlay.ts b/src/chrome/cdtpDebuggee/features/cdtpPausedOverlay.ts new file mode 100644 index 000000000..31be29214 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpPausedOverlay.ts @@ -0,0 +1,24 @@ +import { CDTPEnableableDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; +import { Protocol as CDTP } from 'devtools-protocol'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { inject } from 'inversify'; +import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; + +export interface IPausedOverlay { + setPausedInDebuggerMessage(params: CDTP.Overlay.SetPausedInDebuggerMessageRequest): Promise; +} + +// TODO: Move this to a browser shared package +export class CDTPOverlay extends CDTPEnableableDiagnosticsModule implements IPausedOverlay { + protected readonly api = this._protocolApi.Overlay; + + constructor( + @inject(TYPES.CDTPClient) private readonly _protocolApi: CDTP.ProtocolApi, + @inject(TYPES.IDomainsEnabler) domainsEnabler: CDTPDomainsEnabler, ) { + super(domainsEnabler); + } + + public setPausedInDebuggerMessage(params: CDTP.Overlay.SetPausedInDebuggerMessageRequest): Promise { + return this.api.setPausedInDebuggerMessage(params); + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpRuntime.ts b/src/chrome/cdtpDebuggee/features/cdtpRuntime.ts new file mode 100644 index 000000000..4e7cc8894 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpRuntime.ts @@ -0,0 +1,25 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +export interface IRuntime { + runIfWaitingForDebugger(): Promise; +} + +export class CDTPRuntime implements IRuntime { + constructor( + protected readonly api: CDTP.RuntimeApi) { + } + + public async runIfWaitingForDebugger(): Promise { + // This is a CDTP version difference which will have to be handled more elegantly with others later... + // For now, we need to send both messages and ignore a failing one. + try { + await Promise.all([ + this.api.runIfWaitingForDebugger(), + (this.api as any).run() + ]); + } catch (exception) { + // TODO: Make sure that at least one of the two calls succeeded + // Ignore the failed call + } + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpScriptSourcesRetriever.ts b/src/chrome/cdtpDebuggee/features/cdtpScriptSourcesRetriever.ts new file mode 100644 index 000000000..5242d6496 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpScriptSourcesRetriever.ts @@ -0,0 +1,25 @@ +import { Protocol as CDTP } from 'devtools-protocol'; +import { IScript } from '../../internal/scripts/script'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../../dependencyInjection.ts/types'; + +export interface IScriptSourcesRetriever { + getScriptSource(script: IScript): Promise; +} + +@injectable() +export class CDTPScriptSourcesRetriever implements IScriptSourcesRetriever { + protected readonly api = this._protocolApi.Debugger; + + constructor( + @inject(TYPES.CDTPClient) + private readonly _protocolApi: CDTP.ProtocolApi, + @inject(TYPES.CDTPScriptsRegistry) + private readonly _scriptsRegistry: CDTPScriptsRegistry) { + } + + public async getScriptSource(script: IScript): Promise { + return (await this.api.getScriptSource({ scriptId: this._scriptsRegistry.getCdtpId(script) })).scriptSource; + } +} diff --git a/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts b/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts new file mode 100644 index 000000000..4ac754aa0 --- /dev/null +++ b/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts @@ -0,0 +1,35 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { injectable, inject } from 'inversify'; +import { ICallFrame, ScriptOrLoadedSource } from '../../internal/stackTraces/callFrame'; +import { integer } from '../cdtpPrimitives'; + +export interface SetVariableValueRequest { + readonly scopeNumber: integer; + readonly variableName: string; + readonly newValue: CDTP.Runtime.CallArgument; + readonly frame: ICallFrame; +} + +export interface IUpdateDebugeeState { + setVariableValue(params: SetVariableValueRequest): Promise; +} + +@injectable() +export class CDTPUpdateDebugeeState implements IUpdateDebugeeState { + constructor( + @inject(TYPES.CDTPClient) private readonly api: CDTP.ProtocolApi, + private readonly _callFrameRegistry: CDTPCallFrameRegistry) { + } + + public setVariableValue(params: SetVariableValueRequest): Promise { + return this.api.Debugger.setVariableValue({ + callFrameId: this._callFrameRegistry.getFrameId(params.frame), + scopeNumber: params.scopeNumber, + variableName: params.variableName, + newValue: params.newValue + }); + } +} \ No newline at end of file diff --git a/src/chrome/target/cdtpDiagnosticsModule.ts b/src/chrome/cdtpDebuggee/infrastructure/cdtpDiagnosticsModule.ts similarity index 62% rename from src/chrome/target/cdtpDiagnosticsModule.ts rename to src/chrome/cdtpDebuggee/infrastructure/cdtpDiagnosticsModule.ts index 32e26e7a6..a7091be48 100644 --- a/src/chrome/target/cdtpDiagnosticsModule.ts +++ b/src/chrome/cdtpDebuggee/infrastructure/cdtpDiagnosticsModule.ts @@ -1,34 +1,37 @@ -import { TransformedListenerRegistry } from '../communication/transformedListenerRegistry'; -import { PromiseOrNot } from '../utils/promises'; +import { TransformedListenerRegistry } from '../../communication/transformedListenerRegistry'; +import { PromiseOrNot } from '../../utils/promises'; import { injectable } from 'inversify'; +import { CDTPDomainsEnabler } from './cdtpDomainsEnabler'; export interface IEnableableApi { enable(parameters: EnableParameters): Promise; + on(eventName: string, listener: Function): void; } @injectable() export abstract class CDTPEnableableDiagnosticsModule, EnableParameters = void, EnableResponse = void> { protected abstract get api(): T; - // TODO DIEGO IMPORTANT: Figure out how to ensure that the Enable messages get sent after we declare or the event subscribers. They also need to follow the dependencies order public enable(): EnableParameters extends void ? Promise : never; public enable(parameters: EnableParameters): Promise; public async enable(parameters?: EnableParameters): Promise { - return await this.api.enable(parameters); + return await this._domainsEnabler.registerToEnable(this.api, parameters); } + + constructor(private readonly _domainsEnabler: CDTPDomainsEnabler) { } } @injectable() -export abstract class CDTPEventsEmitterDiagnosticsModule, EnableParameters = void, EnableResponse = void> +export abstract class CDTPEventsEmitterDiagnosticsModule, EnableParameters = void, EnableResponse = void> extends CDTPEnableableDiagnosticsModule { public addApiListener(eventName: string, transformation: (params: O) => PromiseOrNot): (transformedListener: ((params: T) => void)) => void { - /** - * We don't want the constructor of the subclass to be async (It's also not allowed). We want the onScriptParsed() method to wait on enabling the domain before setting the handler if neccesary - * so we store the TransformedListenerRegistry as a promise. - */ + const transformedListenerRegistryPromise = new TransformedListenerRegistry(this.constructor.name, async originalListener => { this.api.on(eventName, originalListener); }, transformation).install(); + + this.enable(); // The domain will be enabled eventually (Assuming this happens during the startup/initial configuration phase). We don't block on it. + return async transformedListener => (await transformedListenerRegistryPromise).registerListener(transformedListener); } } \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts b/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts new file mode 100644 index 000000000..ebf4e4c66 --- /dev/null +++ b/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts @@ -0,0 +1,103 @@ +import { IEnableableApi } from './cdtpDiagnosticsModule'; +import { Protocol as CDTP } from 'devtools-protocol'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { inject, injectable } from 'inversify'; +import * as utils from '../../../utils'; +import { asyncMap } from '../../collections/async'; +import { ValidatedMap } from '../../collections/validatedMap'; +import * as _ from 'lodash'; + +export interface IDomainsEnabler { + registerToEnable, EnableParameters, EnableResponse> + (api: T, parameters: EnableParameters): Promise; + + enableDomains(): Promise; +} + +interface IState { + registerToEnable, EnableParameters, EnableResponse> + (api: T, parameters: EnableParameters): Promise; + enableDomains(): Promise; +} + +class EnableDomainFunctionAndResultPromise { + constructor( + public readonly enableDomain: () => Promise, + public readonly parameters: unknown, + public readonly defer: utils.PromiseDefer, + ) { } +} + +class GatheringDomainsToEnableDuringStartup implements IState { + private readonly _registeredDomains = new ValidatedMap, EnableDomainFunctionAndResultPromise>(); + + public async enableDomains(): Promise { + const entries = Array.from(this._registeredDomains.entries()); + await asyncMap(entries, async pair => this.executeEnable(pair[0], pair[1])); + return new DomainsAlreadyEnabledAfterStartup(); + } + + public async executeEnable(domain: IEnableableApi, extras: EnableDomainFunctionAndResultPromise): Promise { + await this.verifyPrerequisitesAreMet(domain); + + try { + extras.defer.resolve(extras.enableDomain()); + } catch (exception) { + extras.defer.reject(exception); + } + } + + public async verifyPrerequisitesAreMet(domain: IEnableableApi): Promise { + if (domain !== this.protocolApi.Runtime) { + // TODO: For the time being we assume that all domains require the Runtime domain to be enabled. Figure out if this can be improved + await this._registeredDomains.get(this.protocolApi.Runtime).defer.promise; + } + } + + public async registerToEnable, EnableParameters, EnableResponse> + (api: T, parameters: EnableParameters): Promise { + const enableDomain = () => api.enable(parameters); + + const entry = this._registeredDomains.getOrAdd(api, () => + new EnableDomainFunctionAndResultPromise(enableDomain, parameters, utils.promiseDefer())); + + if (entry.parameters !== parameters) { + throw new Error(`Cannot register enable(${parameters}) for domain ${this.getDomainName(api)} because it was registered previously with enable(${entry.parameters})`); + } + + return await entry.defer.promise; + } + + private getDomainName(api: IEnableableApi): string { + return _.findKey(this.protocolApi, api); + } + + constructor(@inject(TYPES.CDTPClient) protected readonly protocolApi: CDTP.ProtocolApi) { } +} + +class DomainsAlreadyEnabledAfterStartup implements IState { + public registerToEnable, EnableParameters, EnableResponse> + (api: T, parameters: EnableParameters): Promise { + return api.enable(parameters); + } + + public enableDomains(): Promise { + throw new Error('Startup was already finished'); + } +} + +@injectable() +export class CDTPDomainsEnabler implements IDomainsEnabler { + private _state: IState = new GatheringDomainsToEnableDuringStartup(this._protocolApi); + + public registerToEnable, EnableParameters, EnableResponse> + (api: T, parameters: EnableParameters): Promise { + return this._state.registerToEnable(api, parameters); + } + + public async enableDomains(): Promise { + this._state = await this._state.enableDomains(); + } + + constructor(@inject(TYPES.CDTPClient) private readonly _protocolApi: CDTP.ProtocolApi) { } +} \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts b/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts new file mode 100644 index 000000000..2ce7f0739 --- /dev/null +++ b/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts @@ -0,0 +1,28 @@ +import { Coordinates, LocationInScript } from '../../internal/locations/location'; +import { createColumnNumber, createLineNumber } from '../../internal/locations/subtypes'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { Protocol as CDTP } from 'devtools-protocol'; + +interface HasCoordinates { + lineNumber: number; + columnNumber?: number; +} + +interface HasScript { + scriptId: CDTP.Runtime.ScriptId; +} + +export interface HasScriptLocation extends HasCoordinates, HasScript { } + +export class CDTPLocationParser { + public async getLocationInScript(crdpObjectWithScriptLocation: HasScriptLocation): Promise { + return new LocationInScript(await this._scriptsRegistry.getScriptByCdtpId(crdpObjectWithScriptLocation.scriptId), + this.getCoordinates(crdpObjectWithScriptLocation)); + } + + private getCoordinates(crdpObjectWithCoordinates: HasCoordinates): Coordinates { + return new Coordinates(createLineNumber(crdpObjectWithCoordinates.lineNumber), createColumnNumber(crdpObjectWithCoordinates.columnNumber)); + } + + constructor(private _scriptsRegistry: CDTPScriptsRegistry) { } +} diff --git a/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts new file mode 100644 index 000000000..cc6d62ae3 --- /dev/null +++ b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts @@ -0,0 +1,33 @@ +import { Protocol as CDTP } from 'devtools-protocol'; + +import { IScript, } from '../../internal/scripts/script'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { CodeFlowFrame } from '../../internal/stackTraces/callFrame'; +import { createCallFrameName } from '../../internal/stackTraces/callFrameName'; +import { CDTPLocationParser, HasScriptLocation } from './cdtpLocationParser'; +import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; +import { asyncMap } from '../../collections/async'; + +export class CDTPStackTraceParser { + private readonly _cdtpLocationParser = new CDTPLocationParser(this._scriptsRegistry); + + public async toStackTraceCodeFlow(stackTrace: CDTP.Runtime.StackTrace): Promise> { + return { + codeFlowFrames: await asyncMap(stackTrace.callFrames, (callFrame, index) => this.runtimeCallFrameToCodeFlowFrame(index, callFrame)), + description: stackTrace.description, + parent: stackTrace.parent && await this.toStackTraceCodeFlow(stackTrace.parent) + }; + } + + private runtimeCallFrameToCodeFlowFrame(index: number, callFrame: CDTP.Runtime.CallFrame): Promise> { + return this.toCodeFlowFrame(index, callFrame, callFrame); + } + + public async toCodeFlowFrame(index: number, callFrame: CDTP.Runtime.CallFrame | CDTP.Debugger.CallFrame, location: HasScriptLocation): Promise> { + const scriptLocation = await this._cdtpLocationParser.getLocationInScript(location); + const name = createCallFrameName(scriptLocation.script, callFrame.functionName); + return new CodeFlowFrame(index, name, scriptLocation); + } + + constructor(private _scriptsRegistry: CDTPScriptsRegistry) { } +} diff --git a/src/chrome/cdtpDebuggee/registries/cdtpBreakpointIdsRegistry.ts b/src/chrome/cdtpDebuggee/registries/cdtpBreakpointIdsRegistry.ts new file mode 100644 index 000000000..9fb88c9de --- /dev/null +++ b/src/chrome/cdtpDebuggee/registries/cdtpBreakpointIdsRegistry.ts @@ -0,0 +1,30 @@ +import { BidirectionalMap } from '../../collections/bidirectionalMap'; +import { Protocol as CDTP } from 'devtools-protocol'; +import { injectable } from 'inversify'; +import { CDTPBPRecipie } from '../cdtpPrimitives'; + +@injectable() +export class CDTPBreakpointIdsRegistry { + // TODO DIEGO: Figure out how to handle if two breakpoint rules set a breakpoint in the same location so it ends up being the same breakpoint id + private readonly _recipieToBreakpointId = new BidirectionalMap(); + + public registerRecipie(cdtpBreakpointId: CDTP.Debugger.BreakpointId, bpRecipie: CDTPBPRecipie): void { + this._recipieToBreakpointId.set(bpRecipie, cdtpBreakpointId); + } + + public unregisterRecipie(bpRecipie: CDTPBPRecipie): void { + this._recipieToBreakpointId.deleteByLeft(bpRecipie); + } + + public getBreakpointId(bpRecipie: CDTPBPRecipie): CDTP.Debugger.BreakpointId { + return this._recipieToBreakpointId.getByLeft(bpRecipie); + } + + public getRecipieByBreakpointId(cdtpBreakpointId: CDTP.Debugger.BreakpointId): CDTPBPRecipie { + return this._recipieToBreakpointId.getByRight(cdtpBreakpointId); + } + + public toString(): string { + return `Breakpoint IDs: ${this._recipieToBreakpointId}`; + } +} diff --git a/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts b/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts new file mode 100644 index 000000000..d65820719 --- /dev/null +++ b/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts @@ -0,0 +1,18 @@ +import { IScript } from '../../internal/scripts/script'; +import { Protocol as CDTP } from 'devtools-protocol'; +import { ValidatedMap } from '../../collections/validatedMap'; +import { ICallFrame, ScriptOrLoadedSource } from '../../internal/stackTraces/callFrame'; +import { injectable } from 'inversify'; + +@injectable() +export class CDTPCallFrameRegistry { + private readonly _callFrameToId = new ValidatedMap, CDTP.Debugger.CallFrameId>(); + + public registerFrameId(callFrameId: CDTP.Debugger.CallFrameId, frame: ICallFrame): void { + this._callFrameToId.set(frame, callFrameId); + } + + public getFrameId(frame: ICallFrame): CDTP.Debugger.CallFrameId { + return this._callFrameToId.get(frame.unmappedCallFrame); + } +} \ No newline at end of file diff --git a/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts b/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts new file mode 100644 index 000000000..ab5f5d6e1 --- /dev/null +++ b/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts @@ -0,0 +1,86 @@ +import { Protocol as CDTP } from 'devtools-protocol'; +import { IScript } from '../../internal/scripts/script'; +import { ValidatedMap } from '../../collections/validatedMap'; +import { ExecutionContext, IExecutionContext } from '../../internal/scripts/executionContext'; +import { injectable } from 'inversify'; + +/** + * TODO: The CDTPScriptsRegistry is still a work in progress. We need to understand exactly how the ExecutionContexts, the Scripts, and the script "generations" work to figure out the best way to implement this + * Is ExecutionContext == Generation? Or is a Generation a set of ExecutionContexts? + */ + +@injectable() +export class CDTPScriptsRegistry { + private readonly _idToExecutionContext = new ValidatedMap(); + private readonly _scripts = new CDTPCurrentGeneration(); + + public registerExecutionContext(executionContextId: CDTP.Runtime.ExecutionContextId): IExecutionContext { + const executionContext = new ExecutionContext(); + this._idToExecutionContext.set(executionContextId, executionContext); + return executionContext; + } + + public markExecutionContextAsDestroyed(executionContextId: CDTP.Runtime.ExecutionContextId): IExecutionContext { + const executionContext = this._idToExecutionContext.get(executionContextId); + executionContext.markAsDestroyed(); + return executionContext; + } + + public getExecutionContextById(executionContextId: CDTP.Runtime.ExecutionContextId): IExecutionContext { + return this._idToExecutionContext.get(executionContextId); + } + + public registerScript(scriptId: CDTP.Runtime.ScriptId, obtainScript: () => Promise): Promise { + return this._scripts.registerNewScript(scriptId, obtainScript); + } + + public getCdtpId(script: IScript): any { + return this._scripts.getCdtpId(script); + } + + public getScriptByCdtpId(runtimeScriptCrdpId: CDTP.Runtime.ScriptId): Promise { + return this._scripts.getScriptByCdtpId(runtimeScriptCrdpId); + } + + public getAllScripts(): IterableIterator> { + return this._scripts.getAllScripts(); + } +} + +class CDTPCurrentGeneration { + // We use these two maps instead of a bidirectional map because we need to map an ID to a Promise instead of a script, to avoid having race conditions... + private readonly _cdtpIdByScript = new ValidatedMap>(); + private readonly _scriptByCdtpId = new ValidatedMap(); + + public async registerNewScript(scriptId: CDTP.Runtime.ScriptId, obtainScript: () => Promise): Promise { + const scriptWithConfigurationPromise = obtainScript().then(script => { + /** + * We need to configure the script here, so we can guarantee that clients who try to use a script will get + * blocked until the script is created, and all the initial configuration is done, so they can use APIs to get + * the script id, search by URL, etc... + */ + this.createScriptInitialConfiguration(scriptId, script); + return script; + }); + + this._cdtpIdByScript.set(scriptId, scriptWithConfigurationPromise); + + return await scriptWithConfigurationPromise; + } + + private createScriptInitialConfiguration(scriptId: CDTP.Runtime.ScriptId, script: IScript): void { + this._scriptByCdtpId.set(script, scriptId); + } + + public getCdtpId(script: IScript): CDTP.Runtime.ScriptId { + return this._scriptByCdtpId.get(script); + } + + public getScriptByCdtpId(runtimeScriptCrdpId: string): Promise { + return this._cdtpIdByScript.get(runtimeScriptCrdpId); + } + + public getAllScripts(): IterableIterator> { + return this._cdtpIdByScript.values(); + } +} diff --git a/src/chrome/chromeConnection.ts b/src/chrome/chromeConnection.ts index 3a4d3d20a..8a5421312 100644 --- a/src/chrome/chromeConnection.ts +++ b/src/chrome/chromeConnection.ts @@ -9,11 +9,12 @@ import { StepProgressEventsEmitter, IObservableEvents, IStepStartedEventsEmitter import * as errors from '../errors'; import * as utils from '../utils'; import { logger } from 'vscode-debugadapter'; -import { ChromeTargetDiscovery, TargetVersions, Version } from './chromeTargetDiscoveryStrategy'; +import { ChromeTargetDiscovery, TargetVersions } from './chromeTargetDiscoveryStrategy'; +import { Version } from "./utils/version"; import { Client } from 'noice-json-rpc'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; export interface ITarget { description: string; @@ -109,7 +110,7 @@ export class ChromeConnection implements IObservableEvents { // return this.chromeDebugAdapter.terminateSession(reason, restart); // } -// protected globalEvaluate(args: Crdp.Runtime.EvaluateRequest): Promise { +// protected globalEvaluate(args: CDTP.Runtime.EvaluateRequest): Promise { // return this.chromeDebugAdapter.globalEvaluate(args); // } // protected get _launchAttachArgs(): ICommonRequestArgs { @@ -80,7 +80,7 @@ import { ICDTPDebuggerEventsProvider } from './target/cdtpDebuggerEventsProvider // protected set _expectingStopReason(value: ReasonType) { // this.chromeDebugAdapter._expectingStopReason = value; // } -// protected get _domains(): Map { +// protected get _domains(): Map { // return this.chromeDebugAdapter._domains; // } // protected get _hasTerminated(): boolean { @@ -145,7 +145,7 @@ export interface ISourceContainer { export type VariableContext = 'variables' | 'watch' | 'repl' | 'hover'; -export type CrdpScript = Crdp.Debugger.ScriptParsedEvent; +export type CrdpScript = CDTP.Debugger.ScriptParsedEvent; export type CrdpDomain = string; @@ -159,9 +159,9 @@ export class ChromeDebugLogic { public static THREAD_ID = 1; public _session: ISession; - public _domains = new Map(); + public _domains = new Map(); private _clientAttached: boolean; - private _exception: Crdp.Runtime.RemoteObject | undefined; + private _exception: CDTP.Runtime.RemoteObject | undefined; private _expectingResumedEvent: boolean; public _expectingStopReason: ReasonType | undefined; private _waitAfterStep = Promise.resolve(); @@ -188,8 +188,6 @@ export class ChromeDebugLogic { protected _breakOnLoadHelper: BreakOnLoadHelper | null; - private readonly _chromeDiagnostics: CDTPDiagnostics; - private readonly _chromeConnection: ChromeConnection; private readonly _sourceMapTransformer: BaseSourceMapTransformer; public _promiseRejectExceptionFilterEnabled = false; @@ -202,21 +200,22 @@ export class ChromeDebugLogic { @inject(TYPES.BasePathTransformer) pathTransformer: BasePathTransformer, @inject(TYPES.ISession) session: ISession, @inject(TYPES.ChromeConnection) chromeConnection: ChromeConnection, - @inject(TYPES.CDTPDiagnostics) chromeDiagnostics: CDTPDiagnostics, @inject(TYPES.DeleteMeScriptsRegistry) private readonly _scriptsLogic: DeleteMeScriptsRegistry, @inject(TYPES.EventSender) private readonly _eventSender: EventSender, - @inject(TYPES.ExceptionThrownEventProvider) private readonly _exceptionThrownEventProvider: ExceptionThrownEventProvider, - @inject(TYPES.ExecutionContextEventsProvider) private readonly _executionContextEventsProvider: ExecutionContextEventsProvider, + @inject(TYPES.ExceptionThrownEventProvider) private readonly _exceptionThrownEventProvider: CDTPExceptionThrownEventsProvider, + @inject(TYPES.ExecutionContextEventsProvider) private readonly _executionContextEventsProvider: CDTPExecutionContextEventsProvider, @inject(TYPES.IInspectDebugeeState) private readonly _inspectDebugeeState: IInspectDebugeeState, @inject(TYPES.IUpdateDebugeeState) private readonly _updateDebugeeState: IUpdateDebugeeState, @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration, - @inject(TYPES.ICDTPDebuggerEventsProvider) private readonly _debuggerEvents: ICDTPDebuggerEventsProvider, + @inject(TYPES.ICDTPDebuggerEventsProvider) private readonly _debuggerEvents: ICDTDebuggeeExecutionEventsProvider, + @inject(TYPES.IConsoleEventsProvider) private readonly _consoleEventsProvider: IConsoleEventsProvider, + @inject(TYPES.ILogEventsProvider) private readonly _logEventsProvider: CDTPLogEventsProvider, + @inject(TYPES.IPauseOnExceptions) private readonly _pauseOnExceptions: IPauseOnExceptionsConfigurer, ) { telemetry.setupEventHandler(e => session.sendEvent(e)); this._batchTelemetryReporter = new BatchTelemetryReporter(telemetry); this._session = session; this._chromeConnection = chromeConnection; - this._chromeDiagnostics = chromeDiagnostics; this.events = new StepProgressEventsEmitter(this._chromeConnection.events ? [this._chromeConnection.events] : []); this._variableHandles = new variables.VariableHandles(); @@ -228,10 +227,6 @@ export class ChromeDebugLogic { this.clearTargetContext(); } - public get chrome(): CDTPDiagnostics { - return this._chromeDiagnostics; - } - public get pathTransformer(): BasePathTransformer { return this._pathTransformer; } @@ -303,12 +298,11 @@ export class ChromeDebugLogic { public install(): ChromeDebugLogic { this._debuggerEvents.onResumed(() => this.onResumed()); this._debuggerEvents.onPaused(paused => this.onPaused(paused)); - this.chrome.Console.onMessageAdded(params => this.onMessageAdded(params)); - this.chrome.Console.enable(); - this.chrome.Runtime.onConsoleAPICalled(params => this.onConsoleAPICalled(params)); + this._consoleEventsProvider.onMessageAdded(params => this.onMessageAdded(params)); + this._consoleEventsProvider.onConsoleAPICalled(params => this.onConsoleAPICalled(params)); this._exceptionThrownEventProvider.onExceptionThrown(params => this.onExceptionThrown(params)); this._executionContextEventsProvider.onExecutionContextsCleared(() => this.clearTargetContext()); - this.chrome.Log.onEntryAdded(entry => this.onLogEntryAdded(entry)); + this._logEventsProvider.onEntryAdded(entry => this.onLogEntryAdded(entry)); this._chromeConnection.onClose(() => this.terminateSession('websocket closed')); @@ -397,7 +391,7 @@ export class ChromeDebugLogic { } } - private async logObjects(objs: Crdp.Runtime.RemoteObject[], isError = false, stackTrace?: CodeFlowStackTrace): Promise { + private async logObjects(objs: CDTP.Runtime.RemoteObject[], isError = false, stackTrace?: CodeFlowStackTrace): Promise { // This is an asynchronous method, so ensure that we handle one at a time so that they are sent out in the same order that they came in. this._currentLogMessage = this._currentLogMessage .then(async () => { @@ -505,7 +499,7 @@ export class ChromeDebugLogic { this._pauseOnPromiseRejections = false; } - return this.chrome.Debugger.setPauseOnExceptions({ state }) + return this._pauseOnExceptions.setPauseOnExceptions({ state }) .then(() => { }); } @@ -613,10 +607,6 @@ export class ChromeDebugLogic { } */ public variables(args: DebugProtocol.VariablesArguments): Promise { - if (!this.chrome) { - return utils.errP(errors.runtimeNotConnectedMsg); - } - const handle = this._variableHandles.get(args.variablesReference); if (!handle) { return Promise.resolve(undefined); @@ -631,12 +621,12 @@ export class ChromeDebugLogic { }); } - public async propertyDescriptorToVariable(propDesc: Crdp.Runtime.PropertyDescriptor, owningObjectId?: string, parentEvaluateName?: string): Promise { + public async propertyDescriptorToVariable(propDesc: CDTP.Runtime.PropertyDescriptor, owningObjectId?: string, parentEvaluateName?: string): Promise { if (propDesc.get) { // Getter const grabGetterValue = 'function remoteFunction(propName) { return this[propName]; }'; - let response: Crdp.Runtime.CallFunctionOnResponse; + let response: CDTP.Runtime.CallFunctionOnResponse; try { response = await this._inspectDebugeeState.callFunctionOn({ objectId: owningObjectId, @@ -678,8 +668,8 @@ export class ChromeDebugLogic { this.getRuntimeProperties({ objectId, ownProperties: true, accessorPropertiesOnly: false, generatePreview: true }) ]).then(getPropsResponses => { // Sometimes duplicates will be returned - merge all descriptors by name - const propsByName = new Map(); - const internalPropsByName = new Map(); + const propsByName = new Map(); + const internalPropsByName = new Map(); getPropsResponses.forEach(response => { if (response) { response.result.forEach(propDesc => @@ -714,7 +704,7 @@ export class ChromeDebugLogic { }); } - private getRuntimeProperties(params: Crdp.Runtime.GetPropertiesRequest): Promise { + private getRuntimeProperties(params: CDTP.Runtime.GetPropertiesRequest): Promise { return this._inspectDebugeeState.getProperties(params) .catch(err => { if (err.message.startsWith('Cannot find context with specified id')) { @@ -726,7 +716,7 @@ export class ChromeDebugLogic { }); } - private internalPropertyDescriptorToVariable(propDesc: Crdp.Runtime.InternalPropertyDescriptor, parentEvaluateName: string): Promise { + private internalPropertyDescriptorToVariable(propDesc: CDTP.Runtime.InternalPropertyDescriptor, parentEvaluateName: string): Promise { return this.remoteObjectToVariable(propDesc.name, propDesc.value, parentEvaluateName); } @@ -803,10 +793,6 @@ export class ChromeDebugLogic { } */ public async evaluate(args: EvaluateArguments): Promise { - if (!this.chrome) { - return utils.errP(errors.runtimeNotConnectedMsg); - } - const expression = args.expression.startsWith('{') && args.expression.endsWith('}') ? `(${args.expression})` : args.expression; @@ -836,17 +822,17 @@ export class ChromeDebugLogic { /** * Allow consumers to override just because of https://github.com/nodejs/node/issues/8426 */ - public globalEvaluate(args: Crdp.Runtime.EvaluateRequest): Promise { + public globalEvaluate(args: CDTP.Runtime.EvaluateRequest): Promise { return this._inspectDebugeeState.evaluate(args); } - private async waitThenDoEvaluate(expression: string, frame?: ICallFrame, extraArgs?: Partial): Promise { + private async waitThenDoEvaluate(expression: string, frame?: ICallFrame, extraArgs?: Partial): Promise { const waitThenEval = this._waitAfterStep.then(() => this.doEvaluate(expression, frame, extraArgs)); this._waitAfterStep = waitThenEval.then(() => { }, () => { }); // to Promise and handle failed evals return waitThenEval; } - private async doEvaluate(expression: string, frame: ICallFrame, extraArgs?: Partial): Promise { + private async doEvaluate(expression: string, frame: ICallFrame, extraArgs?: Partial): Promise { if (frame) { if (!frame) { return utils.errP(errors.evalNotAvailableMsg); @@ -854,7 +840,7 @@ export class ChromeDebugLogic { return this.evaluateOnCallFrame(expression, frame, extraArgs); } else { - let args: Crdp.Runtime.EvaluateRequest = { + let args: CDTP.Runtime.EvaluateRequest = { expression, // silent because of an issue where node will sometimes hang when breaking on exceptions in console messages. Fixed somewhere between 8 and 8.4 silent: true, @@ -870,7 +856,7 @@ export class ChromeDebugLogic { } } - public async evaluateOnCallFrame(expression: string, frame: ICallFrame, extraArgs?: Partial): Promise { + public async evaluateOnCallFrame(expression: string, frame: ICallFrame, extraArgs?: Partial): Promise { let args: EvaluateOnCallFrameRequest = { frame, expression, @@ -905,7 +891,7 @@ export class ChromeDebugLogic { } public setVariableValue(frame: ICallFrame, scopeNumber: number, variableName: string, value: string): Promise { - let evalResultObject: Crdp.Runtime.RemoteObject; + let evalResultObject: CDTP.Runtime.RemoteObject; return this._inspectDebugeeState.evaluateOnCallFrame({ frame, expression: value, silent: true }).then(evalResponse => { if (evalResponse.exceptionDetails) { const errMsg = ChromeUtils.errorMessageFromExceptionDetails(evalResponse.exceptionDetails); @@ -938,7 +924,7 @@ export class ChromeDebugLogic { error => Promise.reject(errors.errorFromEvaluate(error.message))); } - public async remoteObjectToVariable(name: string, object: Crdp.Runtime.RemoteObject, parentEvaluateName?: string, stringify = true, context: VariableContext = 'variables'): Promise { + public async remoteObjectToVariable(name: string, object: CDTP.Runtime.RemoteObject, parentEvaluateName?: string, stringify = true, context: VariableContext = 'variables'): Promise { name = name || '""'; if (object) { @@ -954,7 +940,7 @@ export class ChromeDebugLogic { } } - public createFunctionVariable(name: string, object: Crdp.Runtime.RemoteObject, context: VariableContext, parentEvaluateName?: string): DebugProtocol.Variable { + public createFunctionVariable(name: string, object: CDTP.Runtime.RemoteObject, context: VariableContext, parentEvaluateName?: string): DebugProtocol.Variable { let value: string; const firstBraceIdx = object.description.indexOf('{'); if (firstBraceIdx >= 0) { @@ -976,7 +962,7 @@ export class ChromeDebugLogic { }; } - public createObjectVariable(name: string, object: Crdp.Runtime.RemoteObject, parentEvaluateName: string, context: VariableContext): Promise { + public createObjectVariable(name: string, object: CDTP.Runtime.RemoteObject, parentEvaluateName: string, context: VariableContext): Promise { if ((object.subtype) === 'internal#location') { // Could format this nicely later, see #110 return Promise.resolve(this.createPrimitiveVariableWithValue(name, 'internal#location', parentEvaluateName)); @@ -1020,11 +1006,11 @@ export class ChromeDebugLogic { })); } - protected createPropertyContainer(object: Crdp.Runtime.RemoteObject, evaluateName: string): IVariableContainer { + protected createPropertyContainer(object: CDTP.Runtime.RemoteObject, evaluateName: string): IVariableContainer { return new PropertyContainer(object.objectId, evaluateName); } - public createPrimitiveVariable(name: string, object: Crdp.Runtime.RemoteObject, parentEvaluateName?: string, stringify?: boolean): DebugProtocol.Variable { + public createPrimitiveVariable(name: string, object: CDTP.Runtime.RemoteObject, parentEvaluateName?: string, stringify?: boolean): DebugProtocol.Variable { const value = variables.getRemoteObjectPreview_primitive(object, stringify); const variable = this.createPrimitiveVariableWithValue(name, value, parentEvaluateName); variable.type = object.type; @@ -1130,7 +1116,7 @@ export class ChromeDebugLogic { return this.getNumPropsByEval(objectId, getNumPropsFn); } - private getArrayNumPropsByPreview(object: Crdp.Runtime.RemoteObject): IPropCount { + private getArrayNumPropsByPreview(object: CDTP.Runtime.RemoteObject): IPropCount { let indexedVariables = 0; const indexedProps = object.preview.properties .filter(prop => isIndexedPropName(prop.name)); @@ -1148,7 +1134,7 @@ export class ChromeDebugLogic { return this.getNumPropsByEval(objectId, getNumPropsFn); } - private getCollectionNumPropsByPreview(object: Crdp.Runtime.RemoteObject): IPropCount { + private getCollectionNumPropsByPreview(object: CDTP.Runtime.RemoteObject): IPropCount { let indexedVariables = 0; let namedVariables = object.preview.properties.length + 1; // +1 for [[Entries]]; diff --git a/src/chrome/chromeTargetDiscoveryStrategy.ts b/src/chrome/chromeTargetDiscoveryStrategy.ts index 12c33ea71..2158c1f7f 100644 --- a/src/chrome/chromeTargetDiscoveryStrategy.ts +++ b/src/chrome/chromeTargetDiscoveryStrategy.ts @@ -12,27 +12,9 @@ import * as chromeUtils from './chromeUtils'; import { ITargetDiscoveryStrategy, ITargetFilter, ITarget } from './chromeConnection'; import * as nls from 'vscode-nls'; +import { Version } from './utils/version'; const localize = nls.loadMessageBundle(); -export class Version { - static parse(versionString: string): Version { - const majorAndMinor = versionString.split('.'); - const major = parseInt(majorAndMinor[0], 10); - const minor = parseInt(majorAndMinor[1], 10); - return new Version(major, minor); - } - - public static unknownVersion(): Version { - return new Version(0, 0); // Using 0.0 will make behave isAtLeastVersion as if this was the oldest possible version - } - - constructor(private _major: number, private _minor: number) {} - - public isAtLeastVersion(major: number, minor: number): boolean { - return this._major > major || (this._major === major && this._minor >= minor); - } -} - export class TargetVersions { constructor(public readonly protocol: Version, public readonly browser: Version) {} } @@ -105,11 +87,11 @@ export class ChromeTargetDiscovery implements ITargetDiscoveryStrategy, IObserva let browserVersion = Version.unknownVersion(); if (browserWithPrefixVersionString.startsWith(chromePrefix)) { const browserVersionString = browserWithPrefixVersionString.substr(chromePrefix.length); - browserVersion = Version.parse(browserVersionString); + browserVersion = Version.coerce(browserVersionString); } this.telemetry.reportEvent('targetDebugProtocolVersion', { debugProtocolVersion: response['Protcol-Version'] }); - return new TargetVersions(Version.parse(protocolVersionString), browserVersion); + return new TargetVersions(Version.coerce(protocolVersionString), browserVersion); } } catch (e) { this.logger.log(`Didn't get a valid response for /json/version call. Error: ${e.message}. Response: ${jsonResponse}`); diff --git a/src/chrome/chromeUtils.ts b/src/chrome/chromeUtils.ts index 0a2c75005..cebae677a 100644 --- a/src/chrome/chromeUtils.ts +++ b/src/chrome/chromeUtils.ts @@ -4,7 +4,7 @@ import * as url from 'url'; import * as path from 'path'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; import { logger } from 'vscode-debugadapter'; import * as utils from '../utils'; @@ -132,7 +132,7 @@ export function targetUrlToClientPath(aUrl: string, pathMapping: IPathMapping): * Convert a RemoteObject to a value+variableHandleRef for the client. * TODO - Delete after Microsoft/vscode#12019!! */ -export function remoteObjectToValue(object: Crdp.Runtime.RemoteObject, stringify = true): { value: string, variableHandleRef?: string } { +export function remoteObjectToValue(object: CDTP.Runtime.RemoteObject, stringify = true): { value: string, variableHandleRef?: string } { let value = ''; let variableHandleRef: string; @@ -232,7 +232,7 @@ export function compareVariableNames(var1: string, var2: string): number { return var1.localeCompare(var2); } -export function remoteObjectToCallArgument(object: Crdp.Runtime.RemoteObject): Crdp.Runtime.CallArgument { +export function remoteObjectToCallArgument(object: CDTP.Runtime.RemoteObject): CDTP.Runtime.CallArgument { return { objectId: object.objectId, unserializableValue: object.unserializableValue, @@ -245,7 +245,7 @@ export function remoteObjectToCallArgument(object: Crdp.Runtime.RemoteObject): C * protocol differences in the future. * This includes the error message and full stack */ -export function descriptionFromExceptionDetails(exceptionDetails: Crdp.Runtime.ExceptionDetails): string { +export function descriptionFromExceptionDetails(exceptionDetails: CDTP.Runtime.ExceptionDetails): string { let description: string; if (exceptionDetails.exception) { // Take exception object description, or if a value was thrown, the value @@ -261,7 +261,7 @@ export function descriptionFromExceptionDetails(exceptionDetails: Crdp.Runtime.E /** * Get just the error message from the exception details - the first line without the full stack */ -export function errorMessageFromExceptionDetails(exceptionDetails: Crdp.Runtime.ExceptionDetails): string { +export function errorMessageFromExceptionDetails(exceptionDetails: CDTP.Runtime.ExceptionDetails): string { let description = descriptionFromExceptionDetails(exceptionDetails); const newlineIdx = description.indexOf('\n'); if (newlineIdx >= 0) { diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts index 7b9e5610b..e2701ff04 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts @@ -1,14 +1,13 @@ import * as errors from '../../../errors'; import { DebugProtocol } from 'vscode-debugprotocol'; import { ChromeDebugLogic } from '../../chromeDebugAdapter'; -import { CDTPDiagnostics } from '../../target/cdtpDiagnostics'; import { ClientToInternal } from '../clientToInternal'; import { InternalToClient } from '../internalToClient'; import { IGetLoadedSourcesResponseBody, IDebugAdapterState, PromiseOrNot, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IThreadsResponseBody, IEvaluateResponseBody, IExceptionInfoResponseBody, ILaunchRequestArgs, IAttachRequestArgs } from '../../../debugAdapterInterfaces'; import { StackTracesLogic } from '../../internal/stackTraces/stackTracesLogic'; import { SourcesLogic } from '../../internal/sources/sourcesLogic'; import { BreakpointsLogic } from '../../internal/breakpoints/breakpointsLogic'; -import { CDTPScriptsRegistry } from '../../target/cdtpScriptsRegistry'; +import { CDTPScriptsRegistry } from '../../cdtpDebuggee/registries/cdtpScriptsRegistry'; import { PauseOnExceptionOrRejection } from '../../internal/exceptions/pauseOnException'; import { Stepping } from '../../internal/stepping/stepping'; import { DotScriptCommand } from '../../internal/sources/features/dotScriptsCommand'; @@ -18,9 +17,9 @@ import { SkipFilesLogic } from '../../internal/features/skipFiles'; import { TakeProperActionOnPausedEvent } from '../../internal/features/takeProperActionOnPausedEvent'; import { SmartStepLogic } from '../../internal/features/smartStep'; import { NotifyClientOfLoadedSources } from '../../internal/sources/features/notifyClientOfLoadedSources'; -import { CDTPOnScriptParsedEventProvider } from '../../target/cdtpOnScriptParsedEventProvider'; +import { CDTPOnScriptParsedEventProvider } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; import { Target } from '../../communication/targetChannels'; -import { IDebuggeeRunner } from '../../debugee/debugeeLauncher'; +import { IDebuggeeRunner } from '../../debugeeStartup/debugeeLauncher'; import { StepProgressEventsEmitter } from '../../../executionTimingsReporter'; import { TelemetryPropertyCollector, ITelemetryPropertyCollector } from '../../../telemetry'; import { ICommunicator, utils } from '../../..'; @@ -53,7 +52,6 @@ export class ConnectedCDA implements IDebugAdapterState { ) { } public async install(): Promise { - await this.chrome.install(); await this._chromeDebugAdapter.install(); await this._sourcesLogic.install(); await this._stackTraceLogic.install(); @@ -71,10 +69,6 @@ export class ConnectedCDA implements IDebugAdapterState { return this; } - public get chrome(): CDTPDiagnostics { - return this._chromeDebugAdapter.chrome; - } - public shutdown(): void { return this._chromeDebugAdapter.shutdown(); } diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts index 8825a169c..d5e14b720 100644 --- a/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts @@ -18,7 +18,8 @@ import { ConnectedCDAConfiguration } from './cdaConfiguration'; import { ConnectedCDA } from './connectedCDA'; import { ConnectedCDAEventsCreator } from './connectedCDAEvents'; import { UnconnectedCDACommonLogic } from './unconnectedCDACommonLogic'; -import { IDebuggeeLauncher } from '../../debugee/debugeeLauncher'; +import { IDebuggeeLauncher } from '../../debugeeStartup/debugeeLauncher'; +import { IDomainsEnabler } from '../../cdtpDebuggee/infrastructure/cdtpDomainsEnabler'; export enum ScenarioType { Launch, @@ -86,7 +87,9 @@ export class UnconnectedCDA extends UnconnectedCDACommonLogic implements IDebugA const newState = di.createClassWithDI(ConnectedCDA); await newState.install(); - await chromeConnection.api.Runtime.enable(); + const domainsEnabler = di.createComponent(TYPES.IDomainsEnabler); + await domainsEnabler.enableDomains(); // Enables all the domains that were registered + await chromeConnection.api.Runtime.runIfWaitingForDebugger(); this._session.sendEvent(new InitializedEvent()); diff --git a/src/chrome/client/eventSender.ts b/src/chrome/client/eventSender.ts index dafe57c50..ee108c6bf 100644 --- a/src/chrome/client/eventSender.ts +++ b/src/chrome/client/eventSender.ts @@ -7,7 +7,7 @@ import { LocationInLoadedSource } from '../internal/locations/location'; import { IBPRecipieStatus } from '../internal/breakpoints/bpRecipieStatus'; import { IFormattedExceptionLineDescription } from '../internal/formattedExceptionParser'; import { StoppedEvent2, ReasonType } from '../stoppedEvent'; -import { Crdp, ChromeDebugLogic } from '../..'; +import { CDTP, ChromeDebugLogic } from '../..'; import { injectable, inject } from 'inversify'; import { TYPES } from '../dependencyInjection.ts/types'; @@ -36,7 +36,7 @@ export interface ExceptionThrownParameters { export interface DebugeeIsStoppedParameters { reason: ReasonType; - exception?: Crdp.Runtime.RemoteObject; + exception?: CDTP.Runtime.RemoteObject; } export interface IEventsToClientReporter { diff --git a/src/chrome/collections/mapUsingProjection.ts b/src/chrome/collections/mapUsingProjection.ts index 0587a1fb8..df9577930 100644 --- a/src/chrome/collections/mapUsingProjection.ts +++ b/src/chrome/collections/mapUsingProjection.ts @@ -60,6 +60,11 @@ export class MapUsingProjection implements IValidatedMap { return this; } + public setAndReplaceIfExist(key: K, value: V): this { + this._projectionToKeyAndvalue.setAndReplaceIfExist(this._projection(key), new KeyAndValue(key, value)); + return this; + } + public get size(): number { return this._projectionToKeyAndvalue.size; } diff --git a/src/chrome/collections/utilities.ts b/src/chrome/collections/utilities.ts index a5be74eec..535dc5f23 100644 --- a/src/chrome/collections/utilities.ts +++ b/src/chrome/collections/utilities.ts @@ -15,3 +15,11 @@ export function determineOrderingOfStrings(left: string, right: string): number return 0; } } + +export function singleOne(array: ReadonlyArray): T { + if (array.length === 1) { + return array[0]; + } else { + throw new Error(`Expected array ${array} to have exactly a single element yet it had ${array.length}`); + } +} \ No newline at end of file diff --git a/src/chrome/collections/validatedMap.ts b/src/chrome/collections/validatedMap.ts index 73f4bc206..87c9bcb45 100644 --- a/src/chrome/collections/validatedMap.ts +++ b/src/chrome/collections/validatedMap.ts @@ -1,8 +1,10 @@ import { printMap } from './printing'; +import { breakWhileDebugging } from '../../validation'; export interface IValidatedMap extends Map { tryGetting(key: K): V | undefined; getOrAdd(key: K, obtainValueToAdd: () => V): V; + setAndReplaceIfExist(key: K, value: V): this; } /** A map that throws exceptions instead of returning error codes. */ @@ -29,6 +31,7 @@ export class ValidatedMap implements IValidatedMap { public delete(key: K): boolean { if (!this._wrappedMap.delete(key)) { + breakWhileDebugging(); throw new Error(`Couldn't delete element with key ${key} because it wasn't present in the map`); } @@ -42,6 +45,7 @@ export class ValidatedMap implements IValidatedMap { public get(key: K): V { const value = this._wrappedMap.get(key); if (value === undefined) { + breakWhileDebugging(); throw new Error(`Couldn't get the element with key '${key}' because it wasn't present in this map <${this}>`); } return value; @@ -64,9 +68,14 @@ export class ValidatedMap implements IValidatedMap { public set(key: K, value: V): this { if (this.has(key)) { - // throw new Error(`Cannot set key ${key} because it already exists`); + // breakWhileDebugging(); + // TODO: throw new Error(`Cannot set key ${key} because it already exists`); } + return this.setAndReplaceIfExist(key, value); + } + + public setAndReplaceIfExist(key: K, value: V): this { this._wrappedMap.set(key, value); return this; } diff --git a/src/chrome/communication/internalChannels.ts b/src/chrome/communication/internalChannels.ts index 418940a8b..d23d94158 100644 --- a/src/chrome/communication/internalChannels.ts +++ b/src/chrome/communication/internalChannels.ts @@ -2,8 +2,8 @@ import { NotificationChannelIdentifier } from './notificationsCommunicator'; import { BPRecipie } from '../internal/breakpoints/bpRecipie'; import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; import { registerChannels } from './channel'; -import { PausedEvent } from '../target/events'; import { Vote } from './collaborativeDecision'; +import { PausedEvent } from '../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; const _breakpoints = { // Notifications diff --git a/src/chrome/communication/targetChannels.ts b/src/chrome/communication/targetChannels.ts index 6a4325d0a..d4d7abec9 100644 --- a/src/chrome/communication/targetChannels.ts +++ b/src/chrome/communication/targetChannels.ts @@ -1,8 +1,9 @@ import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; import { NotificationChannelIdentifier } from './notificationsCommunicator'; import { Breakpoint } from '../internal/breakpoints/breakpoint'; -import { ScriptParsedEvent, PausedEvent } from '../target/events'; import { registerChannels } from './channel'; +import { ScriptParsedEvent } from '../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; +import { PausedEvent } from '../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; const _debugger = { // Notifications diff --git a/src/chrome/consoleHelper.ts b/src/chrome/consoleHelper.ts index 378ead93b..bdc120f4f 100644 --- a/src/chrome/consoleHelper.ts +++ b/src/chrome/consoleHelper.ts @@ -2,12 +2,12 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; import * as Color from 'color'; import * as variables from './variables'; -import { ExceptionDetails } from './target/events'; import { IScript } from './internal/scripts/script'; import { CodeFlowStackTrace } from './internal/stackTraces/stackTrace'; +import { ExceptionDetails } from './cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider'; export function formatExceptionDetails(e: ExceptionDetails): string { if (!e.exception) { @@ -20,7 +20,7 @@ export function formatExceptionDetails(e: ExceptionDetails): string { export const clearConsoleCode = '\u001b[2J'; -export function formatConsoleArguments(type: Crdp.Runtime.ConsoleAPICalledEvent['type'], args: Crdp.Runtime.RemoteObject[], stackTrace?: CodeFlowStackTrace): { args: Crdp.Runtime.RemoteObject[], isError: boolean } { +export function formatConsoleArguments(type: CDTP.Runtime.ConsoleAPICalledEvent['type'], args: CDTP.Runtime.RemoteObject[], stackTrace?: CodeFlowStackTrace): { args: CDTP.Runtime.RemoteObject[], isError: boolean } { switch (type) { case 'log': case 'debug': @@ -76,7 +76,7 @@ export function formatConsoleArguments(type: Crdp.Runtime.ConsoleAPICalledEvent[ /** * Collapse non-object arguments, and apply format specifiers (%s, %d, etc). Return a reduced a formatted list of RemoteObjects. */ -function resolveParams(args: Crdp.Runtime.RemoteObject[], skipFormatSpecifiers?: boolean): Crdp.Runtime.RemoteObject[] { +function resolveParams(args: CDTP.Runtime.RemoteObject[], skipFormatSpecifiers?: boolean): CDTP.Runtime.RemoteObject[] { if (!args.length || args[0].objectId) { // If the first arg is not text, nothing is going to happen here return args; @@ -95,7 +95,7 @@ function resolveParams(args: Crdp.Runtime.RemoteObject[], skipFormatSpecifiers?: formatSpecifiers = []; } - const processedArgs: Crdp.Runtime.RemoteObject[] = []; + const processedArgs: CDTP.Runtime.RemoteObject[] = []; const pushStringArg = (strArg: string) => { if (typeof strArg === 'string') { processedArgs.push({ type: 'string', value: strArg }); @@ -140,7 +140,7 @@ function resolveParams(args: Crdp.Runtime.RemoteObject[], skipFormatSpecifiers?: return processedArgs; } -function formatArg(formatSpec: string, arg: Crdp.Runtime.RemoteObject): string | Crdp.Runtime.RemoteObject { +function formatArg(formatSpec: string, arg: CDTP.Runtime.RemoteObject): string | CDTP.Runtime.RemoteObject { const paramValue = String(typeof arg.value !== 'undefined' ? arg.value : arg.description); if (formatSpec === 's') { diff --git a/src/chrome/debugee/debugeeLauncher.ts b/src/chrome/debugeeStartup/debugeeLauncher.ts similarity index 100% rename from src/chrome/debugee/debugeeLauncher.ts rename to src/chrome/debugeeStartup/debugeeLauncher.ts diff --git a/src/chrome/dependencyInjection.ts/bind.ts b/src/chrome/dependencyInjection.ts/bind.ts index cd0fb8cc5..80cf02be6 100644 --- a/src/chrome/dependencyInjection.ts/bind.ts +++ b/src/chrome/dependencyInjection.ts/bind.ts @@ -1,15 +1,10 @@ import { Container, interfaces } from 'inversify'; import { TYPES } from './types'; -import { IDOMInstrumentationBreakpoints, CDTPDOMDebugger, IBrowserNavigation, CDTPPage, IDebugeeVersionProvider, CDTPBrowser } from '../target/cdtpSmallerModules'; -import { IEventsToClientReporter, EventSender } from '../client/eventSender'; -import { IDebugeeExecutionControl, ControlDebugeeExecution, IDebugeeStepping } from '../target/controlDebugeeExecution'; -import { IPauseOnExceptions, IAsyncDebuggingConfiguration, IScriptSources, CDTPDebugger } from '../target/cdtpDebugger'; -import { IBreakpointFeaturesSupport, BreakpointFeaturesSupport } from '../target/breakpointFeaturesSupport'; +import { EventSender } from '../client/eventSender'; +import { CDTPBreakpointFeaturesSupport } from '../cdtpDebuggee/features/cdtpBreakpointFeaturesSupport'; import { IStackTracePresentationLogicProvider, StackTracesLogic } from '../internal/stackTraces/stackTracesLogic'; -import { CDTPStackTraceParser } from '../target/cdtpStackTraceParser'; -import { CDTPLocationParser } from '../target/cdtpLocationParser'; import { SourcesLogic } from '../internal/sources/sourcesLogic'; -import { CDTPScriptsRegistry } from '../target/cdtpScriptsRegistry'; +import { CDTPScriptsRegistry } from '../cdtpDebuggee/registries/cdtpScriptsRegistry'; import { ClientToInternal } from '../client/clientToInternal'; import { InternalToClient } from '../client/internalToClient'; import { BreakpointsLogic } from '../internal/breakpoints/breakpointsLogic'; @@ -19,69 +14,80 @@ import { DotScriptCommand } from '../internal/sources/features/dotScriptsCommand import { BreakpointsRegistry } from '../internal/breakpoints/breakpointsRegistry'; import { ReAddBPsWhenSourceIsLoaded } from '../internal/breakpoints/features/reAddBPsWhenSourceIsLoaded'; import { PauseScriptLoadsToSetBPs } from '../internal/breakpoints/features/pauseScriptLoadsToSetBPs'; -import { BPRecipieInLoadedSourceLogic } from '../internal/breakpoints/bpRecipieInLoadedSourceLogic'; -import { CDTPDiagnostics } from '../target/cdtpDiagnostics'; +import { BPRecipieAtLoadedSourceLogic } from '../internal/breakpoints/bpRecipieAtLoadedSourceLogic'; import { DeleteMeScriptsRegistry } from '../internal/scripts/scriptsRegistry'; import { SyncStepping } from '../internal/stepping/features/syncStepping'; import { AsyncStepping } from '../internal/stepping/features/asyncStepping'; -import { BreakpointIdRegistry } from '../target/breakpointIdRegistry'; -import { ExceptionThrownEventProvider } from '../target/exceptionThrownEventProvider'; -import { ExecutionContextEventsProvider } from '../target/executionContextEventsProvider'; -import { IInspectDebugeeState, InspectDebugeeState } from '../target/inspectDebugeeState'; -import { IUpdateDebugeeState, UpdateDebugeeState } from '../target/updateDebugeeState'; +import { CDTPExceptionThrownEventsProvider } from '../cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider'; +import { CDTPExecutionContextEventsProvider } from '../cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider'; +import { CDTPInspectDebugeeState } from '../cdtpDebuggee/features/cdtpInspectDebugeeState'; +import { CDTPUpdateDebugeeState } from '../cdtpDebuggee/features/cdtpUpdateDebugeeState'; import { SmartStepLogic } from '../internal/features/smartStep'; import { LineColTransformer } from '../../transformers/lineNumberTransformer'; import { ChromeDebugLogic } from '../chromeDebugAdapter'; -import { CDTPOnScriptParsedEventProvider, IScriptParsedProvider } from '../target/cdtpOnScriptParsedEventProvider'; -import { CDTPDebuggerEventsProvider, ICDTPDebuggerEventsProvider } from '../target/cdtpDebuggerEventsProvider'; -import { ITargetBreakpoints, CDTPTargetBreakpoints } from '../target/cdtpTargetBreakpoints'; +import { CDTPOnScriptParsedEventProvider } from '../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; +import { CDTDebuggeeExecutionEventsProvider } from '../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; +import { CDTPDebuggeeBreakpoints } from '../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; +import { IDOMInstrumentationBreakpoints, CDTPDOMDebugger } from '../cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints'; +import { CDTPBrowserNavigator } from '../cdtpDebuggee/features/cdtpBrowserNavigator'; +import { CDTPLogEventsProvider } from '../cdtpDebuggee/eventsProviders/cdtpLogEventsProvider'; +import { CDTPConsoleEventsProvider } from '../cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider'; +import { IAsyncDebuggingConfigurer, CDTPAsyncDebuggingConfigurer } from '../cdtpDebuggee/features/CDTPAsyncDebuggingConfigurer'; +import { IScriptSourcesRetriever, CDTPScriptSourcesRetriever } from '../cdtpDebuggee/features/CDTPScriptSourcesRetriever'; +import { CDTPDebugeeExecutionController } from '../cdtpDebuggee/features/cdtpDebugeeExecutionController'; +import { CDTPPauseOnExceptionsConfigurer } from '../cdtpDebuggee/features/CDTPPauseOnExceptionsConfigurer'; +import { CDTPDebugeeSteppingController } from '../cdtpDebuggee/features/CDTPDebugeeSteppingController'; +import { CDTPDebugeeRuntimeVersionProvider } from '../cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider'; +import { CDTPBlackboxPatternsConfigurer } from '../cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer'; +import { CDTPDomainsEnabler } from '../cdtpDebuggee/infrastructure/cdtpDomainsEnabler'; export function bindAll(di: Container) { bind(di, TYPES.IDOMInstrumentationBreakpoints, CDTPDOMDebugger); - bind(di, TYPES.IAsyncDebuggingConfiguration, CDTPDebugger); - bind(di, TYPES.IScriptSources, CDTPDebugger); + bind(di, TYPES.IAsyncDebuggingConfiguration, CDTPAsyncDebuggingConfigurer); + bind(di, TYPES.IScriptSources, CDTPScriptSourcesRetriever); bind(di, TYPES.IStackTracePresentationLogicProvider, SmartStepLogic); // bind(di, TYPES.IStackTracePresentationLogicProvider, SkipFilesLogic); - bind(di, TYPES.IEventsToClientReporter, EventSender); - bind(di, TYPES.IDebugeeExecutionControl, ControlDebugeeExecution); - bind(di, TYPES.IPauseOnExceptions, CDTPDebugger); - bind(di, TYPES.IBreakpointFeaturesSupport, BreakpointFeaturesSupport); - bind(di, TYPES.IInspectDebugeeState, InspectDebugeeState); - bind(di, TYPES.IUpdateDebugeeState, UpdateDebugeeState); - bind(di, TYPES.CDTPStackTraceParser, CDTPStackTraceParser); - bind(di, TYPES.CDTPLocationParser, CDTPLocationParser); - bind(di, TYPES.ChromeDebugLogic, ChromeDebugLogic); - bind(di, TYPES.SourcesLogic, SourcesLogic); - bind(di, TYPES.CDTPScriptsRegistry, CDTPScriptsRegistry); - bind(di, TYPES.ClientToInternal, ClientToInternal); - bind(di, TYPES.InternalToClient, InternalToClient); - bind(di, TYPES.StackTracesLogic, StackTracesLogic); - bind(di, TYPES.BreakpointsLogic, BreakpointsLogic); - bind(di, TYPES.PauseOnExceptionOrRejection, PauseOnExceptionOrRejection); - bind(di, TYPES.Stepping, Stepping); - bind(di, TYPES.DotScriptCommand, DotScriptCommand); - bind(di, TYPES.CDTPDebugger, CDTPDebugger); - bind(di, TYPES.BreakpointsRegistry, BreakpointsRegistry); - bind(di, TYPES.ReAddBPsWhenSourceIsLoaded, ReAddBPsWhenSourceIsLoaded); - bind(di, TYPES.PauseScriptLoadsToSetBPs, PauseScriptLoadsToSetBPs); - bind(di, TYPES.BPRecipieInLoadedSourceLogic, BPRecipieInLoadedSourceLogic); - bind(di, TYPES.EventSender, EventSender); - bind(di, TYPES.CDTPDiagnostics, CDTPDiagnostics); - bind(di, TYPES.DeleteMeScriptsRegistry, DeleteMeScriptsRegistry); + bind(di, TYPES.IEventsToClientReporter, EventSender); + bind(di, TYPES.ChromeDebugLogic, ChromeDebugLogic); + bind(di, TYPES.SourcesLogic, SourcesLogic); + bind(di, TYPES.CDTPScriptsRegistry, CDTPScriptsRegistry); + bind(di, TYPES.ClientToInternal, ClientToInternal); + bind(di, TYPES.InternalToClient, InternalToClient); + bind(di, TYPES.StackTracesLogic, StackTracesLogic); + bind(di, TYPES.BreakpointsLogic, BreakpointsLogic); + bind(di, TYPES.PauseOnExceptionOrRejection, PauseOnExceptionOrRejection); + bind(di, TYPES.Stepping, Stepping); + bind(di, TYPES.DotScriptCommand, DotScriptCommand); + bind(di, TYPES.BreakpointsRegistry, BreakpointsRegistry); + bind(di, TYPES.ReAddBPsWhenSourceIsLoaded, ReAddBPsWhenSourceIsLoaded); + bind(di, TYPES.PauseScriptLoadsToSetBPs, PauseScriptLoadsToSetBPs); + bind(di, TYPES.EventSender, EventSender); + bind(di, TYPES.DeleteMeScriptsRegistry, DeleteMeScriptsRegistry); // bind(di, TYPES.BaseSourceMapTransformer, BaseSourceMapTransformer); // bind(di, TYPES.BasePathTransformer, BasePathTransformer); - bind(di, TYPES.SyncStepping, SyncStepping); - bind(di, TYPES.AsyncStepping, AsyncStepping); - bind(di, TYPES.BreakpointIdRegistry, BreakpointIdRegistry); - bind(di, TYPES.ExceptionThrownEventProvider, ExceptionThrownEventProvider); - bind(di, TYPES.ExecutionContextEventsProvider, ExecutionContextEventsProvider); - bind(di, TYPES.LineColTransformer, LineColTransformer); - bind(di, TYPES.IDebugeeStepping, ControlDebugeeExecution); - bind(di, TYPES.IBrowserNavigation, CDTPPage); - bind(di, TYPES.IScriptParsedProvider, CDTPOnScriptParsedEventProvider); - bind(di, TYPES.ICDTPDebuggerEventsProvider, CDTPDebuggerEventsProvider); - bind(di, TYPES.IDebugeeVersionProvider, CDTPBrowser); - bind(di, TYPES.ITargetBreakpoints, CDTPTargetBreakpoints); + // bind(di, TYPES.IStackTracePresentationLogicProvider, SkipFilesLogic); + bind(di, TYPES.IDebugeeExecutionControl, CDTPDebugeeExecutionController); + bind(di, TYPES.IPauseOnExceptions, CDTPPauseOnExceptionsConfigurer); + bind(di, TYPES.IBreakpointFeaturesSupport, CDTPBreakpointFeaturesSupport); + bind(di, TYPES.IInspectDebugeeState, CDTPInspectDebugeeState); + bind(di, TYPES.IUpdateDebugeeState, CDTPUpdateDebugeeState); + bind(di, TYPES.BPRecipieInLoadedSourceLogic, BPRecipieAtLoadedSourceLogic); + bind(di, TYPES.SyncStepping, SyncStepping); + bind(di, TYPES.AsyncStepping, AsyncStepping); + // bind(di, cdtpBreakpointIdsRegistry, cdtpBreakpointIdsRegistry); + bind(di, TYPES.ExceptionThrownEventProvider, CDTPExceptionThrownEventsProvider); + bind(di, TYPES.ExecutionContextEventsProvider, CDTPExecutionContextEventsProvider); + bind(di, TYPES.LineColTransformer, LineColTransformer); + bind(di, TYPES.IBrowserNavigation, CDTPBrowserNavigator); + bind(di, TYPES.IScriptParsedProvider, CDTPOnScriptParsedEventProvider); + bind(di, TYPES.ICDTPDebuggerEventsProvider, CDTDebuggeeExecutionEventsProvider); + bind(di, TYPES.IDebugeeVersionProvider, CDTPDebugeeRuntimeVersionProvider); + bind(di, TYPES.ITargetBreakpoints, CDTPDebuggeeBreakpoints); + bind(di, TYPES.IConsoleEventsProvider, CDTPConsoleEventsProvider); + bind(di, TYPES.ILogEventsProvider, CDTPLogEventsProvider); + bind(di, TYPES.IDebugeeSteppingController, CDTPDebugeeSteppingController); + bind(di, TYPES.IBlackboxPatternsConfigurer, CDTPBlackboxPatternsConfigurer); + bind(di, TYPES.IDomainsEnabler, CDTPDomainsEnabler); } function bind(container: Container, serviceIdentifier: interfaces.ServiceIdentifier, newable: interfaces.Newable): void { diff --git a/src/chrome/dependencyInjection.ts/types.ts b/src/chrome/dependencyInjection.ts/types.ts index a669682e5..c694a16e5 100644 --- a/src/chrome/dependencyInjection.ts/types.ts +++ b/src/chrome/dependencyInjection.ts/types.ts @@ -15,9 +15,8 @@ const TYPES = { IScriptSources: Symbol.for('IScriptSources'), EventsConsumedByConnectedCDA: Symbol.for('EventsConsumedByConnectedCDA'), ICDTPDebuggerEventsProvider: Symbol.for('ICDTPDebuggerEventsProvider'), + IDebugeeSteppingController: Symbol.for('IDebugeeSteppingController'), IDebuggeeLauncher: Symbol.for('IDebuggeeLauncher'), - CDTPStackTraceParser: Symbol.for('CDTPStackTraceParser'), - CDTPLocationParser: Symbol.for('CDTPLocationParser'), ChromeDebugLogic: Symbol.for('ChromeDebugLogic'), SourcesLogic: Symbol.for('SourcesLogic'), CDTPScriptsRegistry: Symbol.for('CDTPScriptsRegistry'), @@ -28,27 +27,23 @@ const TYPES = { PauseOnExceptionOrRejection: Symbol.for('PauseOnExceptionOrRejection'), Stepping: Symbol.for('Stepping'), DotScriptCommand: Symbol.for('DotScriptCommand'), - CDTPDebugger: Symbol.for('CDTPDebugger'), BreakpointsRegistry: Symbol.for('BreakpointsRegistry'), ReAddBPsWhenSourceIsLoaded: Symbol.for('ReAddBPsWhenSourceIsLoaded'), PauseScriptLoadsToSetBPs: Symbol.for('PauseScriptLoadsToSetBPs'), BPRecipieInLoadedSourceLogic: Symbol.for('BPRecipieInLoadedSourceLogic'), EventSender: Symbol.for('EventSender'), - CDTPDiagnostics: Symbol.for('CDTPDiagnostics'), DeleteMeScriptsRegistry: Symbol.for('DeleteMeScriptsRegistry'), BaseSourceMapTransformer: Symbol.for('BaseSourceMapTransformer'), BasePathTransformer: Symbol.for('BasePathTransformer'), SyncStepping: Symbol.for('SyncStepping'), AsyncStepping: Symbol.for('AsyncStepping'), ConnectedCDAConfiguration: Symbol.for('ConnectedCDAConfiguration'), - BreakpointIdRegistry: Symbol.for('BreakpointIdRegistry'), ExceptionThrownEventProvider: Symbol.for('ExceptionThrownEventProvider'), ExecutionContextEventsProvider: Symbol.for('ExecutionContextEventsProvider'), IInspectDebugeeState: Symbol.for('IInspectDebugeeState'), IUpdateDebugeeState: Symbol.for('IUpdateDebugeeState'), LineColTransformer: Symbol.for('LineColTransformer'), ChromeConnection: Symbol.for('ChromeConnection'), - IDebugeeStepping: Symbol.for('IDebugeeStepping'), IDebugeeVersionProvider: Symbol.for('IDebugeeVersionProvider'), IBrowserNavigation: Symbol.for('IBrowserNavigation'), IPausedOverlay: Symbol.for('IPausedOverlay'), @@ -58,6 +53,10 @@ const TYPES = { ICDTPRuntime: Symbol.for('ICDTPRuntime'), IScriptParsedProvider: Symbol.for('IScriptParsedProvider'), ITargetBreakpoints: Symbol.for('ITargetBreakpoints'), + IConsoleEventsProvider: Symbol.for('IConsoleEventsProvider'), + ILogEventsProvider: Symbol.for('ILogEventsProvider'), + IBlackboxPatternsConfigurer: Symbol.for('IBlackboxPatternsConfigurer'), + IDomainsEnabler: Symbol.for('IDomainsEnabler'), }; export { TYPES }; diff --git a/src/chrome/extensibility/extensibilityPoints.ts b/src/chrome/extensibility/extensibilityPoints.ts index 82a618a42..ffdf9f6c2 100644 --- a/src/chrome/extensibility/extensibilityPoints.ts +++ b/src/chrome/extensibility/extensibilityPoints.ts @@ -4,7 +4,7 @@ import { BaseSourceMapTransformer } from '../../transformers/baseSourceMapTransf import { LineColTransformer } from '../../transformers/lineNumberTransformer'; import { ILaunchRequestArgs, IAttachRequestArgs } from '../../debugAdapterInterfaces'; import { interfaces } from 'inversify'; -import { IDebuggeeLauncher, IDebuggeeRunner } from '../debugee/debugeeLauncher'; +import { IDebuggeeLauncher, IDebuggeeRunner } from '../debugeeStartup/debugeeLauncher'; import { ConnectedCDAConfiguration } from '../client/chromeDebugAdapter/cdaConfiguration'; export interface IExtensibilityPoints { diff --git a/src/chrome/internal/breakpoints/bpRecipie.ts b/src/chrome/internal/breakpoints/bpRecipie.ts index a365d60f3..2f78a274c 100644 --- a/src/chrome/internal/breakpoints/bpRecipie.ts +++ b/src/chrome/internal/breakpoints/bpRecipie.ts @@ -12,9 +12,11 @@ export interface IBPRecipie; readonly bpActionWhenHit: TBPActionWhenHit; - readonly unmappedBpRecipie: IBPRecipie; // Original bpRecipie before any mapping was done + readonly unmappedBPRecipie: AnyBPRecipie; // Original bpRecipie before any mapping was done } +export type AnyBPRecipie = IBPRecipie; + abstract class BPRecipieCommonLogic { public abstract get bpActionWhenHit(): TBPActionWhenHit; @@ -26,10 +28,10 @@ abstract class BPRecipieCommonLogic +abstract class UnmappedBPRecipieCommonLogic extends BPRecipieCommonLogic { - public get unmappedBpRecipie(): IBPRecipie { + public get unmappedBPRecipie(): IBPRecipie { return this; } @@ -42,10 +44,10 @@ abstract class UnamppedBPRecipieCommonLogic { public get bpActionWhenHit(): TBPActionWhenHit { - return this.unmappedBpRecipie.bpActionWhenHit; + return this.unmappedBPRecipie.bpActionWhenHit; } - constructor(public readonly unmappedBpRecipie: IBPRecipie, + constructor(public readonly unmappedBPRecipie: IBPRecipie, public readonly location: Location) { } public toString(): string { @@ -53,20 +55,12 @@ abstract class MappedBPRecipieCommonLogic - extends MappedBPRecipieCommonLogic implements IBPRecipie { - - public asBPInScriptRecipie(): BPRecipieInScript { - return new BPRecipieInScript(this.unmappedBpRecipie, this.location.mappedToScript()); - } -} - -export class BPRecipieInUnresolvedSource extends UnamppedBPRecipieCommonLogic implements IBPRecipie { +export class BPRecipieInUnresolvedSource extends UnmappedBPRecipieCommonLogic implements IBPRecipie { public withAlwaysBreakAction(): BPRecipieInUnresolvedSource { return new BPRecipieInUnresolvedSource(this.location, new AlwaysBreak()); } - public tryGettingBreakpointInLoadedSource( + public tryResolvingSource( succesfulAction: (breakpointInLoadedSource: BPRecipieInLoadedSource) => R, failedAction: (breakpointInUnbindedSource: BPRecipieInUnresolvedSource) => R): R { return this.location.tryResolvingSource( @@ -74,20 +68,29 @@ export class BPRecipieInUnresolvedSource failedAction(this)); } - public asBreakpointInLoadedSource(): BPRecipieInLoadedSource { - return this.tryGettingBreakpointInLoadedSource( + public resolvedToLoadedSource(): BPRecipieInLoadedSource { + return this.tryResolvingSource( breakpointInLoadedSource => breakpointInLoadedSource, () => { throw new Error(`Failed to convert ${this} into a breakpoint in a loaded source`); }); } - public asBreakpointWithLoadedSource(source: ILoadedSource): BPRecipieInLoadedSource { + public resolvedWithLoadedSource(source: ILoadedSource): BPRecipieInLoadedSource { return new BPRecipieInLoadedSource(this, this.location.resolvedWith(source)); } } +export class BPRecipieInLoadedSource + extends MappedBPRecipieCommonLogic implements IBPRecipie { + + public mappedToScript(): BPRecipieInScript { + return new BPRecipieInScript(this.unmappedBPRecipie, this.location.mappedToScript()); + } +} + export type IBreakpointRecipieInLoadedSource = IBPRecipie; export type IBreakpointRecipieInUnbindedSource = IBPRecipie; +// TODO: Are we missing the IBPActionWhenHit parameter here? export type BPRecipie = TResource extends ISource ? BPRecipieInUnresolvedSource : TResource extends ILoadedSource ? BPRecipieInLoadedSource : @@ -99,19 +102,19 @@ export type BPRecipie = export class BPRecipieInScript extends MappedBPRecipieCommonLogic implements IBPRecipie { - public atLocation(newLocation: LocationInScript): BPRecipieInScript { - return new BPRecipieInScript(this.unmappedBpRecipie, newLocation); + public withLocationReplaced(newLocation: LocationInScript): BPRecipieInScript { + return new BPRecipieInScript(this.unmappedBPRecipie, newLocation); } - public asBPInUrlRegexpRecipie(): BPRecipieInUrlRegexp { + public mappedToUrlRegexp(): BPRecipieInUrlRegexp { const urlRegexp = createURLRegexp(utils.pathToRegex(this.location.script.url)); - return new BPRecipieInUrlRegexp(this.unmappedBpRecipie, + return new BPRecipieInUrlRegexp(this.unmappedBPRecipie, new LocationInUrlRegexp(urlRegexp, this.location.coordinates)); } - public asBPInUrlRecipie(): BPRecipieInUrl { + public mappedToUrl(): BPRecipieInUrl { const url = this.location.script.runtimeSource.identifier; - return new BPRecipieInUrl(this.unmappedBpRecipie, + return new BPRecipieInUrl(this.unmappedBPRecipie, new LocationInUrl(url, this.location.coordinates)); } } diff --git a/src/chrome/internal/breakpoints/bpRecipieInLoadedSourceLogic.ts b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts similarity index 79% rename from src/chrome/internal/breakpoints/bpRecipieInLoadedSourceLogic.ts rename to src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts index 258aaf632..f68558b74 100644 --- a/src/chrome/internal/breakpoints/bpRecipieInLoadedSourceLogic.ts +++ b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts @@ -7,11 +7,11 @@ import { chromeUtils, logger } from '../../..'; import { createColumnNumber, createLineNumber } from '../locations/subtypes'; import { RangeInScript } from '../locations/rangeInScript'; import { BreakpointsRegistry } from './breakpointsRegistry'; -import { PausedEvent } from '../../target/events'; +import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { VoteRelevance, Vote, Abstained } from '../../communication/collaborativeDecision'; import { inject, injectable } from 'inversify'; -import { ITargetBreakpoints } from '../../target/cdtpTargetBreakpoints'; -import { IBreakpointFeaturesSupport } from '../../target/breakpointFeaturesSupport'; +import { IDebuggeeBreakpoints } from '../../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; +import { IBreakpointFeaturesSupport } from '../../cdtpDebuggee/features/cdtpBreakpointFeaturesSupport'; import { TYPES } from '../../dependencyInjection.ts/types'; import { InformationAboutPausedProvider, NotifyStoppedCommonLogic } from '../features/takeProperActionOnPausedEvent'; import { IEventsToClientReporter } from '../../client/eventSender'; @@ -30,16 +30,16 @@ export class HitBreakpoint extends NotifyStoppedCommonLogic { } export interface IBreakpointsInLoadedSource { - addBreakpointForLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise[]>; + addBreakpointAtLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise[]>; } -export interface BPRecipieInLoadedSourceLogicDependencies { +export interface BPRecipieAtLoadedSourceLogicDependencies { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; publishGoingToPauseClient(): void; } @injectable() -export class BPRecipieInLoadedSourceLogic implements IBreakpointsInLoadedSource { +export class BPRecipieAtLoadedSourceLogic implements IBreakpointsInLoadedSource { private readonly doesTargetSupportColumnBreakpointsCached: Promise; public async askForInformationAboutPaused(paused: PausedEvent): Promise> { @@ -53,10 +53,10 @@ export class BPRecipieInLoadedSourceLogic implements IBreakpointsInLoadedSource } } - public async addBreakpointForLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise[]> { - const bpInScriptRecipie = bpRecipie.asBPInScriptRecipie(); + public async addBreakpointAtLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise[]> { + const bpInScriptRecipie = bpRecipie.mappedToScript(); const bestLocation = await this.considerColumnAndSelectBestBPLocation(bpInScriptRecipie.location); - const bpRecipieInBestLocation = bpInScriptRecipie.atLocation(bestLocation); + const bpRecipieInBestLocation = bpInScriptRecipie.withLocationReplaced(bestLocation); const runtimeSource = bpInScriptRecipie.location.script.runtimeSource; this._breakpointRegistry.registerBPRecipie(bpRecipie); @@ -65,17 +65,17 @@ export class BPRecipieInLoadedSourceLogic implements IBreakpointsInLoadedSource if (!runtimeSource.doesScriptHasUrl()) { breakpoints = [await this._targetBreakpoints.setBreakpoint(bpRecipieInBestLocation)]; } else if (runtimeSource.identifier.isLocalFilePath()) { - breakpoints = await this._targetBreakpoints.setBreakpointByUrlRegexp(bpRecipieInBestLocation.asBPInUrlRegexpRecipie()); + breakpoints = await this._targetBreakpoints.setBreakpointByUrlRegexp(bpRecipieInBestLocation.mappedToUrlRegexp()); } else { // The script has a URL and it's not a local file path, so we can leave it as-is - breakpoints = await this._targetBreakpoints.setBreakpointByUrl(bpRecipieInBestLocation.asBPInUrlRecipie()); + breakpoints = await this._targetBreakpoints.setBreakpointByUrl(bpRecipieInBestLocation.mappedToUrl()); } breakpoints.forEach(breakpoint => this._breakpointRegistry.registerBreakpointAsBinded(breakpoint)); return breakpoints; } - public removeBreakpoint(bpRecipie: BPRecipie): Promise { - return this._targetBreakpoints.removeBreakpoint(bpRecipie); + public async removeBreakpoint(_bpRecipie: BPRecipie): Promise { + // TODO: Implement this method return this._targetBreakpoints.removeBreakpoint(bpRecipie); } private async considerColumnAndSelectBestBPLocation(location: LocationInScript): Promise { @@ -102,10 +102,10 @@ export class BPRecipieInLoadedSourceLogic implements IBreakpointsInLoadedSource } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: BPRecipieInLoadedSourceLogicDependencies, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: BPRecipieAtLoadedSourceLogicDependencies, @inject(TYPES.IBreakpointFeaturesSupport) private readonly _breakpointFeaturesSupport: IBreakpointFeaturesSupport, private readonly _breakpointRegistry: BreakpointsRegistry, - @inject(TYPES.ITargetBreakpoints) private readonly _targetBreakpoints: ITargetBreakpoints, + @inject(TYPES.ITargetBreakpoints) private readonly _targetBreakpoints: IDebuggeeBreakpoints, @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { this.doesTargetSupportColumnBreakpointsCached = this._breakpointFeaturesSupport.supportsColumnBreakpoints; } diff --git a/src/chrome/internal/breakpoints/bpRecipieStatus.ts b/src/chrome/internal/breakpoints/bpRecipieStatus.ts index c453bc916..30b716d80 100644 --- a/src/chrome/internal/breakpoints/bpRecipieStatus.ts +++ b/src/chrome/internal/breakpoints/bpRecipieStatus.ts @@ -1,4 +1,4 @@ -import { IBPRecipie } from './bpRecipie'; +import { IBPRecipie, AnyBPRecipie } from './bpRecipie'; import { ILoadedSource } from '../sources/loadedSource'; @@ -29,7 +29,7 @@ export class BPRecipieIsUnbinded implements IBPRecipieStatus { } constructor( - public readonly recipie: IBPRecipie, + public readonly recipie: AnyBPRecipie, public readonly statusDescription: string) { } } @@ -53,7 +53,7 @@ export class BPRecipieIsBinded implements IBPRecipieStatus { } constructor( - public readonly recipie: IBPRecipie, + public readonly recipie: AnyBPRecipie, public readonly breakpoints: IBreakpoint[], public readonly statusDescription: string) { if (this.breakpoints.length === 0) { diff --git a/src/chrome/internal/breakpoints/bpRecipies.ts b/src/chrome/internal/breakpoints/bpRecipies.ts index 0c83b683d..cd6fb49a7 100644 --- a/src/chrome/internal/breakpoints/bpRecipies.ts +++ b/src/chrome/internal/breakpoints/bpRecipies.ts @@ -29,7 +29,7 @@ export class BPRecipiesInUnresolvedSource extends BPRecipiesCommonLogic public tryGettingBPsInLoadedSource(ifSuccesfulDo: (desiredBPsInLoadedSource: BPRecipiesInLoadedSource) => R, ifFaileDo: () => R): R { return this.resource.tryResolving( loadedSource => { - const loadedSourceBPs = this.breakpoints.map(breakpoint => breakpoint.asBreakpointInLoadedSource()); + const loadedSourceBPs = this.breakpoints.map(breakpoint => breakpoint.resolvedToLoadedSource()); return ifSuccesfulDo(new BPRecipiesInLoadedSource(loadedSource, loadedSourceBPs)); }, ifFaileDo); diff --git a/src/chrome/internal/breakpoints/breakpointsLogic.ts b/src/chrome/internal/breakpoints/breakpointsLogic.ts index 7461502c5..4d35db40a 100644 --- a/src/chrome/internal/breakpoints/breakpointsLogic.ts +++ b/src/chrome/internal/breakpoints/breakpointsLogic.ts @@ -1,4 +1,4 @@ -import { IBPRecipie } from './bpRecipie'; +import { AnyBPRecipie } from './bpRecipie'; import { ITelemetryPropertyCollector, IComponent, ConnectedCDAConfiguration } from '../../..'; import { ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; import { BPRecipiesInUnresolvedSource } from './bpRecipies'; @@ -8,7 +8,7 @@ import { asyncMap } from '../../collections/async'; import { IBPRecipieStatus } from './bpRecipieStatus'; import { ClientCurrentBPRecipiesRegistry } from './clientCurrentBPRecipiesRegistry'; import { BreakpointsRegistry } from './breakpointsRegistry'; -import { BPRecipieInLoadedSourceLogic } from './bpRecipieInLoadedSourceLogic'; +import { BPRecipieAtLoadedSourceLogic } from './bpRecipieAtLoadedSourceLogic'; import { RemoveProperty } from '../../../typeUtils'; import { IEventsToClientReporter } from '../../client/eventSender'; import { PauseScriptLoadsToSetBPs, PauseScriptLoadsToSetBPsDependencies } from './features/pauseScriptLoadsToSetBPs'; @@ -42,7 +42,7 @@ export class BreakpointsLogic implements IComponent { this.onUnbounBPRecipieIsNowBound(breakpoint.recipie); } - private onUnbounBPRecipieIsNowBound(bpRecipie: IBPRecipie): void { + private onUnbounBPRecipieIsNowBound(bpRecipie: AnyBPRecipie): void { const bpRecipieStatus = this._breakpointRegistry.getStatusOfBPRecipie(bpRecipie); this._eventsToClientReporter.sendBPStatusChanged({ reason: 'changed', bpRecipieStatus }); } @@ -58,8 +58,8 @@ export class BreakpointsLogic implements IComponent { // Match desired breakpoints to existing breakpoints await asyncMap(requestedBPsToAddInLoadedSources.breakpoints, async requestedBP => { - // DIEGO TODO: Do we need to do one breakpoint at a time to avoid issues on Crdp, or can we do them in parallel now that we use a different algorithm? - await this._bprInLoadedSourceLogic.addBreakpointForLoadedSource(requestedBP); + // DIEGO TODO: Do we need to do one breakpoint at a time to avoid issues on CDTP, or can we do them in parallel now that we use a different algorithm? + await this._bprInLoadedSourceLogic.addBreakpointAtLoadedSource(requestedBP); }); await Promise.all(bpsDelta.existingToRemove.map(async existingBPToRemove => { await this._bprInLoadedSourceLogic.removeBreakpoint(existingBPToRemove); @@ -71,7 +71,7 @@ export class BreakpointsLogic implements IComponent { // We need to investigate if we can make the new breakpoint using a pseudo-regexp to make the target think that they are on different locations // and thus workaround this issue await this._bprInLoadedSourceLogic.removeBreakpoint(existingToBeReplaced.existingBP); - await this._bprInLoadedSourceLogic.addBreakpointForLoadedSource(existingToBeReplaced.replacement.asBreakpointInLoadedSource()); + await this._bprInLoadedSourceLogic.addBreakpointAtLoadedSource(existingToBeReplaced.replacement.resolvedToLoadedSource()); }); }, () => { @@ -104,7 +104,7 @@ export class BreakpointsLogic implements IComponent { @inject(TYPES.BreakpointsRegistry) private readonly _breakpointRegistry: BreakpointsRegistry, @inject(TYPES.ReAddBPsWhenSourceIsLoaded) private readonly _unbindedBreakpointsLogic: ReAddBPsWhenSourceIsLoaded, @inject(TYPES.PauseScriptLoadsToSetBPs) private readonly _bpsWhileLoadingLogic: PauseScriptLoadsToSetBPs, - @inject(TYPES.BPRecipieInLoadedSourceLogic) private readonly _bprInLoadedSourceLogic: BPRecipieInLoadedSourceLogic, + @inject(TYPES.BPRecipieInLoadedSourceLogic) private readonly _bprInLoadedSourceLogic: BPRecipieAtLoadedSourceLogic, @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter, @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration) { this._dependencies.onAsyncBreakpointResolved(breakpoint => this.onAsyncBreakpointResolved(breakpoint)); diff --git a/src/chrome/internal/breakpoints/breakpointsRegistry.ts b/src/chrome/internal/breakpoints/breakpointsRegistry.ts index fa9897e52..14204593e 100644 --- a/src/chrome/internal/breakpoints/breakpointsRegistry.ts +++ b/src/chrome/internal/breakpoints/breakpointsRegistry.ts @@ -1,14 +1,14 @@ import { IBPRecipieStatus, BPRecipieIsBinded, BPRecipieIsUnbinded } from './bpRecipieStatus'; import { IBreakpoint } from './breakpoint'; import { ValidatedMultiMap } from '../../collections/validatedMultiMap'; -import { BPRecipie, IBPRecipie } from './bpRecipie'; +import { BPRecipie, AnyBPRecipie } from './bpRecipie'; import { ScriptOrSourceOrURLOrURLRegexp, LocationInScript } from '../locations/location'; import { injectable } from 'inversify'; @injectable() export class BreakpointsRegistry { // TODO DIEGO: Figure out how to handle if two breakpoint rules set a breakpoint in the same location so it ends up being the same breakpoint id - private readonly _unmappedRecipieToBreakpoints = new ValidatedMultiMap, + private readonly _unmappedRecipieToBreakpoints = new ValidatedMultiMap>(); public registerBPRecipie(bpRecipie: BPRecipie): void { @@ -16,10 +16,10 @@ export class BreakpointsRegistry { } public registerBreakpointAsBinded(bp: IBreakpoint): void { - this._unmappedRecipieToBreakpoints.add(bp.recipie.unmappedBpRecipie, bp); + this._unmappedRecipieToBreakpoints.add(bp.recipie.unmappedBPRecipie, bp); } - public getStatusOfBPRecipie(bpRecipie: IBPRecipie): IBPRecipieStatus { + public getStatusOfBPRecipie(bpRecipie: AnyBPRecipie): IBPRecipieStatus { const breakpoints = this._unmappedRecipieToBreakpoints.get(bpRecipie); if (breakpoints.size > 0) { return new BPRecipieIsBinded(bpRecipie, Array.from(breakpoints), 'TODO DIEGO'); diff --git a/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts b/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts index bbc78de88..59e50f8e7 100644 --- a/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts +++ b/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts @@ -14,7 +14,7 @@ export class ClientCurrentBPRecipiesRegistry { } private registerCurrentBPRecipies(requestedSourceIdentifier: IResourceIdentifier, bpRecipies: BPRecipieInUnresolvedSource[]): void { - this._requestedSourcePathToCurrentBPRecipies.set(requestedSourceIdentifier, Array.from(bpRecipies)); + this._requestedSourcePathToCurrentBPRecipies.setAndReplaceIfExist(requestedSourceIdentifier, Array.from(bpRecipies)); } private calculateBPSDeltaFromExistingBPs(requestedBPRecipies: BPRecipiesInUnresolvedSource): BPRsDeltaInRequestedSource { diff --git a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts index df794b994..58f6926ad 100644 --- a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts +++ b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts @@ -1,16 +1,15 @@ import { IComponent } from '../../features/feature'; -import { PausedEvent } from '../../../target/events'; -import { BPRecipieInUnresolvedSource, IBPRecipie } from '../bpRecipie'; +import { BPRecipieInUnresolvedSource, AnyBPRecipie } from '../bpRecipie'; import { BreakOnHitCount } from '../bpActionWhenHit'; import { ValidatedMap } from '../../../collections/validatedMap'; import { HitCountConditionParser, HitCountConditionFunction } from '../hitCountConditionParser'; -import { ScriptOrSourceOrURLOrURLRegexp } from '../../locations/location'; -import { NotifyStoppedCommonLogic, InformationAboutPausedProvider } from '../../features/takeProperActionOnPausedEvent'; +import { NotifyStoppedCommonLogic, InformationAboutPausedProvider } from '../../features/takeProperActionOnPausedEvent'; import { ReasonType } from '../../../stoppedEvent'; import { Vote, Abstained, VoteRelevance } from '../../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; import { IEventsToClientReporter } from '../../../client/eventSender'; import { TYPES } from '../../../dependencyInjection.ts/types'; +import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; export interface HitCountBreakpointsDependencies { registerAddBPRecipieHandler(handlerRequirements: (bpRecipie: BPRecipieInUnresolvedSource) => boolean, @@ -50,7 +49,7 @@ export class HitAndSatisfiedCountBPCondition extends NotifyStoppedCommonLogic { // TODO DIEGO: Install and use this feature @injectable() export class HitCountBreakpoints implements IComponent { - private readonly underlyingToBPRecipie = new ValidatedMap, HitCountBPData>(); + private readonly underlyingToBPRecipie = new ValidatedMap(); public install(): void { this._dependencies.registerAddBPRecipieHandler( @@ -68,7 +67,7 @@ export class HitCountBreakpoints implements IComponent { public async askForInformationAboutPaused(paused: PausedEvent): Promise> { const hitCountBPData = paused.hitBreakpoints.map(hitBPRecipie => - this.underlyingToBPRecipie.tryGetting(hitBPRecipie.unmappedBpRecipie)).filter(bpRecipie => bpRecipie !== undefined); + this.underlyingToBPRecipie.tryGetting(hitBPRecipie.unmappedBPRecipie)).filter(bpRecipie => bpRecipie !== undefined); const individualDecisions = hitCountBPData.map(data => data.notifyBPHit()); return individualDecisions.indexOf(VoteRelevance.NormalVote) >= 0 diff --git a/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts index e7580d7b7..70358d9f7 100644 --- a/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts +++ b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts @@ -1,5 +1,4 @@ import { asyncMap } from '../../../collections/async'; -import { PausedEvent } from '../../../target/events'; import { ILoadedSource } from '../../sources/loadedSource'; import { IComponent } from '../../features/feature'; import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../../locations/location'; @@ -8,12 +7,14 @@ import { NotifyStoppedCommonLogic, ResumeCommonLogic, InformationAboutPausedProv import { ReasonType } from '../../../stoppedEvent'; import { VoteRelevance, Vote, Abstained } from '../../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; -import { IDOMInstrumentationBreakpoints, IDebugeeVersionProvider } from '../../../target/cdtpSmallerModules'; import { TYPES } from '../../../dependencyInjection.ts/types'; import { IEventsToClientReporter } from '../../../client/eventSender'; -import { IDebugeeExecutionControl } from '../../../target/controlDebugeeExecution'; +import { IDebugeeExecutionController } from '../../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; import { ReAddBPsWhenSourceIsLoaded } from './reAddBPsWhenSourceIsLoaded'; import { BreakpointsRegistry } from '../breakpointsRegistry'; +import { IDOMInstrumentationBreakpoints } from '../../../cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints'; +import { IDebugeeRuntimeVersionProvider } from '../../../cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider'; +import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; export type Dummy = VoteRelevance; // If we don't do this the .d.ts doesn't include VoteRelevance and the compilation fails. Remove this when the issue disappears... export interface PauseScriptLoadsToSetBPsDependencies { @@ -37,11 +38,12 @@ export class HitStillPendingBreakpoint extends NotifyStoppedCommonLogic { export class PausedWhileLoadingScriptToResolveBreakpoints extends ResumeCommonLogic { public readonly relevance = VoteRelevance.FallbackVote; - constructor(protected readonly _debugeeExecutionControl: IDebugeeExecutionControl) { + constructor(protected readonly _debugeeExecutionControl: IDebugeeExecutionController) { super(); } } +/// TODO: Move this to a browser-shared package @injectable() export class PauseScriptLoadsToSetBPs implements IComponent { private readonly stopsWhileScriptsLoadInstrumentationName = 'scriptFirstStatement'; @@ -108,20 +110,17 @@ export class PauseScriptLoadsToSetBPs implements IComponent { // On version 69 Chrome stopped sending an extra event for DOM Instrumentation: See https://bugs.chromium.org/p/chromium/issues/detail?id=882909 // On Chrome 68 we were relying on that event to make Break on load work on breakpoints on the first line of a file. On Chrome 69 we need an alternative way to make it work. // TODO: Reenable the code that uses Versions.Target.Version when this fails - const versions = await this._debugeeVersionProvider.getVersion(); - - const version = versions.product.replace(/Chrome\/([0-9]{2})\..*/, '$1'); - const majorVersionNumber = parseInt(version, 10); - this._scriptFirstStatementStopsBeforeFile = majorVersionNumber < 69; + const runtimeVersion = await this._debugeeVersionProvider.version(); + this._scriptFirstStatementStopsBeforeFile = !runtimeVersion.isAtLeastVersion('69.0.0'); return this; } constructor( @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: PauseScriptLoadsToSetBPsDependencies, @inject(TYPES.IDOMInstrumentationBreakpoints) private readonly _domInstrumentationBreakpoints: IDOMInstrumentationBreakpoints, - @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionControl, + @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionController, @inject(TYPES.IEventsToClientReporter) protected readonly _eventsToClientReporter: IEventsToClientReporter, - @inject(TYPES.IDebugeeVersionProvider) protected readonly _debugeeVersionProvider: IDebugeeVersionProvider, + @inject(TYPES.IDebugeeVersionProvider) protected readonly _debugeeVersionProvider: IDebugeeRuntimeVersionProvider, @inject(TYPES.ReAddBPsWhenSourceIsLoaded) protected readonly _reAddBPsWhenSourceIsLoaded: ReAddBPsWhenSourceIsLoaded, @inject(TYPES.BreakpointsRegistry) protected readonly _breakpointsRegistry: BreakpointsRegistry, ) { diff --git a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts index 9276f92af..6e4d6d54e 100644 --- a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts +++ b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts @@ -7,7 +7,7 @@ import { IEventsToClientReporter } from '../../../client/eventSender'; import { PromiseDefer, promiseDefer } from '../../../../utils'; import { IComponent } from '../../features/feature'; import { injectable, inject } from 'inversify'; -import { IBreakpointsInLoadedSource } from '../bpRecipieInLoadedSourceLogic'; +import { IBreakpointsInLoadedSource } from '../bpRecipieAtLoadedSourceLogic'; import { TYPES } from '../../../dependencyInjection.ts/types'; export interface EventsConsumedByReAddBPsWhenSourceIsLoaded { @@ -52,7 +52,7 @@ export class ReAddBPsWhenSourceIsLoaded implements IComponent { const remainingBPRecipies = new Set(unbindBPRecipies.breakpoints); await asyncMap(unbindBPRecipies.breakpoints, async bpRecipie => { try { - const bpStatus = await this._breakpointsInLoadedSource.addBreakpointForLoadedSource(bpRecipie.asBreakpointWithLoadedSource(source)); + const bpStatus = await this._breakpointsInLoadedSource.addBreakpointAtLoadedSource(bpRecipie.resolvedWithLoadedSource(source)); this._eventsToClientReporter.sendBPStatusChanged({ bpRecipieStatus: new BPRecipieIsBinded(bpRecipie, bpStatus, 'TODO DIEGO'), reason: 'changed' diff --git a/src/chrome/internal/domains/supportedDomains.ts b/src/chrome/internal/domains/supportedDomains.ts index f219c7e9a..48194139c 100644 --- a/src/chrome/internal/domains/supportedDomains.ts +++ b/src/chrome/internal/domains/supportedDomains.ts @@ -1,9 +1,10 @@ import { IComponent } from '../features/feature'; -import { Crdp } from '../../..'; +import { Protocol as CDTP } from 'devtools-protocol'; + import { injectable } from 'inversify'; export interface SupportedDomainsDependencies { - getTargetDebuggerDomainsSchemas(): Promise; + getTargetDebuggerDomainsSchemas(): Promise; } export interface ISupportedDomains { @@ -12,7 +13,7 @@ export interface ISupportedDomains { @injectable() export class SupportedDomains implements IComponent, ISupportedDomains { - private readonly _domains = new Map(); + private readonly _domains = new Map(); public isSupported(domainName: string): boolean { return this._domains.has(domainName); diff --git a/src/chrome/internal/exceptions/pauseOnException.ts b/src/chrome/internal/exceptions/pauseOnException.ts index b88b26af3..4bbbdaa3d 100644 --- a/src/chrome/internal/exceptions/pauseOnException.ts +++ b/src/chrome/internal/exceptions/pauseOnException.ts @@ -1,6 +1,5 @@ import { InformationAboutPausedProvider, NotifyStoppedCommonLogic } from '../features/takeProperActionOnPausedEvent'; import { IComponent } from '../features/feature'; -import { PausedEvent } from '../../target/events'; import * as errors from '../../../errors'; import { utils } from '../../..'; import { FormattedExceptionParser, IFormattedExceptionLineDescription } from '../formattedExceptionParser'; @@ -8,9 +7,10 @@ import { PauseOnPromiseRejectionsStrategy, PauseOnExceptionsStrategy } from './s import { VoteRelevance, Vote, Abstained } from '../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; -import { IPauseOnExceptions } from '../../target/cdtpDebugger'; import { IEventsToClientReporter } from '../../client/eventSender'; import { DeleteMeScriptsRegistry } from '../scripts/scriptsRegistry'; +import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; +import { IPauseOnExceptionsConfigurer } from '../../cdtpDebuggee/features/CDTPPauseOnExceptionsConfigurer'; type ExceptionBreakMode = 'never' | 'always' | 'unhandled' | 'userUnhandled'; @@ -113,6 +113,6 @@ export class PauseOnExceptionOrRejection implements IComponent { constructor(@inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByPauseOnException, @inject(TYPES.DeleteMeScriptsRegistry) private readonly _scriptsLogic: DeleteMeScriptsRegistry, - @inject(TYPES.IPauseOnExceptions) private readonly _pauseOnExceptions: IPauseOnExceptions, + @inject(TYPES.IPauseOnExceptions) private readonly _pauseOnExceptions: IPauseOnExceptionsConfigurer, @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { } } \ No newline at end of file diff --git a/src/chrome/internal/features/skipFiles.ts b/src/chrome/internal/features/skipFiles.ts index 8d7303a9e..573ef0682 100644 --- a/src/chrome/internal/features/skipFiles.ts +++ b/src/chrome/internal/features/skipFiles.ts @@ -1,17 +1,17 @@ -import { IToggleSkipFileStatusArgs, utils, Crdp, BaseSourceMapTransformer, parseResourceIdentifier, ConnectedCDAConfiguration } from '../../..'; +import { IToggleSkipFileStatusArgs, utils, CDTP, BaseSourceMapTransformer, parseResourceIdentifier, ConnectedCDAConfiguration } from '../../..'; import { logger } from 'vscode-debugadapter/lib/logger'; import { IScript } from '../scripts/script'; -import { CDTPDiagnostics } from '../../target/cdtpDiagnostics'; import { StackTracesLogic, IStackTracePresentationLogicProvider } from '../stackTraces/stackTracesLogic'; import { newResourceIdentifierMap, IResourceIdentifier } from '../sources/resourceIdentifier'; import { IComponent } from './feature'; -import { ScriptParsedEvent } from '../../target/events'; import { LocationInLoadedSource } from '../locations/location'; import { ICallFramePresentationDetails } from '../stackTraces/callFramePresentation'; import * as nls from 'vscode-nls'; import { injectable, inject, LazyServiceIdentifer } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { ClientToInternal } from '../../client/clientToInternal'; +import { ScriptParsedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; +import { IBlackboxPatternsConfigurer } from '../../cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer'; const localize = nls.loadMessageBundle(); export interface EventsConsumedBySkipFilesLogic { @@ -136,7 +136,7 @@ export class SkipFilesLogic implements IComponent, ISta private refreshBlackboxPatterns(): void { // Make sure debugging domain is enabled before calling refreshBlackboxPatterns() - this.chrome.Debugger.setBlackboxPatterns({ + this._blackboxPatternsConfigurer.setBlackboxPatterns({ patterns: this._blackboxedRegexes.map(regex => regex.source) }).catch(() => this.warnNoSkipFiles()); } @@ -174,7 +174,7 @@ export class SkipFilesLogic implements IComponent, ISta public async resolveSkipFiles(script: IScript, mappedUrl: IResourceIdentifier, sources: IResourceIdentifier[], toggling?: boolean): Promise { if (sources && sources.length) { const parentIsSkipped = this.shouldSkipSource(script.runtimeSource.identifier); - const libPositions: Crdp.Debugger.ScriptPosition[] = []; + const libPositions: CDTP.Debugger.ScriptPosition[] = []; // Figure out skip/noskip transitions within script let inLibRange = parentIsSkipped; @@ -213,10 +213,10 @@ export class SkipFilesLogic implements IComponent, ISta }; } - await this.chrome.Debugger.setBlackboxedRanges(script, []).catch(() => this.warnNoSkipFiles()); + await this._blackboxPatternsConfigurer.setBlackboxedRanges(script, []).catch(() => this.warnNoSkipFiles()); if (libPositions.length) { - this.chrome.Debugger.setBlackboxedRanges(script, libPositions).catch(() => this.warnNoSkipFiles()); + this._blackboxPatternsConfigurer.setBlackboxedRanges(script, libPositions).catch(() => this.warnNoSkipFiles()); } } } else { @@ -224,7 +224,7 @@ export class SkipFilesLogic implements IComponent, ISta const skippedByPattern = this.matchesSkipFilesPatterns(mappedUrl); if (typeof status === 'boolean' && status !== skippedByPattern) { const positions = status ? [{ lineNumber: 0, columnNumber: 0 }] : []; - this.chrome.Debugger.setBlackboxedRanges(script, positions).catch(() => this.warnNoSkipFiles()); + this._blackboxPatternsConfigurer.setBlackboxedRanges(script, positions).catch(() => this.warnNoSkipFiles()); } } } @@ -276,10 +276,10 @@ export class SkipFilesLogic implements IComponent, ISta constructor( @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedBySkipFilesLogic, - @inject(TYPES.CDTPDiagnostics) private readonly chrome: CDTPDiagnostics, @inject(new LazyServiceIdentifer(() => TYPES.StackTracesLogic)) private readonly stackTracesLogic: StackTracesLogic, @inject(TYPES.BaseSourceMapTransformer) private readonly sourceMapTransformer: BaseSourceMapTransformer, @inject(TYPES.ClientToInternal) private readonly _clientToInternal: ClientToInternal, - @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration + @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration, + @inject(TYPES.IBlackboxPatternsConfigurer) private readonly _blackboxPatternsConfigurer: IBlackboxPatternsConfigurer, ) { } } \ No newline at end of file diff --git a/src/chrome/internal/features/smartStep.ts b/src/chrome/internal/features/smartStep.ts index 354c850b6..56e10d533 100644 --- a/src/chrome/internal/features/smartStep.ts +++ b/src/chrome/internal/features/smartStep.ts @@ -2,7 +2,7 @@ import { BasePathTransformer } from '../../../transformers/basePathTransformer'; import { BaseSourceMapTransformer } from '../../../transformers/baseSourceMapTransformer'; import { IScript } from '../scripts/script'; import { ICallFrame } from '../stackTraces/callFrame'; -import { PausedEvent } from '../../target/events'; +import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { InformationAboutPausedProvider } from './takeProperActionOnPausedEvent'; import { logger } from 'vscode-debugadapter'; import { IComponent } from './feature'; diff --git a/src/chrome/internal/features/takeProperActionOnPausedEvent.ts b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts index a97870ec5..694b08c16 100644 --- a/src/chrome/internal/features/takeProperActionOnPausedEvent.ts +++ b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts @@ -1,16 +1,16 @@ import { IComponent } from './feature'; -import { PausedEvent } from '../../target/events'; +import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { IEventsToClientReporter } from '../../client/eventSender'; import { ReasonType } from '../../stoppedEvent'; import { PromiseOrNot } from '../../utils/promises'; import { Vote, VoteCommonLogic, VoteRelevance, ExecuteDecisionBasedOnVotes } from '../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; -import { IDebugeeExecutionControl } from '../../target/controlDebugeeExecution'; -import { ICDTPDebuggerEventsProvider } from '../../target/cdtpDebuggerEventsProvider'; +import { IDebugeeExecutionController } from '../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; +import { ICDTDebuggeeExecutionEventsProvider } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; export abstract class ResumeCommonLogic extends VoteCommonLogic { - protected readonly abstract _debugeeExecutionControl: IDebugeeExecutionControl; + protected readonly abstract _debugeeExecutionControl: IDebugeeExecutionController; public async execute(): Promise { this._debugeeExecutionControl.resume(); @@ -54,7 +54,7 @@ export class TakeProperActionOnPausedEvent implements IComponent { constructor( @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: TakeActionBasedOnInformationDependencies, - @inject(TYPES.ICDTPDebuggerEventsProvider) private readonly _cdtpDebuggerEventsProvider: ICDTPDebuggerEventsProvider, + @inject(TYPES.ICDTPDebuggerEventsProvider) private readonly _cdtpDebuggerEventsProvider: ICDTDebuggeeExecutionEventsProvider, @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { } } diff --git a/src/chrome/internal/scripts/script.ts b/src/chrome/internal/scripts/script.ts index 7512c83f8..6182a7d78 100644 --- a/src/chrome/internal/scripts/script.ts +++ b/src/chrome/internal/scripts/script.ts @@ -9,6 +9,7 @@ import { printArray } from '../../collections/printing'; import { ISourcesMapper } from './sourcesMapper'; import { IResourceIdentifier, IResourceLocation, newResourceIdentifierMap, parseResourceIdentifier, ResourceName } from '../sources/resourceIdentifier'; import { IExecutionContext } from './executionContext'; +import { Lazy1 } from '../../utils/lazy'; /** This interface represents a piece of code that is being executed in the debugee. Usually a script matches to a file or a url, but that is not always the case. * This interface solves the problem of finding the different loaded sources associated with a script, and being able to identify and compare both scripts and sources easily. @@ -52,9 +53,11 @@ export class Script implements IScript { let developmentSource: (script: IScript) => ILoadedSource; if (locationInRuntimeEnvironment.isEquivalent(locationInDevelopmentEnvinronment) || locationInDevelopmentEnvinronment.textRepresentation === '') { if (fs.existsSync(locationInRuntimeEnvironment.textRepresentation)) { - developmentSource = runtimeSource = script => new ScriptRunFromLocalStorage(script, locationInRuntimeEnvironment, 'TODO DIEGO'); + developmentSource = runtimeSource = new Lazy1((script: IScript) => // Using Lazy1 will ensure both calls return the same instance + new ScriptRunFromLocalStorage(script, locationInRuntimeEnvironment, 'TODO DIEGO')).function; } else { - developmentSource = runtimeSource = script => new DynamicScript(script, locationInRuntimeEnvironment, 'TODO DIEGO'); + developmentSource = runtimeSource = new Lazy1((script: IScript) => // Using Lazy1 will ensure both calls return the same instance + new DynamicScript(script, locationInRuntimeEnvironment, 'TODO DIEGO')).function; } } else { // The script is served from one location, and it's on the workspace on a different location @@ -65,9 +68,9 @@ export class Script implements IScript { } public static createEval(executionContext: IExecutionContext, name: ResourceName, sourcesMapper: ISourcesMapper): Script { - // TODO DIEGO Return the same instance both functions - const getNoURLScript = (script: IScript) => new NoURLScriptSource(script, name, 'TODO DIEGO'); - return new Script(executionContext, getNoURLScript, getNoURLScript, _ => new Map(), sourcesMapper); + // Using Lazy1 will ensure both calls return the same instance + let getNoURLScript = new Lazy1((script: IScript) => new NoURLScriptSource(script, name, 'TODO DIEGO')); + return new Script(executionContext, getNoURLScript.function, getNoURLScript.function, _ => new Map(), sourcesMapper); } constructor(public readonly executionContext: IExecutionContext, getRuntimeSource: (script: IScript) => ILoadedSource, getDevelopmentSource: (script: IScript) => ILoadedSource, diff --git a/src/chrome/internal/scripts/scriptsRegistry.ts b/src/chrome/internal/scripts/scriptsRegistry.ts index dd5fbfeb2..966bdf3d0 100644 --- a/src/chrome/internal/scripts/scriptsRegistry.ts +++ b/src/chrome/internal/scripts/scriptsRegistry.ts @@ -1,4 +1,5 @@ -import { Crdp } from '../../..'; +import { Protocol as CDTP } from 'devtools-protocol'; + import { IScript } from './script'; import { ValidatedMap } from '../../collections/validatedMap'; import { IResourceIdentifier, newResourceIdentifierMap } from '../sources/resourceIdentifier'; @@ -8,19 +9,19 @@ import { injectable } from 'inversify'; @injectable() export class DeleteMeScriptsRegistry { private readonly _scriptsGeneration = new ScriptsGeneration(); - private readonly _idToExecutionContext = new ValidatedMap(); + private readonly _idToExecutionContext = new ValidatedMap(); - public registerExecutionContext(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { + public registerExecutionContext(executionContextId: CDTP.Runtime.ExecutionContextId): IExecutionContext { const executionContext = new ExecutionContext(); this._idToExecutionContext.set(executionContextId, executionContext); return executionContext; } - public getExecutionContextById(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { + public getExecutionContextById(executionContextId: CDTP.Runtime.ExecutionContextId): IExecutionContext { return this._idToExecutionContext.get(executionContextId); } - public registerNewScript(scriptId: Crdp.Runtime.ScriptId, obtainScript: () => Promise): Promise { + public registerNewScript(scriptId: CDTP.Runtime.ScriptId, obtainScript: () => Promise): Promise { return this._scriptsGeneration.registerNewScript(scriptId, obtainScript); } @@ -28,7 +29,7 @@ export class DeleteMeScriptsRegistry { return this._scriptsGeneration.getCdtpId(script); } - public getScriptById(runtimeScriptCrdpId: Crdp.Runtime.ScriptId): Promise { + public getScriptById(runtimeScriptCrdpId: CDTP.Runtime.ScriptId): Promise { return this._scriptsGeneration.scriptById(runtimeScriptCrdpId); } @@ -42,18 +43,18 @@ export class DeleteMeScriptsRegistry { } export class ScriptsGeneration { - private readonly _cdtpIdByScript = new ValidatedMap>(); - private readonly _scriptByCdtpId = new ValidatedMap(); + private readonly _cdtpIdByScript = new ValidatedMap>(); + private readonly _scriptByCdtpId = new ValidatedMap(); private readonly _scriptByPath = newResourceIdentifierMap(); - private createScriptInitialConfiguration(scriptId: Crdp.Runtime.ScriptId, script: IScript): void { + private createScriptInitialConfiguration(scriptId: CDTP.Runtime.ScriptId, script: IScript): void { this._scriptByCdtpId.set(script, scriptId); let scriptsWithSamePath = this._scriptByPath.getOrAdd(script.runtimeSource.identifier, () => []); scriptsWithSamePath.push(script); } - public async registerNewScript(scriptId: Crdp.Runtime.ScriptId, obtainScript: () => Promise): Promise { + public async registerNewScript(scriptId: CDTP.Runtime.ScriptId, obtainScript: () => Promise): Promise { const scriptWithConfigurationPromise = obtainScript().then(script => { /** * We need to configure the script here, so we can guarantee that clients who try to use a script will get @@ -69,7 +70,7 @@ export class ScriptsGeneration { return await scriptWithConfigurationPromise; } - public getCdtpId(script: IScript): Crdp.Runtime.ScriptId { + public getCdtpId(script: IScript): CDTP.Runtime.ScriptId { const scriptId = this._scriptByCdtpId.get(script); if (script === undefined) { diff --git a/src/chrome/internal/sources/features/dotScriptsCommand.ts b/src/chrome/internal/sources/features/dotScriptsCommand.ts index 8e7e5eb2b..d155171f5 100644 --- a/src/chrome/internal/sources/features/dotScriptsCommand.ts +++ b/src/chrome/internal/sources/features/dotScriptsCommand.ts @@ -8,7 +8,7 @@ import { inject, injectable } from 'inversify'; import { BaseSourceMapTransformer } from '../../../../transformers/baseSourceMapTransformer'; import { DeleteMeScriptsRegistry } from '../../scripts/scriptsRegistry'; import { TYPES } from '../../../dependencyInjection.ts/types'; -import { IScriptSources } from '../../../target/cdtpDebugger'; +import { IScriptSourcesRetriever } from '../../../cdtpDebuggee/features/CDTPScriptSourcesRetriever'; @injectable() export class DotScriptCommand { @@ -63,6 +63,6 @@ export class DotScriptCommand { constructor( @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, @inject(TYPES.DeleteMeScriptsRegistry) private readonly _scriptsLogic: DeleteMeScriptsRegistry, - @inject(TYPES.IScriptSources) private readonly _scriptSources: IScriptSources, + @inject(TYPES.IScriptSources) private readonly _scriptSources: IScriptSourcesRetriever, @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter) { } } diff --git a/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts index e2b62f907..950e81b45 100644 --- a/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts +++ b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts @@ -1,6 +1,5 @@ import { IComponent } from '../../features/feature'; import { IScript } from '../../scripts/script'; -import { ScriptParsedEvent } from '../../../target/events'; import { telemetry } from '../../../../telemetry'; import { SourceWasLoadedParameters, IEventsToClientReporter } from '../../../client/eventSender'; import { ValidatedMap } from '../../../collections/validatedMap'; @@ -8,6 +7,7 @@ import { CDTPScriptUrl } from '../resourceIdentifierSubtypes'; import { LoadedSourceEventReason, utils } from '../../../..'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../../dependencyInjection.ts/types'; +import { ScriptParsedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; export interface NotifyClientOfLoadedSourcesDependencies { sendSourceWasLoaded(params: SourceWasLoadedParameters): Promise; diff --git a/src/chrome/internal/sources/resourceIdentifierSubtypes.ts b/src/chrome/internal/sources/resourceIdentifierSubtypes.ts index 7d830d9c5..632f41f2e 100644 --- a/src/chrome/internal/sources/resourceIdentifierSubtypes.ts +++ b/src/chrome/internal/sources/resourceIdentifierSubtypes.ts @@ -3,6 +3,9 @@ import { IResourceIdentifier } from './resourceIdentifier'; // We use this class so the compiler will check that we don't send a file path where the URL provided by CDTP is expected const CDTPScriptUrlSymbol = Symbol(); export type CDTPScriptUrl = string & { readonly [CDTPScriptUrlSymbol]: true }; +export function createCDTPScriptUrl(textRepresentation: string): CDTPScriptUrl { + return textRepresentation; +} const ScriptDevelopmentLocationSymbol = Symbol(); export interface ScriptDevelopmentLocation extends IResourceIdentifier { diff --git a/src/chrome/internal/sources/sourceResolver.ts b/src/chrome/internal/sources/sourceResolver.ts index 4e7c7e9f7..de8dbdaa6 100644 --- a/src/chrome/internal/sources/sourceResolver.ts +++ b/src/chrome/internal/sources/sourceResolver.ts @@ -2,9 +2,9 @@ import { ILoadedSource } from './loadedSource'; import { ISource, SourceToBeResolvedViaPath } from './source'; import { newResourceIdentifierMap, IResourceIdentifier } from './resourceIdentifier'; import { IComponent } from '../features/feature'; -import { ScriptParsedEvent } from '../../target/events'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; +import { ScriptParsedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; export interface EventsConsumedBySourceResolver { onScriptParsed(listener: (scriptEvent: ScriptParsedEvent) => Promise): void; diff --git a/src/chrome/internal/sources/sourcesTextLogic.ts b/src/chrome/internal/sources/sourcesTextLogic.ts index b6ac9b1b4..166046060 100644 --- a/src/chrome/internal/sources/sourcesTextLogic.ts +++ b/src/chrome/internal/sources/sourcesTextLogic.ts @@ -4,7 +4,7 @@ import { printIterable } from '../../collections/printting'; import { IComponent } from '../features/feature'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; -import { IScriptSources } from '../../target/cdtpDebugger'; +import { IScriptSourcesRetriever } from '../../cdtpDebuggee/features/CDTPScriptSourcesRetriever'; @injectable() export class SourceTextLogic implements IComponent { @@ -29,5 +29,5 @@ export class SourceTextLogic implements IComponent { return this; } - constructor(@inject(TYPES.IScriptSources) private readonly _scriptSources: IScriptSources) { } + constructor(@inject(TYPES.IScriptSources) private readonly _scriptSources: IScriptSourcesRetriever) { } } \ No newline at end of file diff --git a/src/chrome/internal/sources/sourcesTreeNodeLogic.ts b/src/chrome/internal/sources/sourcesTreeNodeLogic.ts index 2d95eb5b3..5eaf8a150 100644 --- a/src/chrome/internal/sources/sourcesTreeNodeLogic.ts +++ b/src/chrome/internal/sources/sourcesTreeNodeLogic.ts @@ -3,7 +3,7 @@ import { IScript } from '../scripts/script'; import { IComponent } from '../features/feature'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; -import { CDTPScriptsRegistry } from '../../target/cdtpScriptsRegistry'; +import { CDTPScriptsRegistry } from '../../cdtpDebuggee/registries/cdtpScriptsRegistry'; @injectable() export class SourcesTreeNodeLogic implements IComponent { diff --git a/src/chrome/internal/stackTraces/callFrame.ts b/src/chrome/internal/stackTraces/callFrame.ts index 5d7ba97d4..044b8a773 100644 --- a/src/chrome/internal/stackTraces/callFrame.ts +++ b/src/chrome/internal/stackTraces/callFrame.ts @@ -1,10 +1,11 @@ import { Location } from '../locations/location'; -import { integer } from '../../target/events'; import { ILoadedSource } from '../sources/loadedSource'; import { IScript } from '../scripts/script'; -import { Crdp } from '../../..'; +import { Protocol as CDTP } from 'devtools-protocol'; + import { ICallFrameName } from './callFrameName'; import { Scope } from './scopes'; +import { integer } from '../../cdtpDebuggee/cdtpPrimitives'; export type ScriptOrLoadedSource = IScript | ILoadedSource; // Used for stack traces @@ -45,8 +46,8 @@ export interface ICallFrame { readonly name: string; readonly codeFlow: CodeFlowFrame; readonly scopeChain: Scope[]; - readonly frameThis?: Crdp.Runtime.RemoteObject; - readonly returnValue?: Crdp.Runtime.RemoteObject; + readonly frameThis?: CDTP.Runtime.RemoteObject; + readonly returnValue?: CDTP.Runtime.RemoteObject; readonly unmappedCallFrame: ICallFrame; } @@ -88,8 +89,8 @@ export class ScriptCallFrame extends CallFrameCommonLogic { constructor( public readonly codeFlow: CodeFlowFrame, public readonly scopeChain: Scope[], - public readonly frameThis?: Crdp.Runtime.RemoteObject, // This is optional only to support Runtime.StackTraces aka StackTraceCodeFlow - public readonly returnValue?: Crdp.Runtime.RemoteObject) { + public readonly frameThis?: CDTP.Runtime.RemoteObject, // This is optional only to support Runtime.StackTraces aka StackTraceCodeFlow + public readonly returnValue?: CDTP.Runtime.RemoteObject) { super(); } } @@ -99,11 +100,11 @@ export class LoadedSourceCallFrame extends CallFrameCommonLogic { return this.unmappedCallFrame.scopeChain; } - public get frameThis(): Crdp.Runtime.RemoteObject { + public get frameThis(): CDTP.Runtime.RemoteObject { return this.unmappedCallFrame.frameThis; } - public get returnValue(): Crdp.Runtime.RemoteObject { + public get returnValue(): CDTP.Runtime.RemoteObject { return this.unmappedCallFrame.returnValue; } diff --git a/src/chrome/internal/stackTraces/scopes.ts b/src/chrome/internal/stackTraces/scopes.ts index 01313357d..ed1f20186 100644 --- a/src/chrome/internal/stackTraces/scopes.ts +++ b/src/chrome/internal/stackTraces/scopes.ts @@ -1,10 +1,10 @@ import { LocationInScript } from '../locations/location'; -import { Crdp } from '../../..'; +import { Protocol as CDTP } from 'devtools-protocol'; export class Scope { constructor( public readonly type: ('global' | 'local' | 'with' | 'closure' | 'catch' | 'block' | 'script' | 'eval' | 'module'), - public readonly object: Crdp.Runtime.RemoteObject, + public readonly object: CDTP.Runtime.RemoteObject, public readonly name?: string, public readonly startLocation?: LocationInScript, public readonly endLocation?: LocationInScript) { } diff --git a/src/chrome/internal/stackTraces/stackTracesLogic.ts b/src/chrome/internal/stackTraces/stackTracesLogic.ts index b3f469f8e..450af3a77 100644 --- a/src/chrome/internal/stackTraces/stackTracesLogic.ts +++ b/src/chrome/internal/stackTraces/stackTracesLogic.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { PausedEvent } from '../../target/events'; +import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { StackTracePresentation, FramePresentationOrLabel, StackTraceLabel } from './stackTracePresentation'; import { ILoadedSource } from '../sources/loadedSource'; import { CodeFlowStackTrace } from './stackTrace'; @@ -19,9 +19,9 @@ import { IComponent, ComponentConfiguration } from '../features/feature'; import { InformationAboutPausedProvider } from '../features/takeProperActionOnPausedEvent'; import { asyncMap } from '../../collections/async'; import { TYPES } from '../../dependencyInjection.ts/types'; -import { IAsyncDebuggingConfiguration } from '../../target/cdtpDebugger'; import { ConnectedCDAConfiguration } from '../../..'; import { Vote, Abstained } from '../../communication/collaborativeDecision'; +import { IAsyncDebuggingConfigurer } from '../../cdtpDebuggee/features/CDTPAsyncDebuggingConfigurer'; export interface EventsConsumedByStackTrace { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; @@ -158,7 +158,7 @@ export class StackTracesLogic implements IComponent { @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByStackTrace, // TODO DIEGO: @multiInject(new LazyServiceIdentifer(() => TYPES.IStackTracePresentationLogicProvider)) private readonly _stackTracePresentationLogicProviders: IStackTracePresentationLogicProvider[], @inject(TYPES.IStackTracePresentationLogicProvider) private readonly _stackTracePresentationLogicProviders: IStackTracePresentationLogicProvider, - @inject(TYPES.IAsyncDebuggingConfiguration) private readonly _breakpointFeaturesSupport: IAsyncDebuggingConfiguration, + @inject(TYPES.IAsyncDebuggingConfiguration) private readonly _breakpointFeaturesSupport: IAsyncDebuggingConfigurer, @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration) { } } \ No newline at end of file diff --git a/src/chrome/internal/stepping/features/asyncStepping.ts b/src/chrome/internal/stepping/features/asyncStepping.ts index 2745a712b..df0fca2a4 100644 --- a/src/chrome/internal/stepping/features/asyncStepping.ts +++ b/src/chrome/internal/stepping/features/asyncStepping.ts @@ -1,10 +1,11 @@ import { IComponent } from '../../features/feature'; -import { PausedEvent } from '../../../target/events'; import { InformationAboutPausedProvider, ResumeCommonLogic } from '../../features/takeProperActionOnPausedEvent'; import { VoteRelevance, Vote, Abstained } from '../../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; -import { IDebugeeExecutionControl, IDebugeeStepping } from '../../../target/controlDebugeeExecution'; import { TYPES } from '../../../dependencyInjection.ts/types'; +import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; +import { IDebugeeExecutionController } from '../../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; +import { IDebugeeSteppingController } from '../../../cdtpDebuggee/features/CDTPDebugeeSteppingController'; export interface EventsConsumedByAsyncStepping { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; @@ -13,7 +14,7 @@ export interface EventsConsumedByAsyncStepping { export class PausedBecauseAsyncCallWasScheduled extends ResumeCommonLogic { public readonly relevance = VoteRelevance.FallbackVote; - constructor(protected _debugeeExecutionControl: IDebugeeExecutionControl) { + constructor(protected _debugeeExecutionControl: IDebugeeExecutionController) { super(); } } @@ -35,6 +36,6 @@ export class AsyncStepping implements IComponent { constructor( @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByAsyncStepping, - @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionControl, - @inject(TYPES.IDebugeeStepping) private readonly _debugeeStepping: IDebugeeStepping) { } + @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionController, + @inject(TYPES.IDebugeeSteppingController) private readonly _debugeeStepping: IDebugeeSteppingController) { } } \ No newline at end of file diff --git a/src/chrome/internal/stepping/features/syncStepping.ts b/src/chrome/internal/stepping/features/syncStepping.ts index 2d06e6b3f..18f41cad3 100644 --- a/src/chrome/internal/stepping/features/syncStepping.ts +++ b/src/chrome/internal/stepping/features/syncStepping.ts @@ -3,11 +3,12 @@ import { ICallFrame } from '../../stackTraces/callFrame'; import { IScript } from '../../scripts/script'; import { InformationAboutPausedProvider, } from '../../features/takeProperActionOnPausedEvent'; import { IComponent } from '../../features/feature'; -import { PausedEvent } from '../../../target/events'; import { Abstained, Vote } from '../../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; -import { IDebugeeStepping, IDebugeeExecutionControl } from '../../../target/controlDebugeeExecution'; +import { IDebugeeExecutionController } from '../../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; import { TYPES } from '../../../dependencyInjection.ts/types'; +import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; +import { IDebugeeSteppingController } from '../../../cdtpDebuggee/features/CDTPDebugeeSteppingController'; type SteppingAction = () => Promise; @@ -72,6 +73,6 @@ export class SyncStepping implements IComponent { constructor( @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: SyncSteppingDependencies, - @inject(TYPES.IDebugeeStepping) private readonly _debugeeStepping: IDebugeeStepping, - @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionControl) { } + @inject(TYPES.IDebugeeSteppingController) private readonly _debugeeStepping: IDebugeeSteppingController, + @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionController) { } } \ No newline at end of file diff --git a/src/chrome/stoppedEvent.ts b/src/chrome/stoppedEvent.ts index 058b8ccf6..76d67d65c 100644 --- a/src/chrome/stoppedEvent.ts +++ b/src/chrome/stoppedEvent.ts @@ -5,7 +5,7 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { StoppedEvent } from 'vscode-debugadapter'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; import * as utils from '../utils'; import * as nls from 'vscode-nls'; @@ -14,7 +14,7 @@ const localize = nls.loadMessageBundle(); export type ReasonType = 'step' | 'breakpoint' | 'exception' | 'pause' | 'entry' | 'debugger_statement' | 'frame_entry' | 'promise_rejection'; export class StoppedEvent2 extends StoppedEvent { - constructor(reason: ReasonType, threadId: number, exception?: Crdp.Runtime.RemoteObject) { + constructor(reason: ReasonType, threadId: number, exception?: CDTP.Runtime.RemoteObject) { const exceptionText = exception && exception.description && utils.firstLine(exception.description); super(reason, threadId, exceptionText); diff --git a/src/chrome/target/addSourceUriToExpression.ts b/src/chrome/target/addSourceUriToExpression.ts deleted file mode 100644 index 35b537472..000000000 --- a/src/chrome/target/addSourceUriToExpression.ts +++ /dev/null @@ -1,15 +0,0 @@ -export class AddSourceUriToExpession { - private nextEvaluateScriptId = 0; - - public addURLIfMissing(expression: string): string { - const sourceUrlPrefix = '\n//# sourceURL='; - - if (expression.indexOf(sourceUrlPrefix) < 0) { - expression += `${sourceUrlPrefix}/${this._prefix}/id=${this.nextEvaluateScriptId++}`; - } - - return expression; - } - - constructor(private readonly _prefix: string) {} -} \ No newline at end of file diff --git a/src/chrome/target/breakpointIdRegistry.ts b/src/chrome/target/breakpointIdRegistry.ts deleted file mode 100644 index dacc7503e..000000000 --- a/src/chrome/target/breakpointIdRegistry.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { BidirectionalMap } from '../collections/bidirectionalMap'; -import { BPRecipie, IBPRecipie } from '../internal/breakpoints/bpRecipie'; -import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; -import { Crdp } from '../..'; -import { injectable } from 'inversify'; - -@injectable() -export class BreakpointIdRegistry { - // TODO DIEGO: Figure out how to handle if two breakpoint rules set a breakpoint in the same location so it ends up being the same breakpoint id - private readonly _recipieToBreakpointId = new BidirectionalMap, Crdp.Debugger.BreakpointId>(); - - public registerRecipie(cdtpBreakpointId: Crdp.Debugger.BreakpointId, bpRecipie: BPRecipie): void { - this._recipieToBreakpointId.set(bpRecipie.unmappedBpRecipie, cdtpBreakpointId); - } - - public unregisterRecipie(bpRecipie: BPRecipie): void { - this._recipieToBreakpointId.deleteByLeft(bpRecipie.unmappedBpRecipie); - } - - public getBreakpointId(bpRecipie: BPRecipie): Crdp.Debugger.BreakpointId { - return this._recipieToBreakpointId.getByLeft(bpRecipie); - } - - public getRecipieByBreakpointId(cdtpBreakpointId: Crdp.Debugger.BreakpointId): IBPRecipie { - return this._recipieToBreakpointId.getByRight(cdtpBreakpointId); - } - - public toString(): string { - return `Breakpoint IDs: ${this._recipieToBreakpointId}`; - } -} diff --git a/src/chrome/target/callFrameRegistry.ts b/src/chrome/target/callFrameRegistry.ts deleted file mode 100644 index bf7425b5c..000000000 --- a/src/chrome/target/callFrameRegistry.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IScript } from '../internal/scripts/script'; -import { Crdp } from '../..'; -import { ValidatedMap } from '../collections/validatedMap'; -import { ICallFrame, ScriptOrLoadedSource } from '../internal/stackTraces/callFrame'; -import { injectable } from 'inversify'; - -@injectable() -export class CallFrameRegistry { - private readonly _callFrameToId = new ValidatedMap, Crdp.Debugger.CallFrameId>(); - - public getFrameId(frame: ICallFrame): Crdp.Debugger.CallFrameId { - return this._callFrameToId.get(frame.unmappedCallFrame); - } -} \ No newline at end of file diff --git a/src/chrome/target/cdtpDebugger.ts b/src/chrome/target/cdtpDebugger.ts deleted file mode 100644 index 10c2025b0..000000000 --- a/src/chrome/target/cdtpDebugger.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; -import { Crdp } from '../..'; -import { ScriptParsedEvent } from './events'; -import { IScript } from '../internal/scripts/script'; -import { PauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions } from '../internal/exceptions/strategies'; -import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; -import { inject, injectable } from 'inversify'; -import { TYPES } from '../dependencyInjection.ts/types'; - -export type ScriptParsedListener = (params: ScriptParsedEvent) => void; - -export interface IPauseOnExceptions { - setPauseOnExceptions(strategy: PauseOnExceptionsStrategy): Promise; -} - -export interface IAsyncDebuggingConfiguration { - setAsyncCallStackDepth(maxDepth: Crdp.integer): Promise; -} - -export interface IScriptSources { - getScriptSource(script: IScript): Promise; -} - -@injectable() -export class CDTPDebugger extends CDTPEventsEmitterDiagnosticsModule implements IPauseOnExceptions, IScriptSources, IAsyncDebuggingConfiguration { - protected readonly api = this._protocolApi.Debugger; - - public setAsyncCallStackDepth(maxDepth: Crdp.integer): Promise { - return this.api.setAsyncCallStackDepth({ maxDepth }); - } - - public setBlackboxedRanges(script: IScript, positions: Crdp.Debugger.ScriptPosition[]): Promise { - return this.api.setBlackboxedRanges({ scriptId: this._scriptsRegistry.getCrdpId(script), positions: positions }); - } - - public setBlackboxPatterns(params: Crdp.Debugger.SetBlackboxPatternsRequest): Promise { - return this.api.setBlackboxPatterns(params); - } - - public setPauseOnExceptions(strategy: PauseOnExceptionsStrategy): Promise { - let state: 'none' | 'uncaught' | 'all'; - - if (strategy instanceof PauseOnAllExceptions) { - state = 'all'; - } else if (strategy instanceof PauseOnUnhandledExceptions) { - state = 'uncaught'; - } else if (strategy instanceof DoNotPauseOnAnyExceptions) { - state = 'none'; - } else { - throw new Error(`Can't pause on exception using an unknown strategy ${strategy}`); - } - - return this.api.setPauseOnExceptions({ state }); - } - - public async getScriptSource(script: IScript): Promise { - return (await this.api.getScriptSource({ scriptId: this._scriptsRegistry.getCrdpId(script) })).scriptSource; - } - - constructor( - @inject(TYPES.CDTPClient) private readonly _protocolApi: Crdp.ProtocolApi, - @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry) { - super(); - } -} diff --git a/src/chrome/target/cdtpDebuggerEventsProvider.ts b/src/chrome/target/cdtpDebuggerEventsProvider.ts deleted file mode 100644 index d2d9a9ed3..000000000 --- a/src/chrome/target/cdtpDebuggerEventsProvider.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; -import { asyncMap } from '../collections/async'; -import { PausedEvent } from './events'; -import { CDTPStackTraceParser } from './cdtpStackTraceParser'; -import { adaptToSinglIntoToMulti } from '../../utils'; -import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; -import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; -import { BreakpointIdRegistry } from './breakpointIdRegistry'; -import { ScriptCallFrame, ICallFrame, CodeFlowFrame } from '../internal/stackTraces/callFrame'; -import { asyncUndefinedOnFailure } from '../utils/failures'; -import { CDTPLocationParser } from './cdtpLocationParser'; -import { Scope } from '../internal/stackTraces/scopes'; -import { IScript } from '../internal/scripts/script'; -import { injectable, inject } from 'inversify'; -import { TYPES } from '../dependencyInjection.ts/types'; -import { Crdp } from '../..'; - -export interface ICDTPDebuggerEventsProvider { - onPaused(listener: (event: PausedEvent) => void): void; - onResumed(listener: () => void): void; -} - -@injectable() -export class CDTPDebuggerEventsProvider extends CDTPEventsEmitterDiagnosticsModule implements ICDTPDebuggerEventsProvider { - protected readonly api = this._protocolApi.Debugger; - - private getBPsFromIDs = adaptToSinglIntoToMulti(this, this.getBPFromID); - - public readonly onPaused = this.addApiListener('paused', async (params: Crdp.Debugger.PausedEvent) => { - if (params.callFrames.length === 0) { - throw new Error(`Expected a pause event to have at least a single call frame: ${JSON.stringify(params)}`); - } - - const callFrames = await asyncMap(params.callFrames, (callFrame, index) => this.toCallFrame(index, callFrame)); - return new PausedEvent(callFrames, params.reason, params.data, - this.getBPsFromIDs(params.hitBreakpoints), - params.asyncStackTrace && await this._crdpToInternal.toStackTraceCodeFlow(params.asyncStackTrace), - params.asyncStackTraceId, params.asyncCallStackTraceId); - }); - - public readonly onResumed = this.addApiListener('resumed', (params: void) => params); - - public readonly onScriptFailedToParse = this.addApiListener('resumed', (params: Crdp.Debugger.ScriptFailedToParseEvent) => params); - - private getBPFromID(hitBreakpoint: Crdp.Debugger.BreakpointId): IBPRecipie { - return this._breakpointIdRegistry.getRecipieByBreakpointId(hitBreakpoint); - } - - private async toCallFrame(index: number, callFrame: Crdp.Debugger.CallFrame): Promise> { - return new ScriptCallFrame(await this.DebuggertoCallFrameCodeFlow(index, callFrame), - await Promise.all(callFrame.scopeChain.map(scope => this.toScope(scope))), - callFrame.this, callFrame.returnValue); - } - - private DebuggertoCallFrameCodeFlow(index: number, callFrame: Crdp.Debugger.CallFrame): Promise> { - return this._crdpToInternal.configurableToCallFrameCodeFlow(index, callFrame, callFrame.location); - } - - private async toScope(scope: Crdp.Debugger.Scope): Promise { - return { - type: scope.type, - object: scope.object, - name: scope.name, - // TODO FILE BUG: Chrome sometimes returns line -1 when the doc says it's 0 based - startLocation: await asyncUndefinedOnFailure(async () => scope.startLocation && await this._cdtpLocationParser.getPositionInScript(scope.startLocation)), - endLocation: await asyncUndefinedOnFailure(async () => scope.endLocation && await this._cdtpLocationParser.getPositionInScript(scope.endLocation)) - }; - } - - constructor( - @inject(TYPES.CDTPClient) private readonly _protocolApi: Crdp.ProtocolApi, - @inject(TYPES.CDTPStackTraceParser) private readonly _crdpToInternal: CDTPStackTraceParser, - @inject(TYPES.CDTPLocationParser) private readonly _cdtpLocationParser: CDTPLocationParser, - @inject(TYPES.BreakpointIdRegistry) private readonly _breakpointIdRegistry: BreakpointIdRegistry) { - super(); - } -} \ No newline at end of file diff --git a/src/chrome/target/cdtpDiagnostics.ts b/src/chrome/target/cdtpDiagnostics.ts deleted file mode 100644 index 7e02eb7fb..000000000 --- a/src/chrome/target/cdtpDiagnostics.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Crdp } from '../..'; -import { CDTPStackTraceParser } from './cdtpStackTraceParser'; -import { CDTPDebugger } from './cdtpDebugger'; -import { CDTPConsole, CDTPSchema, CDTPDOMDebugger, CDTPPage, CDTPNetwork, CDTPBrowser, CDTPOverlay, CDTPLog } from './cdtpSmallerModules'; -import { CDTPRuntime } from './cdtpRuntime'; -import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; -import { injectable, inject } from 'inversify'; -import { IComponent } from '../internal/features/feature'; -import { CDTPDebuggerEventsProvider } from './cdtpDebuggerEventsProvider'; -import { CDTPLocationParser } from './cdtpLocationParser'; -import { ExceptionThrownEventProvider } from './exceptionThrownEventProvider'; -import { TYPES } from '../dependencyInjection.ts/types'; - -// TODO: Remove this class and use dependency injection/inversify to initialize all this -@injectable() -export class CDTPDiagnostics implements IComponent { - public Debugger: CDTPDebugger; - public ExceptionThrownEventProvider: ExceptionThrownEventProvider; - public Console: CDTPConsole; - public Runtime: CDTPRuntime; - public Schema: CDTPSchema; - public DOMDebugger: CDTPDOMDebugger; - public Page: CDTPPage; - public Network: CDTPNetwork; - public Browser: CDTPBrowser; - public Overlay: CDTPOverlay; - public Log: CDTPLog; - - public async install(): Promise { - // Enable domains so we can use the handlers - await Promise.all([ - this.Debugger.enable(), - this.Runtime.enable().then(() => this.Runtime.runIfWaitingForDebugger()), - this.Log.enable().catch(_exception => { }) // Not supported by all runtimes - ]); - } - - constructor( - @inject(TYPES.CDTPClient) private _api: Crdp.ProtocolApi, - @inject(TYPES.CDTPScriptsRegistry) protected scriptsRegistry: CDTPScriptsRegistry, - @inject(TYPES.CDTPLocationParser) protected cdtpLocationParser: CDTPLocationParser, - @inject(TYPES.CDTPStackTraceParser) protected cdtpStackTraceParser: CDTPStackTraceParser, - @inject(TYPES.ICDTPDebuggerEventsProvider) public debuggerEvents: CDTPDebuggerEventsProvider, - ) { - this.Debugger = new CDTPDebugger(this._api, scriptsRegistry); - this.ExceptionThrownEventProvider = new ExceptionThrownEventProvider(this._api, cdtpStackTraceParser, scriptsRegistry); - this.Console = new CDTPConsole(this._api.Console); - this.Runtime = new CDTPRuntime(this._api.Runtime, cdtpStackTraceParser); - this.Schema = new CDTPSchema(this._api.Schema); - this.DOMDebugger = new CDTPDOMDebugger(this._api); - this.Page = new CDTPPage(this._api); - this.Network = new CDTPNetwork(this._api.Network); - this.Browser = new CDTPBrowser(this._api); - this.Overlay = new CDTPOverlay(this._api.Overlay); - this.Log = new CDTPLog(this._api.Log, cdtpStackTraceParser); - } -} diff --git a/src/chrome/target/cdtpLocationParser.ts b/src/chrome/target/cdtpLocationParser.ts deleted file mode 100644 index 9bce12208..000000000 --- a/src/chrome/target/cdtpLocationParser.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Coordinates, LocationInScript } from '../internal/locations/location'; -import { createColumnNumber, createLineNumber } from '../internal/locations/subtypes'; -import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; -import { injectable, inject } from 'inversify'; -import { TYPES } from '../dependencyInjection.ts/types'; -import { Crdp } from '../..'; - -interface HasLocation { - lineNumber: number; - columnNumber?: number; -} - -interface HasScript { - scriptId: Crdp.Runtime.ScriptId; -} - -export interface HasScriptLocation extends HasLocation, HasScript { } - -@injectable() -export class CDTPLocationParser { - public async getPositionInScript(crdpScriptLocation: HasScriptLocation): Promise { - return new LocationInScript(await this._scriptsRegistry.getScriptById(crdpScriptLocation.scriptId), - this.getLocation(crdpScriptLocation)); - } - - private getLocation(crdpLocation: HasLocation): Coordinates { - return new Coordinates(createLineNumber(crdpLocation.lineNumber), createColumnNumber(crdpLocation.columnNumber)); - } - - constructor( - @inject(TYPES.CDTPScriptsRegistry) private _scriptsRegistry: CDTPScriptsRegistry) { } -} diff --git a/src/chrome/target/cdtpOnScriptParsedEventProvider.ts b/src/chrome/target/cdtpOnScriptParsedEventProvider.ts deleted file mode 100644 index 89de911aa..000000000 --- a/src/chrome/target/cdtpOnScriptParsedEventProvider.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { Crdp, parseResourceIdentifier, BasePathTransformer, BaseSourceMapTransformer } from '../..'; -import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; -import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; -import { IScript, Script } from '../internal/scripts/script'; -import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; -import { SourcesMapper, NoSourceMapping } from '../internal/scripts/sourcesMapper'; -import { ResourceName } from '../internal/sources/resourceIdentifier'; -import { ScriptParsedEvent } from './events'; -import { TYPES } from '../dependencyInjection.ts/types'; -import { CDTPStackTraceParser } from './cdtpStackTraceParser'; -import { inject } from 'inversify'; - -export interface IScriptParsedProvider { - onScriptParsed(listener: (event: ScriptParsedEvent) => void): void; -} - -export class CDTPOnScriptParsedEventProvider extends CDTPEventsEmitterDiagnosticsModule implements IScriptParsedProvider { - protected readonly api = this._protocolApi.Debugger; - - public onScriptParsed = this.addApiListener('scriptParsed', async (params: Crdp.Debugger.ScriptParsedEvent) => { - await this.createAndRegisterScript(params); - - return await this.toScriptParsedEvent(params); - }); - - private async createAndRegisterScript(params: Crdp.Debugger.ScriptParsedEvent): Promise { - // The stack trace and hash can be large and the DA doesn't need it. - delete params.stackTrace; - delete params.hash; - - const executionContext = this._scriptsRegistry.getExecutionContextById(params.executionContextId); - - const script = await this._scriptsRegistry.registerNewScript(params.scriptId, async () => { - if (params.url !== undefined && params.url !== '') { - const runtimeSourceLocation = parseResourceIdentifier(params.url as CDTPScriptUrl); - const developmentSourceLocation = await this._pathTransformer.scriptParsed(runtimeSourceLocation); - const sourceMap = await this._sourceMapTransformer.scriptParsed(runtimeSourceLocation.canonicalized, params.sourceMapURL); - const sourceMapper = sourceMap - ? new SourcesMapper(sourceMap) - : new NoSourceMapping(); - - const runtimeScript = Script.create(executionContext, runtimeSourceLocation, developmentSourceLocation, sourceMapper); - return runtimeScript; - } else { - const sourceMap = await this._sourceMapTransformer.scriptParsed('', params.sourceMapURL); - const sourceMapper = sourceMap - ? new SourcesMapper(sourceMap) - : new NoSourceMapping(); - const runtimeScript = Script.createEval(executionContext, new ResourceName(params.scriptId as CDTPScriptUrl), sourceMapper); - return runtimeScript; - } - }); - - return script; - } - - private async toScriptParsedEvent(params: Crdp.Debugger.ScriptParsedEvent): Promise { - return { - script: await this._scriptsRegistry.getScriptById(params.scriptId), - url: params.url, - startLine: params.startLine, - startColumn: params.startColumn, - endLine: params.endLine, - endColumn: params.endColumn, - executionContextId: params.executionContextId, - hash: params.hash, - executionContextAuxData: params.executionContextAuxData, - isLiveEdit: params.isLiveEdit, - sourceMapURL: params.sourceMapURL, - hasSourceURL: params.hasSourceURL, - isModule: params.isModule, - length: params.length, - stackTrace: params.stackTrace && await this._crdpToInternal.toStackTraceCodeFlow(params.stackTrace) - }; - } - - constructor( - @inject(TYPES.CDTPClient) private readonly _protocolApi: Crdp.ProtocolApi, - @inject(TYPES.CDTPStackTraceParser) private readonly _crdpToInternal: CDTPStackTraceParser, - @inject(TYPES.BasePathTransformer) private readonly _pathTransformer: BasePathTransformer, - @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, - @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry) { - super(); - } -} \ No newline at end of file diff --git a/src/chrome/target/cdtpRuntime.ts b/src/chrome/target/cdtpRuntime.ts deleted file mode 100644 index e8ef6b61d..000000000 --- a/src/chrome/target/cdtpRuntime.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Crdp } from '../..'; -import { CDTPEventsEmitterDiagnosticsModule, IEnableableApi } from './cdtpDiagnosticsModule'; -import { CDTPStackTraceParser } from './cdtpStackTraceParser'; - -export interface ICDTPRuntime extends IEnableableApi {} - -export class CDTPRuntime extends CDTPEventsEmitterDiagnosticsModule implements ICDTPRuntime { - public readonly onConsoleAPICalled = this.addApiListener('consoleAPICalled', async (params: Crdp.Runtime.ConsoleAPICalledEvent) => - ({ - args: params.args, context: params.context, executionContextId: params.executionContextId, - stackTrace: params.stackTrace && await this._crdpToInternal.toStackTraceCodeFlow(params.stackTrace), timestamp: params.timestamp, type: params.type - })); - - public async runIfWaitingForDebugger(): Promise { - // This is a CDP version difference which will have to be handled more elegantly with others later... - // For now, we need to send both messages and ignore a failing one. - try { - await Promise.all([ - this.api.runIfWaitingForDebugger(), - (this.api as any).run() - ]); - } catch (exception) { - // Ignore the failed call - } - } - - constructor( - protected readonly api: Crdp.RuntimeApi, - private readonly _crdpToInternal: CDTPStackTraceParser) { - super(); - } -} diff --git a/src/chrome/target/cdtpScriptsRegistry.ts b/src/chrome/target/cdtpScriptsRegistry.ts deleted file mode 100644 index 0bc7b7cb8..000000000 --- a/src/chrome/target/cdtpScriptsRegistry.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Crdp } from '../..'; -import { IScript } from '../internal/scripts/script'; -import { newResourceIdentifierMap, IResourceIdentifier } from '../internal/sources/resourceIdentifier'; -import { ValidatedMap } from '../collections/validatedMap'; -import { ExecutionContext, IExecutionContext } from '../internal/scripts/executionContext'; -import { injectable } from 'inversify'; - -@injectable() -export class CDTPScriptsRegistry { - private readonly _idToExecutionContext = new ValidatedMap(); - private readonly _scripts = new CDTPCurrentGeneration(); - - public markExecutionContextAsDestroyed(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { - const executionContext = this._idToExecutionContext.get(executionContextId); - executionContext.markAsDestroyed(); - return executionContext; - } - - public registerExecutionContext(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { - const executionContext = new ExecutionContext(); - this._idToExecutionContext.set(executionContextId, executionContext); - return executionContext; - } - - public getExecutionContextById(executionContextId: Crdp.Runtime.ExecutionContextId): IExecutionContext { - return this._idToExecutionContext.get(executionContextId); - } - - public registerNewScript(scriptId: Crdp.Runtime.ScriptId, obtainScript: () => Promise): Promise { - return this._scripts.registerNewScript(scriptId, obtainScript); - } - - public getCrdpId(script: IScript): any { - return this._scripts.getCdtpId(script); - } - - public getScriptById(runtimeScriptCrdpId: Crdp.Runtime.ScriptId): Promise { - return this._scripts.scriptById(runtimeScriptCrdpId); - } - - public getScriptsByPath(nameOrLocation: IResourceIdentifier): IScript[] { - return this._scripts.getScriptByPath(nameOrLocation); - } - - public getAllScripts(): IterableIterator> { - return this._scripts.getAllScripts(); - } - - constructor() { - } -} - -export class CDTPCurrentGeneration { - private readonly _cdtpIdByScript = new ValidatedMap>(); - private readonly _scriptByCdtpId = new ValidatedMap(); - private readonly _scriptByPath = newResourceIdentifierMap(); - - private createScriptInitialConfiguration(scriptId: Crdp.Runtime.ScriptId, script: IScript): void { - this._scriptByCdtpId.set(script, scriptId); - - let scriptsWithSamePath = this._scriptByPath.getOrAdd(script.runtimeSource.identifier, () => []); - scriptsWithSamePath.push(script); - } - - public async registerNewScript(scriptId: Crdp.Runtime.ScriptId, obtainScript: () => Promise): Promise { - const scriptWithConfigurationPromise = obtainScript().then(script => { - /** - * We need to configure the script here, so we can guarantee that clients who try to use a script will get - * blocked until the script is created, and all the initial configuration is done, so they can use APIs to get - * the script id, search by URL, etc... - */ - this.createScriptInitialConfiguration(scriptId, script); - return script; - }); - - this._cdtpIdByScript.set(scriptId, scriptWithConfigurationPromise); - - return await scriptWithConfigurationPromise; - } - - public getCdtpId(script: IScript): Crdp.Runtime.ScriptId { - const scriptId = this._scriptByCdtpId.get(script); - - if (script === undefined) { - throw new Error(`Couldn't find a CRDP id for script ${script}`); - } - - return scriptId; - } - - public scriptById(runtimeScriptCrdpId: string): Promise { - return this._cdtpIdByScript.get(runtimeScriptCrdpId); - } - - public getScriptByPath(path: IResourceIdentifier): IScript[] { - const runtimeScript = this._scriptByPath.tryGetting(path); - return runtimeScript || []; - } - - public getAllScripts(): IterableIterator> { - return this._cdtpIdByScript.values(); - } -} diff --git a/src/chrome/target/cdtpSmallerModules.ts b/src/chrome/target/cdtpSmallerModules.ts deleted file mode 100644 index 14b481c9c..000000000 --- a/src/chrome/target/cdtpSmallerModules.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { CDTPEnableableDiagnosticsModule, CDTPEventsEmitterDiagnosticsModule, IEnableableApi } from './cdtpDiagnosticsModule'; -import { Crdp } from '../..'; -import { CDTPStackTraceParser } from './cdtpStackTraceParser'; -import { injectable, inject } from 'inversify'; -import { LogEntry } from './events'; -import { TYPES } from '../dependencyInjection.ts/types'; - -export class CDTPConsole extends CDTPEventsEmitterDiagnosticsModule { - public readonly onMessageAdded = this.addApiListener('messageAdded', (params: Crdp.Console.MessageAddedEvent) => params); - - constructor(protected api: Crdp.ConsoleApi) { - super(); - } -} - -export class CDTPSchema { - public async getDomains(): Promise { - return (await this.api.getDomains()).domains; - } - - constructor(protected api: Crdp.SchemaApi) {} -} - -export interface IDOMInstrumentationBreakpoints { - setInstrumentationBreakpoint(params: Crdp.DOMDebugger.SetInstrumentationBreakpointRequest): Promise; - removeInstrumentationBreakpoint(params: Crdp.DOMDebugger.SetInstrumentationBreakpointRequest): Promise; -} - -@injectable() -export class CDTPDOMDebugger implements IDOMInstrumentationBreakpoints { - protected api = this._protocolApi.DOMDebugger; - - public setInstrumentationBreakpoint(params: Crdp.DOMDebugger.SetInstrumentationBreakpointRequest): Promise { - return this.api.setInstrumentationBreakpoint(params); - } - - public removeInstrumentationBreakpoint(params: Crdp.DOMDebugger.SetInstrumentationBreakpointRequest): Promise { - return this.api.removeInstrumentationBreakpoint(params); - } - - constructor(@inject(TYPES.CDTPClient) protected _protocolApi: Crdp.ProtocolApi) {} -} - -export interface IBrowserNavigation extends IEnableableApi { - navigate(params: Crdp.Page.NavigateRequest): Promise; - reload(params: Crdp.Page.ReloadRequest): Promise; - onFrameNavigated(listener: (params: Crdp.Page.FrameNavigatedEvent) => void): void; -} - -@injectable() -export class CDTPPage extends CDTPEventsEmitterDiagnosticsModule implements IBrowserNavigation { - protected api = this._protocolApi.Page; - - public readonly onFrameNavigated = this.addApiListener('frameNavigated', (params: Crdp.Page.FrameNavigatedEvent) => params); - - public navigate(params: Crdp.Page.NavigateRequest): Promise { - return this.api.navigate(params); - } - - public reload(params: Crdp.Page.ReloadRequest): Promise { - return this.api.reload(params); - } - - constructor(@inject(TYPES.CDTPClient) protected _protocolApi: Crdp.ProtocolApi) { - super(); - } -} - -export interface INetworkCacheConfiguration { - setCacheDisabled(params: Crdp.Network.SetCacheDisabledRequest): Promise; -} - -export class CDTPNetwork extends CDTPEventsEmitterDiagnosticsModule implements INetworkCacheConfiguration { - public disable(): Promise { - return this.api.disable(); - } - - public setCacheDisabled(params: Crdp.Network.SetCacheDisabledRequest): Promise { - return this.api.setCacheDisabled(params); - } - - constructor(protected api: Crdp.NetworkApi) { - super(); - } -} - -export interface IDebugeeVersionProvider { - getVersion(): Promise; -} - -@injectable() -export class CDTPBrowser implements IDebugeeVersionProvider { - protected api = this._protocolApi.Browser; - - public getVersion(): Promise { - return this.api.getVersion(); - } - - constructor(@inject(TYPES.CDTPClient) protected _protocolApi: Crdp.ProtocolApi) { - } -} - -export interface IPausedOverlay { - setPausedInDebuggerMessage(params: Crdp.Overlay.SetPausedInDebuggerMessageRequest): Promise; -} - -export class CDTPOverlay extends CDTPEnableableDiagnosticsModule implements IPausedOverlay { - public setPausedInDebuggerMessage(params: Crdp.Overlay.SetPausedInDebuggerMessageRequest): Promise { - return this.api.setPausedInDebuggerMessage(params); - } - - constructor(protected api: Crdp.OverlayApi) { - super(); - } -} - -export class CDTPLog extends CDTPEventsEmitterDiagnosticsModule { - public readonly onEntryAdded = this.addApiListener('entryAdded', async (params: Crdp.Log.EntryAddedEvent) => await this.toLogEntry(params.entry)); - - private async toLogEntry(entry: Crdp.Log.LogEntry): Promise { - return { - source: entry.source, - level: entry.level, - text: entry.text, - timestamp: entry.timestamp, - url: entry.url, - lineNumber: entry.lineNumber, - stackTrace: entry.stackTrace && await this._crdpToInternal.toStackTraceCodeFlow(entry.stackTrace), - networkRequestId: entry.networkRequestId, - workerId: entry.workerId, - args: entry.args, - }; - } - - constructor(protected readonly api: Crdp.LogApi, private readonly _crdpToInternal: CDTPStackTraceParser) { - super(); - } -} diff --git a/src/chrome/target/cdtpStackTraceParser.ts b/src/chrome/target/cdtpStackTraceParser.ts deleted file mode 100644 index 86b69b34a..000000000 --- a/src/chrome/target/cdtpStackTraceParser.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Crdp } from '../..'; -import { IScript, } from '../internal/scripts/script'; -import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; -import { CodeFlowStackTrace } from '../internal/stackTraces/stackTrace'; -import { CodeFlowFrame } from '../internal/stackTraces/callFrame'; -import { createCallFrameName } from '../internal/stackTraces/callFrameName'; -import { IResourceIdentifier } from '../internal/sources/resourceIdentifier'; -import { CDTPLocationParser, HasScriptLocation } from './cdtpLocationParser'; -import { injectable, inject } from 'inversify'; -import { TYPES } from '../dependencyInjection.ts/types'; -import { URLRegexp } from '../internal/locations/subtypes'; - -export type CDTPResource = IScript | URLRegexp | IResourceIdentifier; - -@injectable() -export class CDTPStackTraceParser { - public async toStackTraceCodeFlow(stackTrace: Crdp.Runtime.StackTrace): Promise> { - return { - codeFlowFrames: await Promise.all(stackTrace.callFrames.map((callFrame, index) => this.RuntimetoCallFrameCodeFlow(index, callFrame))), - description: stackTrace.description, parent: stackTrace.parent && await this.toStackTraceCodeFlow(stackTrace.parent) - }; - } - - private RuntimetoCallFrameCodeFlow(index: number, callFrame: Crdp.Runtime.CallFrame): Promise> { - return this.configurableToCallFrameCodeFlow(index, callFrame, callFrame); - } - - public async configurableToCallFrameCodeFlow(index: number, callFrame: Crdp.Runtime.CallFrame | Crdp.Debugger.CallFrame, location: HasScriptLocation): Promise> { - const scriptLocation = await this._cdtpLocationParser.getPositionInScript(location); - const name = createCallFrameName(scriptLocation.script, callFrame.functionName); - return new CodeFlowFrame(index, name, scriptLocation); - } - - constructor( - @inject(TYPES.CDTPLocationParser) private readonly _cdtpLocationParser: CDTPLocationParser) { } -} diff --git a/src/chrome/target/cdtpTargetBreakpoints.ts b/src/chrome/target/cdtpTargetBreakpoints.ts deleted file mode 100644 index da2c4888c..000000000 --- a/src/chrome/target/cdtpTargetBreakpoints.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp, BPRecipie, IBPRecipie } from '../internal/breakpoints/bpRecipie'; -import { AlwaysBreak, ConditionalBreak } from '../internal/breakpoints/bpActionWhenHit'; -import { BreakpointInScript, BreakpointInUrl, BreakpointInUrlRegexp, Breakpoint } from '../internal/breakpoints/breakpoint'; -import { RangeInScript } from '../internal/locations/rangeInScript'; -import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; -import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; -import { Crdp } from '../..'; -import { BreakpointIdRegistry } from './breakpointIdRegistry'; -import { TYPES } from '../dependencyInjection.ts/types'; -import { asyncMap } from '../collections/async'; -import { IScript } from '../internal/scripts/script'; -import { URL } from '../internal/sources/resourceIdentifier'; -import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; -import { CDTPLocationParser } from './cdtpLocationParser'; -import { inject, injectable } from 'inversify'; -import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; -import { URLRegexp } from '../internal/locations/subtypes'; - -export interface ITargetBreakpoints { - setBreakpoint(bpRecipie: BPRecipieInScript): Promise; - setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise; - setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise; - getPossibleBreakpoints(rangeInScript: RangeInScript): Promise; - removeBreakpoint(bpRecipie: BPRecipie): Promise; -} - -interface BreakpointClass { - new(recipie: BPRecipie, actualLocation: LocationInScript): Breakpoint; -} - -@injectable() -export class CDTPTargetBreakpoints extends CDTPEventsEmitterDiagnosticsModule implements ITargetBreakpoints { - protected readonly api: Crdp.DebuggerApi = this.protocolApi.Debugger; - - public readonly onBreakpointResolved = this.addApiListener('breakpointResolved', async (params: Crdp.Debugger.BreakpointResolvedEvent) => { - const bpRecipie = this._breakpointIdRegistry.getRecipieByBreakpointId(params.breakpointId); - const breakpoint = new Breakpoint(bpRecipie, - await this.toLocationInScript(params.location)); - return breakpoint; - }); - - public async setBreakpoint(bpRecipie: BPRecipieInScript): Promise { - const condition = this.getBPRecipieCondition(bpRecipie); - - const response = await this.api.setBreakpoint({ location: this.toCrdpLocation(bpRecipie.location), condition }); - - // We need to call registerRecipie sync with the response, before any awaits so if we get an event witha breakpointId we'll be able to resolve it properly - this._breakpointIdRegistry.registerRecipie(response.breakpointId, bpRecipie); - - return this.toBreakpointInScript(bpRecipie, response); - } - - public async setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise { - const condition = this.getBPRecipieCondition(bpRecipie); - const url = bpRecipie.location.url.textRepresentation; - const location = bpRecipie.location.coordinates; - - const response = await this.api.setBreakpointByUrl({ url, lineNumber: location.lineNumber, columnNumber: location.columnNumber, condition }); - - // We need to call registerRecipie sync with the response, before any awaits so if we get an event witha breakpointId we'll be able to resolve it properly - this._breakpointIdRegistry.registerRecipie(response.breakpointId, bpRecipie); - - return Promise.all(response.locations.map(cdtpLocation => this.toBreakpointInUrl(bpRecipie, cdtpLocation))); - } - - public async setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise { - const condition = this.getBPRecipieCondition(bpRecipie); - const urlRegex = bpRecipie.location.urlRegexp; - const location = bpRecipie.location.coordinates; - - const response = await this.api.setBreakpointByUrl({ urlRegex, lineNumber: location.lineNumber, columnNumber: location.columnNumber, condition }); - - // We need to call registerRecipie sync with the response, before any awaits so if we get an event witha breakpointId we'll be able to resolve it properly - this._breakpointIdRegistry.registerRecipie(response.breakpointId, bpRecipie); - - return Promise.all(response.locations.map(cdtpLocation => this.toBreakpointInUrlRegexp(bpRecipie, cdtpLocation))); - } - - public async getPossibleBreakpoints(rangeInScript: RangeInScript): Promise { - const response = await this.api.getPossibleBreakpoints({ - start: this.toCrdpLocation(rangeInScript.startInScript), - end: this.toCrdpLocation(rangeInScript.endInScript) - }); - - return asyncMap(response.locations, async location => await this.toLocationInScript(location)); - } - - public async removeBreakpoint(bpRecipie: BPRecipie): Promise { - await this.api.removeBreakpoint({ breakpointId: this._breakpointIdRegistry.getBreakpointId(bpRecipie) }); - this._breakpointIdRegistry.unregisterRecipie(bpRecipie); - } - - private getBPRecipieCondition(bpRecipie: IBPRecipie): string | undefined { - return bpRecipie.bpActionWhenHit.basedOnTypeDo({ - alwaysBreak: () => undefined, - conditionalBreak: conditionalBreak => conditionalBreak.expressionOfWhenToBreak - }); - } - - private async toBreakpointInUrlRegexp(bpRecipie: BPRecipieInUrlRegexp, actualLocation: Crdp.Debugger.Location): Promise { - return this.toBreakpoinInResource(BreakpointInUrlRegexp, bpRecipie, actualLocation); - } - - private async toBreakpoinInResource(classToUse: BreakpointClass, - bpRecipie: BPRecipie, actualLocation: Crdp.Debugger.Location): Promise> { - const breakpoint = new classToUse(bpRecipie, await this.toLocationInScript(actualLocation)); - return breakpoint; - } - - private async toBreakpointInScript(bpRecipie: BPRecipieInScript, params: Crdp.Debugger.SetBreakpointResponse): Promise { - return this.toBreakpoinInResource(BreakpointInScript, bpRecipie, params.actualLocation); - } - - private async toBreakpointInUrl(bpRecipie: BPRecipieInUrl, actualLocation: Crdp.Debugger.Location): Promise { - return this.toBreakpoinInResource>(BreakpointInUrl, bpRecipie, actualLocation); - } - - private toCrdpLocation(location: LocationInScript): Crdp.Debugger.Location { - return { - scriptId: this._scriptsRegistry.getCrdpId(location.script), - lineNumber: location.lineNumber, - columnNumber: location.columnNumber - }; - } - - public toLocationInScript(location: Crdp.Debugger.Location): Promise { - return this._cdtpLocationParser.getPositionInScript(location); - } - - constructor( - @inject(TYPES.CDTPClient) protected readonly protocolApi: Crdp.ProtocolApi, - @inject(TYPES.CDTPLocationParser) private readonly _cdtpLocationParser: CDTPLocationParser, - @inject(TYPES.BreakpointIdRegistry) private readonly _breakpointIdRegistry: BreakpointIdRegistry, - @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry) { - super(); - } -} diff --git a/src/chrome/target/controlDebugeeExecution.ts b/src/chrome/target/controlDebugeeExecution.ts deleted file mode 100644 index 3d7a10a42..000000000 --- a/src/chrome/target/controlDebugeeExecution.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Crdp } from '../..'; - -import { ICallFrame } from '../internal/stackTraces/callFrame'; - -import { IScript } from '../internal/scripts/script'; -import { CallFrameRegistry } from './callFrameRegistry'; -import { injectable, inject } from 'inversify'; -import { TYPES } from '../dependencyInjection.ts/types'; - -export interface IDebugeeExecutionControl { - resume(): Promise; - pause(): Promise; -} - -export interface IDebugeeStepping { - stepOver(): Promise; - stepInto(params: { breakOnAsyncCall: boolean }): Promise; - stepOut(): Promise; - restartFrame(callFrame: ICallFrame): Promise; - pauseOnAsyncCall(params: Crdp.Debugger.PauseOnAsyncCallRequest): Promise; -} - -@injectable() -export class ControlDebugeeExecution implements IDebugeeExecutionControl, IDebugeeStepping { - public pauseOnAsyncCall(params: Crdp.Debugger.PauseOnAsyncCallRequest): Promise { - return this.api.Debugger.pauseOnAsyncCall(params); - } - - public resume(): Promise { - return this.api.Debugger.resume(); - } - - public stepOver(): Promise { - return this.api.Debugger.stepOver(); - } - - public stepInto(params: Crdp.Debugger.StepIntoRequest): Promise { - return this.api.Debugger.stepInto(params); - } - - public stepOut(): Promise { - return this.api.Debugger.stepOut(); - } - - public pause(): Promise { - return this.api.Debugger.pause(); - } - - public restartFrame(frame: ICallFrame): Promise { - return this.api.Debugger.restartFrame({ callFrameId: this._callFrameRegistry.getFrameId(frame) }); - } - - constructor( - @inject(TYPES.CDTPClient) protected readonly api: Crdp.ProtocolApi, - private readonly _callFrameRegistry: CallFrameRegistry) { - } -} \ No newline at end of file diff --git a/src/chrome/target/events.ts b/src/chrome/target/events.ts deleted file mode 100644 index 3d0324b4a..000000000 --- a/src/chrome/target/events.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { IScript } from '../internal/scripts/script'; - -import { Crdp } from '../..'; - -import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; -import { CodeFlowStackTrace } from '../internal/stackTraces/stackTrace'; -import { ICallFrame, ScriptOrLoadedSource } from '../internal/stackTraces/callFrame'; -import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; - -export type integer = number; - -/** - * A new JavaScript Script has been parsed by the debugee and it's about to be executed - */ -export interface ScriptParsedEvent { - readonly script: IScript; - readonly url: string; - readonly startLine: integer; - readonly startColumn: integer; - readonly endLine: integer; - readonly endColumn: integer; - readonly executionContextId: Crdp.Runtime.ExecutionContextId; - readonly hash: string; - readonly executionContextAuxData?: any; - readonly isLiveEdit?: boolean; - readonly sourceMapURL?: string; - readonly hasSourceURL?: boolean; - readonly isModule?: boolean; - readonly length?: integer; - readonly stackTrace?: CodeFlowStackTrace; -} - -export class PausedEvent { - public cloneButWithHitBreakpoints(hitBreakpoints: IBPRecipie[]): PausedEvent { - return new PausedEvent( - this.callFrames, - this.reason, - this.data, - hitBreakpoints, - this.asyncStackTrace, - this.asyncCallStackTraceId, - this.asyncStackTraceId); - } - - constructor( - public readonly callFrames: ICallFrame[], - public readonly reason: ('XHR' | 'DOM' | 'EventListener' | 'exception' | 'assert' | 'debugCommand' | 'promiseRejection' | 'OOM' | 'other' | 'ambiguous'), - public readonly data?: any, - public readonly hitBreakpoints?: IBPRecipie[], // TODO DIEGO: Make this readonly - public readonly asyncStackTrace?: CodeFlowStackTrace, - public readonly asyncStackTraceId?: Crdp.Runtime.StackTraceId, - public readonly asyncCallStackTraceId?: Crdp.Runtime.StackTraceId) { } -} - -export interface ConsoleAPICalledEvent { - readonly type: ('log' | 'debug' | 'info' | 'error' | 'warning' | 'dir' | 'dirxml' | 'table' | 'trace' | 'clear' | 'startGroup' | 'startGroupCollapsed' | 'endGroup' | 'assert' | 'profile' | 'profileEnd' | 'count' | 'timeEnd'); - readonly args: Crdp.Runtime.RemoteObject[]; - readonly executionContextId: Crdp.Runtime.ExecutionContextId; - readonly timestamp: Crdp.Runtime.Timestamp; - readonly stackTrace?: CodeFlowStackTrace; - readonly context?: string; -} - -export interface ExceptionThrownEvent { - readonly timestamp: Crdp.Runtime.Timestamp; - readonly exceptionDetails: ExceptionDetails; -} - -export interface ExceptionDetails { - readonly exceptionId: integer; - readonly text: string; - readonly lineNumber: integer; - readonly columnNumber: integer; - readonly script?: IScript; - readonly url?: string; - readonly stackTrace?: CodeFlowStackTrace; - readonly exception?: Crdp.Runtime.RemoteObject; - readonly executionContextId?: Crdp.Runtime.ExecutionContextId; -} - -export interface SetVariableValueRequest { - readonly scopeNumber: integer; - readonly variableName: string; - readonly newValue: Crdp.Runtime.CallArgument; - readonly frame: ICallFrame; -} - -export type LogEntrySource = 'xml' | 'javascript' | 'network' | 'storage' | 'appcache' | 'rendering' | 'security' | 'deprecation' | 'worker' | 'violation' | 'intervention' | 'recommendation' | 'other'; -export type LogLevel = 'verbose' | 'info' | 'warning' | 'error'; - -export interface LogEntry { - readonly source: LogEntrySource; - readonly level: LogLevel; - readonly text: string; - readonly timestamp: Crdp.Runtime.Timestamp; - readonly url?: string; - readonly lineNumber?: integer; - readonly stackTrace?: CodeFlowStackTrace; - readonly networkRequestId?: Crdp.Network.RequestId; - readonly workerId?: string; - readonly args?: Crdp.Runtime.RemoteObject[]; -} diff --git a/src/chrome/target/exceptionThrownEventProvider.ts b/src/chrome/target/exceptionThrownEventProvider.ts deleted file mode 100644 index 5c21ec3a1..000000000 --- a/src/chrome/target/exceptionThrownEventProvider.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Crdp } from '../..'; -import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; -import { ExceptionDetails } from './events'; -import { CDTPStackTraceParser } from './cdtpStackTraceParser'; -import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; -import { injectable, inject } from 'inversify'; -import { TYPES } from '../dependencyInjection.ts/types'; - -export interface IExceptionThrownEventProvider { - -} - -@injectable() -export class ExceptionThrownEventProvider extends CDTPEventsEmitterDiagnosticsModule implements IExceptionThrownEventProvider { - protected readonly api: Crdp.RuntimeApi = this.protocolApi.Runtime; - - public readonly onExceptionThrown = this.addApiListener('exceptionThrown', async (params: Crdp.Runtime.ExceptionThrownEvent) => - ({ - timestamp: params.timestamp, - exceptionDetails: await this.toExceptionDetails(params.exceptionDetails) - })); - - private async toExceptionDetails(exceptionDetails: Crdp.Runtime.ExceptionDetails): Promise { - return { - exceptionId: exceptionDetails.exceptionId, - text: exceptionDetails.text, - lineNumber: exceptionDetails.lineNumber, - columnNumber: exceptionDetails.columnNumber, - script: exceptionDetails.scriptId ? await this._scriptsRegistry.getScriptById(exceptionDetails.scriptId) : undefined, - url: exceptionDetails.url, - stackTrace: exceptionDetails.stackTrace && await this._cdtpStackTraceParser.toStackTraceCodeFlow(exceptionDetails.stackTrace), - exception: exceptionDetails.exception, - executionContextId: exceptionDetails.executionContextId, - }; - } - - constructor( - @inject(TYPES.CDTPClient) private readonly protocolApi: Crdp.ProtocolApi, - private readonly _cdtpStackTraceParser: CDTPStackTraceParser, - private readonly _scriptsRegistry: CDTPScriptsRegistry, - ) { - super(); - } -} \ No newline at end of file diff --git a/src/chrome/target/executionContextEventsProvider.ts b/src/chrome/target/executionContextEventsProvider.ts deleted file mode 100644 index 27188fd91..000000000 --- a/src/chrome/target/executionContextEventsProvider.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { CDTPEventsEmitterDiagnosticsModule } from './cdtpDiagnosticsModule'; -import { Crdp } from '../..'; -import { inject, injectable } from 'inversify'; -import { CDTPScriptsRegistry } from './cdtpScriptsRegistry'; -import { TYPES } from '../dependencyInjection.ts/types'; - -@injectable() -export class ExecutionContextEventsProvider extends CDTPEventsEmitterDiagnosticsModule { - protected readonly api: Crdp.RuntimeApi = this._protocolApi.Runtime; - - public readonly onExecutionContextsCleared = this.addApiListener('executionContextsCleared', (params: void) => params); - - public readonly onExecutionContextDestroyed = this.addApiListener('executionContextDestroyed', async (params: Crdp.Runtime.ExecutionContextDestroyedEvent) => - this._scriptsRegistry.markExecutionContextAsDestroyed(params.executionContextId)); - - public readonly onExecutionContextCreated = this.addApiListener('executionContextCreated', async (params: Crdp.Runtime.ExecutionContextCreatedEvent) => - this._scriptsRegistry.registerExecutionContext(params.context.id)); - - constructor( - @inject(TYPES.CDTPClient) private readonly _protocolApi: Crdp.ProtocolApi, - @inject(TYPES.CDTPScriptsRegistry) private readonly _scriptsRegistry: CDTPScriptsRegistry) { - super(); - } -} \ No newline at end of file diff --git a/src/chrome/target/inspectDebugeeState.ts b/src/chrome/target/inspectDebugeeState.ts deleted file mode 100644 index c8c24ba11..000000000 --- a/src/chrome/target/inspectDebugeeState.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { EvaluateOnCallFrameRequest } from './requests'; -import { Crdp } from '../..'; -import { CallFrameRegistry } from './callFrameRegistry'; -import { AddSourceUriToExpession } from './addSourceUriToExpression'; -import { injectable, inject } from 'inversify'; -import { TYPES } from '../dependencyInjection.ts/types'; - -export interface IInspectDebugeeState { - callFunctionOn(params: Crdp.Runtime.CallFunctionOnRequest): Promise; - getProperties(params: Crdp.Runtime.GetPropertiesRequest): Promise; - evaluate(params: Crdp.Runtime.EvaluateRequest): Promise; - evaluateOnCallFrame(params: EvaluateOnCallFrameRequest): Promise; -} - -@injectable() -export class InspectDebugeeState implements IInspectDebugeeState { - private addSourceUriToEvaluates = new AddSourceUriToExpession('evaluateOnFrame'); - - public callFunctionOn(params: Crdp.Runtime.CallFunctionOnRequest): Promise { - return this.api.Runtime.callFunctionOn(params); - } - - public getProperties(params: Crdp.Runtime.GetPropertiesRequest): Promise { - return this.api.Runtime.getProperties(params); - } - - public evaluate(params: Crdp.Runtime.EvaluateRequest): Promise { - params.expression = this.addSourceUriToEvaluates.addURLIfMissing(params.expression); - return this.api.Runtime.evaluate(params); - } - - public evaluateOnCallFrame(params: EvaluateOnCallFrameRequest): Promise { - return this.api.Debugger.evaluateOnCallFrame({ - callFrameId: this._callFrameRegistry.getFrameId(params.frame.unmappedCallFrame), - expression: this.addSourceUriToEvaluates.addURLIfMissing(params.expression), - objectGroup: params.objectGroup, - includeCommandLineAPI: params.includeCommandLineAPI, - silent: params.silent, - returnByValue: params.returnByValue, - generatePreview: params.generatePreview, - throwOnSideEffect: params.throwOnSideEffect, - timeout: params.timeout, - }); - } - - constructor( - @inject(TYPES.CDTPClient) protected readonly api: Crdp.ProtocolApi, - private readonly _callFrameRegistry: CallFrameRegistry) { - } -} \ No newline at end of file diff --git a/src/chrome/target/requests.ts b/src/chrome/target/requests.ts deleted file mode 100644 index 2d5da392b..000000000 --- a/src/chrome/target/requests.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Crdp } from '../..'; -import { LocationInScript } from '../internal/locations/location'; -import { ICallFrame, ScriptOrLoadedSource } from '../internal/stackTraces/callFrame'; - -export interface INewSetBreakpointResult { - readonly breakpointId?: Crdp.Debugger.BreakpointId; - readonly actualLocation?: LocationInScript; -} - -export interface INewAddBreakpointsResult { - readonly breakpointId?: Crdp.Debugger.BreakpointId; - readonly actualLocation?: LocationInScript & { scriptId?: Crdp.Runtime.ScriptId }; // TODO: node-debug2 is currently using the scriptId property -} - -export interface EvaluateOnCallFrameRequest { - readonly frame: ICallFrame; - readonly expression: string; - readonly objectGroup?: string; - readonly includeCommandLineAPI?: boolean; - readonly silent?: boolean; - readonly returnByValue?: boolean; - readonly generatePreview?: boolean; - readonly throwOnSideEffect?: boolean; - readonly timeout?: Crdp.Runtime.TimeDelta; -} \ No newline at end of file diff --git a/src/chrome/target/updateDebugeeState.ts b/src/chrome/target/updateDebugeeState.ts deleted file mode 100644 index f6d305299..000000000 --- a/src/chrome/target/updateDebugeeState.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Crdp } from '../..'; -import { SetVariableValueRequest } from './events'; -import { CallFrameRegistry } from './callFrameRegistry'; -import { TYPES } from '../dependencyInjection.ts/types'; -import { injectable, inject } from 'inversify'; - -export interface IUpdateDebugeeState { - setVariableValue(params: SetVariableValueRequest): Promise; -} - -@injectable() -export class UpdateDebugeeState implements IUpdateDebugeeState { - public setVariableValue(params: SetVariableValueRequest): Promise { - return this.api.Debugger.setVariableValue({ - callFrameId: this._callFrameRegistry.getFrameId(params.frame), - scopeNumber: params.scopeNumber, - variableName: params.variableName, - newValue: params.newValue - }); - } - - constructor( - @inject(TYPES.CDTPClient) private readonly api: Crdp.ProtocolApi, - private readonly _callFrameRegistry: CallFrameRegistry) { - } -} \ No newline at end of file diff --git a/src/chrome/utils/lazy.ts b/src/chrome/utils/lazy.ts new file mode 100644 index 000000000..3ce3aed8b --- /dev/null +++ b/src/chrome/utils/lazy.ts @@ -0,0 +1,24 @@ +const empty = Symbol(); + +export class Lazy1 { + private _value: T | typeof empty = empty; + private _parameter: P | typeof empty = empty; + private _function = (parameter: P) => this.value(parameter); + + public value(parameter: P): T { + if (this._value === empty) { + this._value = this._obtainValue(parameter); + this._parameter = parameter; + } else if (this._parameter !== parameter) { + throw new Error(`Can't obtain a lazy value with parameter ${parameter} when the previous call used parameter ${String(this._parameter)}`); + } + + return this._value; + } + + public get function(): (parameter: P) => T { + return this._function; + } + + constructor(private readonly _obtainValue: (parameter: P) => T) { } +} \ No newline at end of file diff --git a/src/chrome/utils/version.ts b/src/chrome/utils/version.ts new file mode 100644 index 000000000..ffc404e74 --- /dev/null +++ b/src/chrome/utils/version.ts @@ -0,0 +1,17 @@ +import * as semver from 'semver'; + +export class Version { + constructor(private readonly _semverVersion: semver.SemVer) { } + + public static coerce(versionString: string): Version { + return new Version(semver.coerce(versionString)); + } + + public static unknownVersion(): Version { + return Version.coerce('0.0.0'); // Using 0.0.0 will make behave isAtLeastVersion as if this was the oldest possible version + } + + public isAtLeastVersion(versionToCompare: string): boolean { + return semver.gte(this._semverVersion, versionToCompare); + } +} diff --git a/src/chrome/variables.ts b/src/chrome/variables.ts index 4777002eb..2eea8bc4c 100644 --- a/src/chrome/variables.ts +++ b/src/chrome/variables.ts @@ -6,7 +6,7 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { Handles } from 'vscode-debugadapter'; import { ChromeDebugLogic, VariableContext } from './chromeDebugAdapter'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; import * as utils from '../utils'; import { ICallFrame, ScriptOrLoadedSource } from './internal/stackTraces/callFrame'; @@ -35,7 +35,7 @@ export class PropertyContainer extends BaseVariableContainer { } export class LoggedObjects extends BaseVariableContainer { - constructor(private args: Crdp.Runtime.RemoteObject[]) { + constructor(private args: CDTP.Runtime.RemoteObject[]) { super(undefined); } @@ -45,12 +45,12 @@ export class LoggedObjects extends BaseVariableContainer { } export class ScopeContainer extends BaseVariableContainer { - private _thisObj: Crdp.Runtime.RemoteObject; - private _returnValue: Crdp.Runtime.RemoteObject; + private _thisObj: CDTP.Runtime.RemoteObject; + private _returnValue: CDTP.Runtime.RemoteObject; private _frameId: ICallFrame; private _origScopeIndex: number; - public constructor(frameId: ICallFrame, origScopeIndex: number, objectId: string, thisObj?: Crdp.Runtime.RemoteObject, returnValue?: Crdp.Runtime.RemoteObject) { + public constructor(frameId: ICallFrame, origScopeIndex: number, objectId: string, thisObj?: CDTP.Runtime.RemoteObject, returnValue?: CDTP.Runtime.RemoteObject) { super(objectId, ''); this._thisObj = thisObj; this._returnValue = returnValue; @@ -83,7 +83,7 @@ export class ScopeContainer extends BaseVariableContainer { return adapter.setVariableValue(this._frameId, this._origScopeIndex, name, value); } - private insertRemoteObject(adapter: ChromeDebugLogic, variables: DebugProtocol.Variable[], name: string, obj: Crdp.Runtime.RemoteObject): Promise { + private insertRemoteObject(adapter: ChromeDebugLogic, variables: DebugProtocol.Variable[], name: string, obj: CDTP.Runtime.RemoteObject): Promise { return adapter.remoteObjectToVariable(name, obj).then(variable => { variables.unshift(variable); return variables; @@ -92,9 +92,9 @@ export class ScopeContainer extends BaseVariableContainer { } export class ExceptionContainer extends PropertyContainer { - protected _exception: Crdp.Runtime.RemoteObject; + protected _exception: CDTP.Runtime.RemoteObject; - protected constructor(_objectId: string, exception: Crdp.Runtime.RemoteObject) { + protected constructor(_objectId: string, exception: CDTP.Runtime.RemoteObject) { super(exception.objectId, undefined); this._exception = exception; } @@ -102,7 +102,7 @@ export class ExceptionContainer extends PropertyContainer { /** * Expand the exception as if it were a Scope */ - public static create(exception: Crdp.Runtime.RemoteObject): ExceptionContainer { + public static create(exception: CDTP.Runtime.RemoteObject): ExceptionContainer { return exception.objectId ? new ExceptionContainer(exception.objectId, exception) : new ExceptionValueContainer(exception); @@ -113,7 +113,7 @@ export class ExceptionContainer extends PropertyContainer { * For when a value is thrown instead of an object */ export class ExceptionValueContainer extends ExceptionContainer { - public constructor(exception: Crdp.Runtime.RemoteObject) { + public constructor(exception: CDTP.Runtime.RemoteObject) { super('EXCEPTION_ID', exception); } @@ -121,7 +121,7 @@ export class ExceptionValueContainer extends ExceptionContainer { * Make up a fake 'Exception' property to hold the thrown value, displayed under the Exception Scope */ public expand(adapter: ChromeDebugLogic, _filter?: string, _start?: number, _count?: number): Promise { - const excValuePropDescriptor: Crdp.Runtime.PropertyDescriptor = { name: 'Exception', value: this._exception }; + const excValuePropDescriptor: CDTP.Runtime.PropertyDescriptor = { name: 'Exception', value: this._exception }; return adapter.propertyDescriptorToVariable(excValuePropDescriptor) .then(variable => [variable]); } @@ -135,7 +135,7 @@ const PREVIEW_PROPS_DEFAULT = 3; const PREVIEW_PROPS_CONSOLE = 8; const PREVIEW_PROP_LENGTH = 50; const ELLIPSIS = '…'; -function getArrayPreview(object: Crdp.Runtime.RemoteObject, context?: string): string { +function getArrayPreview(object: CDTP.Runtime.RemoteObject, context?: string): string { let value = object.description; if (object.preview) { const numProps = context === 'repl' ? PREVIEW_PROPS_CONSOLE : PREVIEW_PROPS_DEFAULT; @@ -175,7 +175,7 @@ function getArrayPreview(object: Crdp.Runtime.RemoteObject, context?: string): s return value; } -function getObjectPreview(object: Crdp.Runtime.RemoteObject, context?: string): string { +function getObjectPreview(object: CDTP.Runtime.RemoteObject, context?: string): string { let value = object.description; if (object.preview) { const numProps = context === 'repl' ? PREVIEW_PROPS_CONSOLE : PREVIEW_PROPS_DEFAULT; @@ -197,7 +197,7 @@ function getObjectPreview(object: Crdp.Runtime.RemoteObject, context?: string): return value; } -function propertyPreviewToString(prop: Crdp.Runtime.PropertyPreview): string { +function propertyPreviewToString(prop: CDTP.Runtime.PropertyPreview): string { const value = typeof prop.value === 'undefined' ? `<${prop.type}>` : trimProperty(prop.value); @@ -213,7 +213,7 @@ function trimProperty(value: string): string { value; } -export function getRemoteObjectPreview(object: Crdp.Runtime.RemoteObject, stringify = true, context?: string): string { +export function getRemoteObjectPreview(object: CDTP.Runtime.RemoteObject, stringify = true, context?: string): string { if (object) { if (object.type === 'object') { return getRemoteObjectPreview_object(object, context); @@ -227,7 +227,7 @@ export function getRemoteObjectPreview(object: Crdp.Runtime.RemoteObject, string return ''; } -export function getRemoteObjectPreview_object(object: Crdp.Runtime.RemoteObject, context?: string): string { +export function getRemoteObjectPreview_object(object: CDTP.Runtime.RemoteObject, context?: string): string { const objectDescription = object.description || ''; if ((object.subtype) === 'internal#location') { // Could format this nicely later, see #110 @@ -260,7 +260,7 @@ export function getRemoteObjectPreview_object(object: Crdp.Runtime.RemoteObject, } } -export function getRemoteObjectPreview_primitive(object: Crdp.Runtime.RemoteObject, stringify?: boolean): string { +export function getRemoteObjectPreview_primitive(object: CDTP.Runtime.RemoteObject, stringify?: boolean): string { // The value is a primitive value, or something that has a description (not object, primitive, or undefined). And force to be string if (typeof object.value === 'undefined') { return object.description + ''; @@ -276,7 +276,7 @@ export function getRemoteObjectPreview_primitive(object: Crdp.Runtime.RemoteObje } } -export function getRemoteObjectPreview_function(object: Crdp.Runtime.RemoteObject, _context?: string): string { +export function getRemoteObjectPreview_function(object: CDTP.Runtime.RemoteObject, _context?: string): string { const firstBraceIdx = object.description.indexOf('{'); if (firstBraceIdx >= 0) { return object.description.substring(0, firstBraceIdx) + '{ … }'; diff --git a/src/debugAdapterInterfaces.d.ts b/src/debugAdapterInterfaces.d.ts index 09126e63b..d13fba622 100644 --- a/src/debugAdapterInterfaces.d.ts +++ b/src/debugAdapterInterfaces.d.ts @@ -7,7 +7,7 @@ */ import { DebugProtocol } from 'vscode-debugprotocol'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; import { ITelemetryPropertyCollector } from './telemetry'; import { IStringDictionary } from './utils'; import { ITargetFilter } from './chrome/chromeConnection'; @@ -100,8 +100,8 @@ export type ISetBreakpointsResponseBody = DebugProtocol.SetBreakpointsResponse[' * If a breakpoint is set but Chrome returns no locations, actualLocation is not set. */ export interface ISetBreakpointResult { - breakpointId?: Crdp.Debugger.BreakpointId; - actualLocation?: Crdp.Debugger.Location; + breakpointId?: CDTP.Debugger.BreakpointId; + actualLocation?: CDTP.Debugger.Location; } export type ISourceResponseBody = DebugProtocol.SourceResponse['body']; @@ -139,7 +139,7 @@ export interface TimeTravelClient { reverse(): Promise; } -export interface TimeTravelRuntime extends Crdp.ProtocolApi { +export interface TimeTravelRuntime extends CDTP.ProtocolApi { TimeTravel: TimeTravelClient; } diff --git a/src/index.ts b/src/index.ts index d754477f6..81e0269d7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,24 +29,28 @@ import * as variables from './chrome/variables'; import { NullLogger } from './nullLogger'; import * as executionTimingsReporter from './executionTimingsReporter'; -import { Protocol as Crdp } from 'devtools-protocol'; -import { Version, TargetVersions } from './chrome/chromeTargetDiscoveryStrategy'; +import { Protocol as CDTP } from 'devtools-protocol'; +import { TargetVersions } from './chrome/chromeTargetDiscoveryStrategy'; +import { Version } from "./chrome/utils/version"; import { IOnPausedResult } from './chrome/internal/breakpoints/breakpointsLogic'; import { parseResourceIdentifier } from './chrome/internal/sources/resourceIdentifier'; import { ChromeDebugAdapter } from './chrome/client/chromeDebugAdapter/chromeDebugAdapterV2'; import { IExtensibilityPoints, OnlyProvideCustomLauncherExtensibilityPoints } from './chrome/extensibility/extensibilityPoints'; -import { IDebuggeeLauncher, ILaunchResult, IDebuggeeRunner } from './chrome/debugee/debugeeLauncher'; +import { IDebuggeeLauncher, ILaunchResult, IDebuggeeRunner } from './chrome/debugeeStartup/debugeeLauncher'; import { inject, injectable, postConstruct } from 'inversify'; import { ConnectedCDAConfiguration } from './chrome/client/chromeDebugAdapter/cdaConfiguration'; import { IComponent } from './chrome/internal/features/feature'; import { TYPES } from './chrome/dependencyInjection.ts/types'; -import { IInspectDebugeeState } from './chrome/target/inspectDebugeeState'; -import { CDTPEventsEmitterDiagnosticsModule } from './chrome/target/cdtpDiagnosticsModule'; -import { INetworkCacheConfiguration, IDebugeeVersionProvider, IPausedOverlay, IBrowserNavigation } from './chrome/target/cdtpSmallerModules'; +import { IInspectDebugeeState } from './chrome/cdtpDebuggee/features/cdtpInspectDebugeeState'; +import { CDTPEventsEmitterDiagnosticsModule } from './chrome/cdtpDebuggee/infrastructure/cdtpDiagnosticsModule'; import { ICommunicator } from './chrome/communication/communicator'; import { ISupportedDomains } from './chrome/internal/domains/supportedDomains'; import { Internal } from './chrome/communication/internalChannels'; import { ISession } from './chrome/client/session'; +import { IPausedOverlay } from './chrome/cdtpDebuggee/features/cdtpPausedOverlay'; +import { INetworkCacheConfiguration } from './chrome/cdtpDebuggee/features/cdtpNetworkCacheConfiguration'; +import { IDebugeeRuntimeVersionProvider } from './chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider'; +import { IBrowserNavigator } from './chrome/cdtpDebuggee/features/cdtpBrowserNavigator'; export { chromeConnection, @@ -99,15 +103,15 @@ export { Internal, INetworkCacheConfiguration, - IDebugeeVersionProvider, + IDebugeeRuntimeVersionProvider as IDebugeeVersionProvider, parseResourceIdentifier, - IBrowserNavigation, + IBrowserNavigator as IBrowserNavigation, ISession, TYPES, IInspectDebugeeState, - Crdp + CDTP }; diff --git a/src/transformers/remotePathTransformer.ts b/src/transformers/remotePathTransformer.ts index e159f9a8c..ac772eda5 100644 --- a/src/transformers/remotePathTransformer.ts +++ b/src/transformers/remotePathTransformer.ts @@ -5,7 +5,6 @@ import * as fs from 'fs'; import * as path from 'path'; import { logger } from 'vscode-debugadapter'; -import { DebugProtocol } from 'vscode-debugprotocol'; import { ICommonRequestArgs } from '../debugAdapterInterfaces'; import * as errors from '../errors'; import { UrlPathTransformer } from '../transformers/urlPathTransformer'; @@ -68,20 +67,6 @@ export class RemotePathTransformer extends UrlPathTransformer { return scriptPath; } - public async fixSource(source: DebugProtocol.Source): Promise { - await super.fixSource(source); - - if (source && source.path) { - const remotePath = parseResourceIdentifier(source && source.path); - const localPath = this.getClientPathFromTargetPath(remotePath) || remotePath; - if (utils.existsSync(localPath.canonicalized)) { - source.path = localPath.canonicalized; - source.sourceReference = undefined; - source.origin = undefined; - } - } - } - private shouldMapPaths(remotePath: IResourceIdentifier): boolean { // Map paths only if localRoot/remoteRoot are set, and the remote path is absolute on some system return !!this._localRoot && !!this._remoteRoot && (path.posix.isAbsolute(remotePath.canonicalized) || path.win32.isAbsolute(remotePath.canonicalized)); diff --git a/src/transformers/urlPathTransformer.ts b/src/transformers/urlPathTransformer.ts index f913d4ed5..d4d495446 100644 --- a/src/transformers/urlPathTransformer.ts +++ b/src/transformers/urlPathTransformer.ts @@ -6,7 +6,6 @@ import { BasePathTransformer } from './basePathTransformer'; import { IPathMapping } from '../debugAdapterInterfaces'; import { logger } from 'vscode-debugadapter'; -import { DebugProtocol } from 'vscode-debugprotocol'; import * as ChromeUtils from '../chrome/chromeUtils'; import * as path from 'path'; @@ -38,7 +37,7 @@ export class UrlPathTransformer extends BasePathTransformer { public async scriptParsed(scriptUrl: IResourceIdentifier): Promise { const clientPath = await this.targetUrlToClientPath(scriptUrl); - if (!clientPath) { + if (clientPath.canonicalized === '') { // It's expected that eval scripts (eval://) won't be resolved if (!scriptUrl.canonicalized.startsWith(ChromeUtils.EVAL_NAME_PREFIX)) { logger.log(`Paths.scriptParsed: could not resolve ${scriptUrl} to a file with pathMapping/webRoot: ${JSON.stringify(this._pathMapping)}. It may be external or served directly from the server's memory (and that's OK).`); @@ -46,8 +45,10 @@ export class UrlPathTransformer extends BasePathTransformer { } else { logger.log(`Paths.scriptParsed: resolved ${scriptUrl} to ${clientPath}. pathMapping/webroot: ${JSON.stringify(this._pathMapping)}`); const canonicalizedClientPath = clientPath; - this._clientPathToTargetUrl.set(canonicalizedClientPath, scriptUrl); - this._targetUrlToClientPath.set(scriptUrl, clientPath); + + // an HTML file with multiple script tags will call this method several times with the same scriptUrl, so we use setAndReplaceIfExist + this._clientPathToTargetUrl.setAndReplaceIfExist(canonicalizedClientPath, scriptUrl); + this._targetUrlToClientPath.setAndReplaceIfExist(scriptUrl, clientPath); scriptUrl = clientPath; } @@ -55,25 +56,6 @@ export class UrlPathTransformer extends BasePathTransformer { return Promise.resolve(scriptUrl); } - public async fixSource(source: DebugProtocol.Source): Promise { - // TODO DIEGO: Delete this method - if (source && source.path) { - // Try to resolve the url to a path in the workspace. If it's not in the workspace, - // just use the script.url as-is. It will be resolved or cleared by the SourceMapTransformer. - const clientPath = this.getClientPathFromTargetPath(parseResourceIdentifier(source.path)) || - await this.targetUrlToClientPath(parseResourceIdentifier(source.path)); - - // Incoming stackFrames have sourceReference and path set. If the path was resolved to a file in the workspace, - // clear the sourceReference since it's not needed. - if (clientPath) { - source.path = clientPath.canonicalized; - source.sourceReference = undefined; - source.origin = undefined; - source.name = path.basename(clientPath.canonicalized); - } - } - } - public getTargetPathFromClientPath(clientPath: IResourceIdentifier): IResourceIdentifier { // If it's already a URL, skip the Map return path.isAbsolute(clientPath.canonicalized) ? diff --git a/test/chrome/chromeDebugAdapter.test.ts b/test/chrome/chromeDebugAdapter.test.ts index f7054261a..f2acc2d7b 100644 --- a/test/chrome/chromeDebugAdapter.test.ts +++ b/test/chrome/chromeDebugAdapter.test.ts @@ -18,7 +18,7 @@ import * as mockery from 'mockery'; import { EventEmitter } from 'events'; import * as assert from 'assert'; import { Mock, MockBehavior, It, IMock, Times } from 'typemoq'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; import * as testUtils from '../testUtils'; import * as utils from '../../src/utils'; @@ -136,7 +136,7 @@ suite('ChromeDebugAdapter', () => { Promise.resolve(''); }); - mockEventEmitter.emit('Debugger.scriptParsed', { scriptId, url }); + mockEventEmitter.emit('Debugger.scriptParsed', { scriptId, url }); } // Helper to run async asserts inside promises so they can be correctly awaited @@ -195,7 +195,7 @@ suite('ChromeDebugAdapter', () => { mockChrome.Debugger .setup(x => x.setBreakpointByUrl(It.isValue({ urlRegex, lineNumber, columnNumber, condition }))) .returns(() => Promise.resolve( - { + { breakpointId: BP_ID + i, locations: success ? [location] : [] })) @@ -204,7 +204,7 @@ suite('ChromeDebugAdapter', () => { mockChrome.Debugger .setup(x => x.setBreakpoint(It.isValue({ location: { lineNumber, columnNumber, scriptId }, condition }))) .returns(() => Promise.resolve( - { + { breakpointId: BP_ID + i, actualLocation: success ? location : null })) @@ -342,9 +342,9 @@ suite('ChromeDebugAdapter', () => { .then(response => { expectRemoveBreakpoint([0, 1]); mockEventEmitter.emit('Debugger.globalObjectCleared'); - mockEventEmitter.emit('Debugger.scriptParsed', { scriptId: 'afterRefreshScriptId', url: FILE_NAME }); - mockEventEmitter.emit('Debugger.breakpointResolved', { breakpointId: BP_ID + 0, location: { scriptId: 'afterRefreshScriptId' } }); - mockEventEmitter.emit('Debugger.breakpointResolved', { breakpointId: BP_ID + 1, location: { scriptId: 'afterRefreshScriptId' } }); + mockEventEmitter.emit('Debugger.scriptParsed', { scriptId: 'afterRefreshScriptId', url: FILE_NAME }); + mockEventEmitter.emit('Debugger.breakpointResolved', { breakpointId: BP_ID + 0, location: { scriptId: 'afterRefreshScriptId' } }); + mockEventEmitter.emit('Debugger.breakpointResolved', { breakpointId: BP_ID + 1, location: { scriptId: 'afterRefreshScriptId' } }); breakpoints.push({ line: 321, column: 123 }); expectSetBreakpoint(breakpoints, FILE_NAME, 'afterRefreshScriptId'); @@ -359,7 +359,7 @@ suite('ChromeDebugAdapter', () => { ]; // Set up the mock to return a different location - const location: Crdp.Debugger.Location = { + const location: CDTP.Debugger.Location = { scriptId: SCRIPT_ID, lineNumber: breakpoints[0].line + 10, columnNumber: breakpoints[0].column + 10 }; const expectedResponse: ISetBreakpointsResponseBody = { breakpoints: [{ line: location.lineNumber, column: location.columnNumber, verified: true, id: 1000 }]}; @@ -368,7 +368,7 @@ suite('ChromeDebugAdapter', () => { mockChrome.Debugger .setup(x => x.setBreakpointByUrl(It.isValue({ urlRegex: expectedRegex, lineNumber: breakpoints[0].line, columnNumber: breakpoints[0].column, condition: undefined }))) .returns(() => Promise.resolve( - { breakpointId: BP_ID, locations: [location] })) + { breakpointId: BP_ID, locations: [location] })) .verifiable(); return chromeDebugAdapter.attach(ATTACH_ARGS) @@ -715,7 +715,7 @@ suite('ChromeDebugAdapter', () => { }); suite('evaluate()', () => { - function getExpectedValueResponse(resultObj: Crdp.Runtime.RemoteObject): IEvaluateResponseBody { + function getExpectedValueResponse(resultObj: CDTP.Runtime.RemoteObject): IEvaluateResponseBody { let result: string; let variablesReference = 0; if (resultObj.type === 'string') { @@ -731,21 +731,21 @@ suite('ChromeDebugAdapter', () => { }; } - function setupEvalMock(expression: string, result: Crdp.Runtime.RemoteObject): void { + function setupEvalMock(expression: string, result: CDTP.Runtime.RemoteObject): void { mockChrome.Runtime - .setup(x => x.evaluate(It.isValue({ expression, silent: true, generatePreview: true, includeCommandLineAPI: true, objectGroup: 'console', userGesture: true }))) - .returns(() => Promise.resolve({ result })); + .setup(x => x.evaluate(It.isValue({ expression, silent: true, generatePreview: true, includeCommandLineAPI: true, objectGroup: 'console', userGesture: true }))) + .returns(() => Promise.resolve({ result })); } - function setupEvalOnCallFrameMock(expression: string, callFrameId: string, result: Crdp.Runtime.RemoteObject): void { + function setupEvalOnCallFrameMock(expression: string, callFrameId: string, result: CDTP.Runtime.RemoteObject): void { mockChrome.Debugger .setup(x => x.evaluateOnCallFrame(It.isValue({ expression, callFrameId, silent: true, generatePreview: true, includeCommandLineAPI: true, objectGroup: 'console' }))) - .returns(() => Promise.resolve({ result })); + .returns(() => Promise.resolve({ result })); } test('calls Runtime.evaluate when not paused', () => { const expression = '1+1'; - const result: Crdp.Runtime.RemoteObject = { type: 'string', description: '2' }; + const result: CDTP.Runtime.RemoteObject = { type: 'string', description: '2' }; setupEvalMock(expression, result); return chromeDebugAdapter.evaluate({ expression }).then(response => { @@ -756,7 +756,7 @@ suite('ChromeDebugAdapter', () => { test('calls Debugger.evaluateOnCallFrame when paused', () => { const callFrameId = '1'; const expression = '1+1'; - const result: Crdp.Runtime.RemoteObject = { type: 'string', description: '2' }; + const result: CDTP.Runtime.RemoteObject = { type: 'string', description: '2' }; setupEvalOnCallFrameMock(expression, callFrameId, result); // Sue me (just easier than sending a Debugger.paused event) @@ -773,10 +773,10 @@ suite('ChromeDebugAdapter', () => { await chromeDebugAdapter.attach(ATTACH_ARGS); const scriptId = 'script1'; - const location: Crdp.Debugger.Location = { lineNumber: 0, columnNumber: 0, scriptId }; + const location: CDTP.Debugger.Location = { lineNumber: 0, columnNumber: 0, scriptId }; const callFrame = { callFrameId: 'id1', location }; emitScriptParsed('', scriptId); - mockEventEmitter.emit('Debugger.paused', { callFrames: [callFrame, callFrame] }); + mockEventEmitter.emit('Debugger.paused', { callFrames: [callFrame, callFrame] }); const { stackFrames } = await chromeDebugAdapter.stackTrace({ threadId: THREAD_ID }); @@ -786,7 +786,7 @@ suite('ChromeDebugAdapter', () => { const sourceReference = stackFrames[0].source.sourceReference; // If it pauses a second time, and we request another stackTrace, should have the same result - mockEventEmitter.emit('Debugger.paused', {callFrames: [callFrame, callFrame]}); + mockEventEmitter.emit('Debugger.paused', {callFrames: [callFrame, callFrame]}); const { stackFrames: stackFrames2 } = await chromeDebugAdapter.stackTrace({ threadId: THREAD_ID }); assert.equal(stackFrames2.length, 2); @@ -806,7 +806,7 @@ suite('ChromeDebugAdapter', () => { const generatedExceptionStr = getExceptionStr(generatedPath, 6); const authoredExceptionStr = getExceptionStr(authoredPath, 12); - const exceptionEvent: Crdp.Runtime.ExceptionThrownEvent = { + const exceptionEvent: CDTP.Runtime.ExceptionThrownEvent = { 'timestamp': 1490164925297, 'exceptionDetails': { 'exceptionId': 21, diff --git a/test/chrome/consoleHelper.test.ts b/test/chrome/consoleHelper.test.ts index a406687a0..b19403ceb 100644 --- a/test/chrome/consoleHelper.test.ts +++ b/test/chrome/consoleHelper.test.ts @@ -3,7 +3,7 @@ *--------------------------------------------------------*/ import * as assert from 'assert'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; import * as testUtils from '../testUtils'; import * as ConsoleHelper from '../../src/chrome/consoleHelper'; @@ -20,7 +20,7 @@ suite('ConsoleHelper', () => { /** * Test helper valid when the message consists only of strings that will be collapsed to one string */ - function doAssertForString(params: Crdp.Runtime.ConsoleAPICalledEvent, expectedText: string, expectedIsError = false): void { + function doAssertForString(params: CDTP.Runtime.ConsoleAPICalledEvent, expectedText: string, expectedIsError = false): void { const result = ConsoleHelper.formatConsoleArguments(params.type, params.args, params.stackTrace); // Strings are collapsed to one string @@ -164,8 +164,8 @@ namespace Runtime { * @param params - The list of parameters passed to the log function * @param overrideProps - An object of props that the message should have. The rest are filled in with defaults. */ - function makeMockMessage(type: string, args: (string | number | null | undefined)[], overrideProps?: any): Crdp.Runtime.ConsoleAPICalledEvent { - const message: Crdp.Runtime.ConsoleAPICalledEvent = { + function makeMockMessage(type: string, args: (string | number | null | undefined)[], overrideProps?: any): CDTP.Runtime.ConsoleAPICalledEvent { + const message: CDTP.Runtime.ConsoleAPICalledEvent = { type, executionContextId: 2, timestamp: Date.now(), @@ -187,15 +187,15 @@ namespace Runtime { * Returns a mock ConsoleAPICalledEvent with the given argument values. * You can pass '$obj' to get an object. */ - export function makeLog(...args: (string | number | null | undefined)[]): Crdp.Runtime.ConsoleAPICalledEvent { + export function makeLog(...args: (string | number | null | undefined)[]): CDTP.Runtime.ConsoleAPICalledEvent { const msg = makeMockMessage('log', args); return msg; } - export function makeArgs(...args: (string | number | null | undefined)[]): Crdp.Runtime.RemoteObject[] { + export function makeArgs(...args: (string | number | null | undefined)[]): CDTP.Runtime.RemoteObject[] { return args.map(arg => { if (arg === '$obj') { - return { + return { value: undefined, type: 'object', description: 'Object', @@ -212,14 +212,14 @@ namespace Runtime { }); } - export function makeAssert(...args: any[]): Crdp.Runtime.ConsoleAPICalledEvent { - const fakeStackTrace: Crdp.Runtime.StackTrace = { + export function makeAssert(...args: any[]): CDTP.Runtime.ConsoleAPICalledEvent { + const fakeStackTrace: CDTP.Runtime.StackTrace = { callFrames: [{ url: '/script/a.js', lineNumber: 4, columnNumber: 1, scriptId: '1', functionName: 'myFn' }] }; return makeMockMessage('assert', args, { level: 'error', stackTrace: fakeStackTrace }); } - export function makeNetworkLog(text: string, url: string): Crdp.Runtime.ConsoleAPICalledEvent { + export function makeNetworkLog(text: string, url: string): CDTP.Runtime.ConsoleAPICalledEvent { return makeMockMessage('log', [text], { source: 'network', url, level: 'error' }); } } diff --git a/test/chrome/variables.test.ts b/test/chrome/variables.test.ts index 2b4595a06..dea05ec67 100644 --- a/test/chrome/variables.test.ts +++ b/test/chrome/variables.test.ts @@ -3,7 +3,7 @@ *--------------------------------------------------------*/ import * as assert from 'assert'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; import * as Variables from '../../src/chrome/variables'; @@ -24,10 +24,10 @@ suite('Variables', () => { } suite('getArrayPreview()', () => { - function getRemoteArray(props: any[]): Crdp.Runtime.RemoteObject { - const preview = { + function getRemoteArray(props: any[]): CDTP.Runtime.RemoteObject { + const preview = { properties: props.map((prop, i) => { - return { + return { name: i.toString(), type: getPropType(prop), value: getPropValue(prop) @@ -82,11 +82,11 @@ suite('Variables', () => { }); suite('getObjectPreview()', () => { - function getRemoteObject(obj: any): Crdp.Runtime.RemoteObject { - const preview = { + function getRemoteObject(obj: any): CDTP.Runtime.RemoteObject { + const preview = { properties: Object.keys(obj).map((prop) => { const value = obj[prop]; - return { + return { name: prop.toString(), type: getPropType(value), value: getPropValue(value) diff --git a/test/mocks/debugProtocolMocks.ts b/test/mocks/debugProtocolMocks.ts index 289eb3acd..d327a0ff7 100644 --- a/test/mocks/debugProtocolMocks.ts +++ b/test/mocks/debugProtocolMocks.ts @@ -5,16 +5,16 @@ import { EventEmitter } from 'events'; import { Mock, IMock } from 'typemoq'; -import { Protocol as Crdp } from 'devtools-protocol'; +import { Protocol as CDTP } from 'devtools-protocol'; export interface IMockChromeConnectionAPI { - apiObjects: Crdp.ProtocolApi; + apiObjects: CDTP.ProtocolApi; - Console: IMock; - Debugger: IMock; - Runtime: IMock; - Inspector: IMock; - Log: IMock; + Console: IMock; + Debugger: IMock; + Runtime: IMock; + Inspector: IMock; + Log: IMock; mockEventEmitter: EventEmitter; } @@ -65,31 +65,31 @@ function getLogStubs(mockEventEmitter) { export function getMockChromeConnectionApi(): IMockChromeConnectionAPI { const mockEventEmitter = new EventEmitter(); - const mockConsole = Mock.ofInstance(getConsoleStubs(mockEventEmitter)); + const mockConsole = Mock.ofInstance(getConsoleStubs(mockEventEmitter)); mockConsole.callBase = true; mockConsole .setup(x => x.enable()) .returns(() => Promise.resolve()); - const mockDebugger = Mock.ofInstance(getDebuggerStubs(mockEventEmitter)); + const mockDebugger = Mock.ofInstance(getDebuggerStubs(mockEventEmitter)); mockDebugger.callBase = true; mockDebugger .setup(x => x.enable()) .returns(() => Promise.resolve(null)); - const mockRuntime = Mock.ofInstance(getRuntimeStubs(mockEventEmitter)); + const mockRuntime = Mock.ofInstance(getRuntimeStubs(mockEventEmitter)); mockRuntime.callBase = true; mockRuntime .setup(x => x.enable()) .returns(() => Promise.resolve()); - const mockInspector = Mock.ofInstance(getInspectorStubs(mockEventEmitter)); + const mockInspector = Mock.ofInstance(getInspectorStubs(mockEventEmitter)); mockInspector.callBase = true; - const mockLog = Mock.ofInstance(getLogStubs(mockEventEmitter)); + const mockLog = Mock.ofInstance(getLogStubs(mockEventEmitter)); mockLog.callBase = true; - const chromeConnectionAPI: Crdp.ProtocolApi = { + const chromeConnectionAPI: CDTP.ProtocolApi = { Console: mockConsole.object, Debugger: mockDebugger.object, Runtime: mockRuntime.object, diff --git a/test/testDebug/testDebugeeRunner.ts b/test/testDebug/testDebugeeRunner.ts index 2c76f5eaa..6195f635b 100644 --- a/test/testDebug/testDebugeeRunner.ts +++ b/test/testDebug/testDebugeeRunner.ts @@ -1,10 +1,9 @@ import { ITelemetryPropertyCollector } from '../../src'; -import { IDebuggeeRunner } from '../../src/chrome/debugee/debugeeLauncher'; -import { CDTPDiagnostics } from '../../src/chrome/target/cdtpDiagnostics'; +import { IDebuggeeRunner } from '../../src/chrome/debugeeStartup/debugeeLauncher'; export class TestDebugeeRunner implements IDebuggeeRunner { public async run(_telemetryPropertyCollector: ITelemetryPropertyCollector): Promise { } - constructor(readonly _chrome: CDTPDiagnostics) { } + constructor() { } } \ No newline at end of file From ca7e80b9d037de27453d6b7c948a4b2ec7f64121 Mon Sep 17 00:00:00 2001 From: digeff Date: Fri, 11 Jan 2019 12:14:03 -0800 Subject: [PATCH 06/23] Finish resolving merge conflicts --- .../cdtpDebuggee/registries/cdtpScriptsRegistry.ts | 14 ++++++++++++++ .../internal/sources/features/dotScriptsCommand.ts | 3 +-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts b/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts index ab5f5d6e1..6eeb5a717 100644 --- a/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts +++ b/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts @@ -3,6 +3,7 @@ import { IScript } from '../../internal/scripts/script'; import { ValidatedMap } from '../../collections/validatedMap'; import { ExecutionContext, IExecutionContext } from '../../internal/scripts/executionContext'; import { injectable } from 'inversify'; +import { IResourceIdentifier, newResourceIdentifierMap } from '../../internal/sources/resourceIdentifier'; /** * TODO: The CDTPScriptsRegistry is still a work in progress. We need to understand exactly how the ExecutionContexts, the Scripts, and the script "generations" work to figure out the best way to implement this @@ -45,12 +46,17 @@ export class CDTPScriptsRegistry { public getAllScripts(): IterableIterator> { return this._scripts.getAllScripts(); } + + public getScriptsByPath(nameOrLocation: IResourceIdentifier): IScript[] { + return this._scripts.getScriptByPath(nameOrLocation); + } } class CDTPCurrentGeneration { // We use these two maps instead of a bidirectional map because we need to map an ID to a Promise instead of a script, to avoid having race conditions... private readonly _cdtpIdByScript = new ValidatedMap>(); private readonly _scriptByCdtpId = new ValidatedMap(); + private readonly _scriptByPath = newResourceIdentifierMap(); public async registerNewScript(scriptId: CDTP.Runtime.ScriptId, obtainScript: () => Promise): Promise { const scriptWithConfigurationPromise = obtainScript().then(script => { @@ -70,6 +76,9 @@ class CDTPCurrentGeneration { private createScriptInitialConfiguration(scriptId: CDTP.Runtime.ScriptId, script: IScript): void { this._scriptByCdtpId.set(script, scriptId); + + let scriptsWithSamePath = this._scriptByPath.getOrAdd(script.runtimeSource.identifier, () => []); + scriptsWithSamePath.push(script); } public getCdtpId(script: IScript): CDTP.Runtime.ScriptId { @@ -83,4 +92,9 @@ class CDTPCurrentGeneration { public getAllScripts(): IterableIterator> { return this._cdtpIdByScript.values(); } + + public getScriptByPath(path: IResourceIdentifier): IScript[] { + const runtimeScript = this._scriptByPath.tryGetting(path); + return runtimeScript || []; + } } diff --git a/src/chrome/internal/sources/features/dotScriptsCommand.ts b/src/chrome/internal/sources/features/dotScriptsCommand.ts index 1e28ced04..000b1207d 100644 --- a/src/chrome/internal/sources/features/dotScriptsCommand.ts +++ b/src/chrome/internal/sources/features/dotScriptsCommand.ts @@ -4,10 +4,9 @@ import { BaseSourceMapTransformer } from '../../../../transformers/baseSourceMap import { IEventsToClientReporter } from '../../../client/eventSender'; import { determineOrderingOfStrings } from '../../../collections/utilities'; import { TYPES } from '../../../dependencyInjection.ts/types'; -import { IScriptSources } from '../../../target/cdtpDebugger'; -import { CDTPScriptsRegistry } from '../../../target/cdtpScriptsRegistry'; import { IScript } from '../../scripts/script'; import { IScriptSourcesRetriever } from '../../../cdtpDebuggee/features/CDTPScriptSourcesRetriever'; +import { CDTPScriptsRegistry } from '../../../cdtpDebuggee/registries/cdtpScriptsRegistry'; @injectable() export class DotScriptCommand { From ffad8979033fbf6665a08b46f4fc2dc7ea57f4cf Mon Sep 17 00:00:00 2001 From: digeff Date: Mon, 14 Jan 2019 09:43:20 -0800 Subject: [PATCH 07/23] Fix remove breakpoint --- src/chrome/cdtpDebuggee/cdtpPrimitives.ts | 4 +- .../features/cdtpDebuggeeBreakpoints.ts | 23 ++++++-- src/chrome/chromeConnection.ts | 2 +- src/chrome/client/clientToInternal.ts | 6 +- src/chrome/client/eventSender.ts | 3 +- src/chrome/client/internalToClient.ts | 12 ++-- .../internal/breakpoints/bpActionWhenHit.ts | 16 ++--- src/chrome/internal/breakpoints/bpRecipie.ts | 29 +++++++--- .../bpRecipieAtLoadedSourceLogic.ts | 25 ++++++-- src/chrome/internal/breakpoints/bpRecipies.ts | 2 +- .../breakpoints/bpsDeltaCalculator.ts | 58 ++++++------------- .../internal/breakpoints/breakpointsLogic.ts | 52 +++++++++-------- .../clientCurrentBPRecipiesRegistry.ts | 6 +- .../features/hitCountBreakpoints.ts | 16 ++--- .../registries/bpRecipieRegistry.ts | 29 ++++++++++ src/chrome/internal/features/skipFiles.ts | 12 ++-- src/chrome/internal/locations/location.ts | 27 +++++++-- src/chrome/internal/scripts/script.ts | 9 +-- src/chrome/internal/sources/loadedSource.ts | 8 +-- .../internal/sources/resourceIdentifier.ts | 7 ++- src/chrome/internal/sources/source.ts | 8 +-- .../internal/sources/unresolvedSource.ts | 9 +-- src/chrome/internalSourceBreakpoint.ts | 4 +- src/chrome/utils/equivalence.ts | 3 + src/utils.ts | 7 ++- 25 files changed, 233 insertions(+), 144 deletions(-) create mode 100644 src/chrome/internal/breakpoints/registries/bpRecipieRegistry.ts create mode 100644 src/chrome/utils/equivalence.ts diff --git a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts index 15b41a189..b2b9351e3 100644 --- a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts +++ b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts @@ -4,8 +4,10 @@ import { URLRegexp } from '../internal/locations/subtypes'; import { AlwaysBreak, ConditionalBreak } from '../internal/breakpoints/bpActionWhenHit'; import { URL } from '../internal/sources/resourceIdentifier'; import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; +import { IBreakpoint } from '../internal/breakpoints/breakpoint'; export type integer = number; export type CDTPSupportedResources = IScript | URL | URLRegexp; export type CDTPSupportedHitActions = AlwaysBreak | ConditionalBreak; -export type CDTPBPRecipie = IBPRecipie; \ No newline at end of file +export type CDTPBPRecipie = IBPRecipie; +export type CDTPBreakpoint = IBreakpoint; diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts index 721e774a9..82325cf13 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts @@ -2,7 +2,7 @@ import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp, BPRecipie, IBP import { AlwaysBreak, ConditionalBreak } from '../../internal/breakpoints/bpActionWhenHit'; import { BreakpointInScript, BreakpointInUrl, BreakpointInUrlRegexp, Breakpoint } from '../../internal/breakpoints/breakpoint'; import { RangeInScript } from '../../internal/locations/rangeInScript'; -import { LocationInScript } from '../../internal/locations/location'; +import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../../internal/locations/location'; import { Protocol as CDTP } from 'devtools-protocol'; import { TYPES } from '../../dependencyInjection.ts/types'; import { inject, injectable } from 'inversify'; @@ -14,16 +14,20 @@ import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagno import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; import { Coordinates } from '../../internal/locations/location'; import { singleOne } from '../../collections/utilities'; -import { CDTPSupportedResources, CDTPSupportedHitActions } from '../cdtpPrimitives'; +import { CDTPSupportedResources, CDTPSupportedHitActions, CDTPBreakpoint } from '../cdtpPrimitives'; +import { Listeners } from '../../communication/listeners'; type SetBPInCDTPCall = (resource: TResource, position: Coordinates, cdtpConditionField: string) => Promise; +export type OnBreakpointResolvedListener = (breakpoint: Breakpoint) => void; export interface IDebuggeeBreakpoints { setBreakpoint(bpRecipie: BPRecipieInScript): Promise; setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise; setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise; getPossibleBreakpoints(rangeInScript: RangeInScript): Promise; - removeBreakpoint(bpRecipie: BPRecipie): Promise; + removeBreakpoint(bpRecipie: IBPRecipie): Promise; + onBreakpointResolvedAsync(listener: OnBreakpointResolvedListener): void; + onBreakpointResolvedSyncOrAsync(listener: OnBreakpointResolvedListener): void; } interface BreakpointClass { @@ -36,7 +40,9 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< private readonly _cdtpLocationParser = new CDTPLocationParser(this._scriptsRegistry); - public readonly onBreakpointResolved = this.addApiListener('breakpointResolved', async (params: CDTP.Debugger.BreakpointResolvedEvent) => { + private readonly onBreakpointResolvedSyncOrAsyncListeners = new Listeners(); + + public readonly onBreakpointResolvedAsync = this.addApiListener('breakpointResolved', async (params: CDTP.Debugger.BreakpointResolvedEvent) => { const bpRecipie = this._breakpointIdRegistry.getRecipieByBreakpointId(params.breakpointId); const breakpoint = new Breakpoint(bpRecipie, await this.toLocationInScript(params.location)); @@ -50,6 +56,11 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< @inject(TYPES.IDomainsEnabler) domainsEnabler: CDTPDomainsEnabler, ) { super(domainsEnabler); + this.onBreakpointResolvedAsync(bp => this.onBreakpointResolvedSyncOrAsyncListeners.call(bp)); + } + + public onBreakpointResolvedSyncOrAsync(listener: (breakpoint: Breakpoint) => void): void { + this.onBreakpointResolvedSyncOrAsyncListeners.add(listener); } public async setBreakpoint(bpRecipie: BPRecipieInScript): Promise { @@ -92,7 +103,9 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< */ this._breakpointIdRegistry.registerRecipie(response.breakpointId, bpRecipie); - return Promise.all(response.locations.map(cdtpLocation => this.toBreakpoinInResource(classToUse, bpRecipie, cdtpLocation))); + const breakpoints = await Promise.all(response.locations.map(cdtpLocation => this.toBreakpoinInResource(classToUse, bpRecipie, cdtpLocation))); + breakpoints.forEach(bp => this.onBreakpointResolvedSyncOrAsyncListeners.call(bp)); + return breakpoints; } public async getPossibleBreakpoints(rangeInScript: RangeInScript): Promise { diff --git a/src/chrome/chromeConnection.ts b/src/chrome/chromeConnection.ts index 8a5421312..05905b351 100644 --- a/src/chrome/chromeConnection.ts +++ b/src/chrome/chromeConnection.ts @@ -10,7 +10,7 @@ import * as errors from '../errors'; import * as utils from '../utils'; import { logger } from 'vscode-debugadapter'; import { ChromeTargetDiscovery, TargetVersions } from './chromeTargetDiscoveryStrategy'; -import { Version } from "./utils/version"; +import { Version } from './utils/version'; import { Client } from 'noice-json-rpc'; diff --git a/src/chrome/client/clientToInternal.ts b/src/chrome/client/clientToInternal.ts index e26914109..1cd187bf6 100644 --- a/src/chrome/client/clientToInternal.ts +++ b/src/chrome/client/clientToInternal.ts @@ -1,5 +1,5 @@ import { ILoadedSource } from '../internal/sources/loadedSource'; -import { BPRecipieInUnresolvedSource } from '../internal/breakpoints/bpRecipie'; +import { BPRecipieInSource } from '../internal/breakpoints/bpRecipie'; import { DebugProtocol } from 'vscode-debugprotocol'; import { SourcesLogic } from '../internal/sources/sourcesLogic'; import { Coordinates, LocationInSource } from '../internal/locations/location'; @@ -62,8 +62,8 @@ export class ClientToInternal { return new BPRecipiesInUnresolvedSource(source, breakpoints); } - public toBPRecipie(source: ISource, clientBreakpoint: DebugProtocol.SourceBreakpoint): BPRecipieInUnresolvedSource { - return new BPRecipieInUnresolvedSource( + public toBPRecipie(source: ISource, clientBreakpoint: DebugProtocol.SourceBreakpoint): BPRecipieInSource { + return new BPRecipieInSource( new LocationInSource(source, this.toLocation(clientBreakpoint)), this.toBPActionWhenHit(clientBreakpoint)); } diff --git a/src/chrome/client/eventSender.ts b/src/chrome/client/eventSender.ts index ee108c6bf..9eb790cc1 100644 --- a/src/chrome/client/eventSender.ts +++ b/src/chrome/client/eventSender.ts @@ -7,9 +7,10 @@ import { LocationInLoadedSource } from '../internal/locations/location'; import { IBPRecipieStatus } from '../internal/breakpoints/bpRecipieStatus'; import { IFormattedExceptionLineDescription } from '../internal/formattedExceptionParser'; import { StoppedEvent2, ReasonType } from '../stoppedEvent'; -import { CDTP, ChromeDebugLogic } from '../..'; import { injectable, inject } from 'inversify'; import { TYPES } from '../dependencyInjection.ts/types'; +import { Protocol as CDTP } from 'devtools-protocol'; +import { ChromeDebugLogic } from '../chromeDebugAdapter'; export interface OutputParameters { readonly output: string; diff --git a/src/chrome/client/internalToClient.ts b/src/chrome/client/internalToClient.ts index ac09d6d93..bb75067fc 100644 --- a/src/chrome/client/internalToClient.ts +++ b/src/chrome/client/internalToClient.ts @@ -4,7 +4,6 @@ import * as pathModule from 'path'; import { asyncAdaptToSinglIntoToMulti } from '../../utils'; import { ILoadedSource, ILoadedSourceTreeNode } from '../internal/sources/loadedSource'; import { LocationInLoadedSource } from '../internal/locations/location'; -import { Source } from 'vscode-debugadapter'; import { RemoveProperty } from '../../typeUtils'; import { IBPRecipieStatus } from '../internal/breakpoints/bpRecipieStatus'; import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; @@ -14,6 +13,7 @@ import { IExceptionInformation } from '../internal/exceptions/pauseOnException'; import { IFormattedExceptionLineDescription } from '../internal/formattedExceptionParser'; import { injectable, inject } from 'inversify'; import { TYPES } from '../dependencyInjection.ts/types'; +import { Source } from 'vscode-debugadapter'; interface ClientLocationInSource { source: DebugProtocol.Source; @@ -66,10 +66,12 @@ export class InternalToClient { const exists = await utils.existsAsync(loadedSource.identifier.canonicalized); // if the path exists, do not send the sourceReference - const source = new Source( - pathModule.basename(loadedSource.identifier.textRepresentation), - loadedSource.identifier.textRepresentation, - exists ? undefined : this._handlesRegistry.sources.getIdByObject(loadedSource)); + // new Source sends 0 for undefined + const source: Source = { + name: pathModule.basename(loadedSource.identifier.textRepresentation), + path: loadedSource.identifier.textRepresentation, + sourceReference: exists ? undefined : this._handlesRegistry.sources.getIdByObject(loadedSource), + }; return source; } diff --git a/src/chrome/internal/breakpoints/bpActionWhenHit.ts b/src/chrome/internal/breakpoints/bpActionWhenHit.ts index bc304c707..db495abd8 100644 --- a/src/chrome/internal/breakpoints/bpActionWhenHit.ts +++ b/src/chrome/internal/breakpoints/bpActionWhenHit.ts @@ -1,5 +1,7 @@ -export interface IBPActionWhenHit { - isEquivalent(bpActionWhenHit: IBPActionWhenHit): boolean; +import { IEquivalenceComparable } from '../../utils/equivalence'; + +export interface IBPActionWhenHit extends IEquivalenceComparable { + isEquivalentTo(bpActionWhenHit: IBPActionWhenHit): boolean; basedOnTypeDo(actionBasedOnClass: { alwaysBreak?: (alwaysBreak: AlwaysBreak) => R, @@ -15,7 +17,7 @@ export interface IBPActionWhenHit { } export abstract class BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public abstract isEquivalent(bpActionWhenHit: IBPActionWhenHit): boolean; + public abstract isEquivalentTo(bpActionWhenHit: IBPActionWhenHit): boolean; basedOnTypeDo(actionBasedOnClass: { alwaysBreak?: (alwaysBreak: AlwaysBreak) => R, @@ -54,7 +56,7 @@ export abstract class BasedOnTypeDoCommonLogic implements IBPActionWhenHit { } export class AlwaysBreak extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public isEquivalent(otherBPActionWhenHit: IBPActionWhenHit): boolean { + public isEquivalentTo(otherBPActionWhenHit: IBPActionWhenHit): boolean { return otherBPActionWhenHit.isAlwaysBreak(); } @@ -68,7 +70,7 @@ export class AlwaysBreak extends BasedOnTypeDoCommonLogic implements IBPActionWh } export class ConditionalBreak extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public isEquivalent(otherBPActionWhenHit: IBPActionWhenHit): boolean { + public isEquivalentTo(otherBPActionWhenHit: IBPActionWhenHit): boolean { return otherBPActionWhenHit.isConditionalBreak() && otherBPActionWhenHit.expressionOfWhenToBreak === this.expressionOfWhenToBreak; } @@ -87,7 +89,7 @@ export class ConditionalBreak extends BasedOnTypeDoCommonLogic implements IBPAct } export class BreakOnHitCount extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public isEquivalent(otherBPActionWhenHit: IBPActionWhenHit): boolean { + public isEquivalentTo(otherBPActionWhenHit: IBPActionWhenHit): boolean { return otherBPActionWhenHit.isBreakOnHitCount() && otherBPActionWhenHit.pauseOnHitCondition === this.pauseOnHitCondition; } @@ -106,7 +108,7 @@ export class BreakOnHitCount extends BasedOnTypeDoCommonLogic implements IBPActi } export class LogMessage extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public isEquivalent(otherBPActionWhenHit: IBPActionWhenHit): boolean { + public isEquivalentTo(otherBPActionWhenHit: IBPActionWhenHit): boolean { return otherBPActionWhenHit.isLogMessage() && otherBPActionWhenHit.expressionToLog === this.expressionToLog; } diff --git a/src/chrome/internal/breakpoints/bpRecipie.ts b/src/chrome/internal/breakpoints/bpRecipie.ts index 2f78a274c..d50ec78c1 100644 --- a/src/chrome/internal/breakpoints/bpRecipie.ts +++ b/src/chrome/internal/breakpoints/bpRecipie.ts @@ -1,5 +1,5 @@ import { ISource } from '../sources/source'; -import { Location, ScriptOrSourceOrURLOrURLRegexp, LocationInUrl, LocationInUrlRegexp, LocationInScript } from '../locations/location'; +import { Location, ScriptOrSourceOrURLOrURLRegexp, LocationInUrl, LocationInUrlRegexp, LocationInScript, ILocation } from '../locations/location'; import { ILoadedSource } from '../sources/loadedSource'; import { IScript } from '../scripts/script'; import { IBPActionWhenHit, AlwaysBreak } from './bpActionWhenHit'; @@ -7,8 +7,10 @@ import { utils } from '../../..'; import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; import { IResourceIdentifier, URL } from '../sources/resourceIdentifier'; import { URLRegexp, createURLRegexp } from '../locations/subtypes'; +import { IEquivalenceComparable } from '../../utils/equivalence'; -export interface IBPRecipie { +export interface IBPRecipie + extends IEquivalenceComparable { readonly location: Location; readonly bpActionWhenHit: TBPActionWhenHit; @@ -35,6 +37,12 @@ abstract class UnmappedBPRecipieCommonLogic): boolean { + // TODO: Figure out how to remove the > casts + return (>this.location).isEquivalentTo(>right.location) + && this.bpActionWhenHit.isEquivalentTo(right.bpActionWhenHit); + } + constructor( location: Location, public readonly bpActionWhenHit: TBPActionWhenHit) { @@ -47,6 +55,11 @@ abstract class MappedBPRecipieCommonLogic): boolean { + return (>this.location).isEquivalentTo(>right.location) + && right.unmappedBPRecipie.isEquivalentTo(this.unmappedBPRecipie); + } + constructor(public readonly unmappedBPRecipie: IBPRecipie, public readonly location: Location) { } @@ -55,14 +68,14 @@ abstract class MappedBPRecipieCommonLogic extends UnmappedBPRecipieCommonLogic implements IBPRecipie { - public withAlwaysBreakAction(): BPRecipieInUnresolvedSource { - return new BPRecipieInUnresolvedSource(this.location, new AlwaysBreak()); +export class BPRecipieInSource extends UnmappedBPRecipieCommonLogic implements IBPRecipie { + public withAlwaysBreakAction(): BPRecipieInSource { + return new BPRecipieInSource(this.location, new AlwaysBreak()); } public tryResolvingSource( succesfulAction: (breakpointInLoadedSource: BPRecipieInLoadedSource) => R, - failedAction: (breakpointInUnbindedSource: BPRecipieInUnresolvedSource) => R): R { + failedAction: (breakpointInUnbindedSource: BPRecipieInSource) => R): R { return this.location.tryResolvingSource( locationInLoadedSource => succesfulAction(new BPRecipieInLoadedSource(this, locationInLoadedSource)), () => failedAction(this)); @@ -92,7 +105,7 @@ export type IBreakpointRecipieInUnbindedSource = IBPRecipie; // TODO: Are we missing the IBPActionWhenHit parameter here? export type BPRecipie = - TResource extends ISource ? BPRecipieInUnresolvedSource : + TResource extends ISource ? BPRecipieInSource : TResource extends ILoadedSource ? BPRecipieInLoadedSource : TResource extends IScript ? BPRecipieInScript : TResource extends IResourceIdentifier ? BPRecipieInUrl : @@ -107,7 +120,7 @@ export class BPRecipieInScript { - const urlRegexp = createURLRegexp(utils.pathToRegex(this.location.script.url)); + const urlRegexp = createURLRegexp(utils.pathToRegex(this.location.script.url, `${Math.random() * 100000000000000}`)); return new BPRecipieInUrlRegexp(this.unmappedBPRecipie, new LocationInUrlRegexp(urlRegexp, this.location.coordinates)); } diff --git a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts index f68558b74..81c9b1ef0 100644 --- a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts +++ b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts @@ -16,6 +16,8 @@ import { TYPES } from '../../dependencyInjection.ts/types'; import { InformationAboutPausedProvider, NotifyStoppedCommonLogic } from '../features/takeProperActionOnPausedEvent'; import { IEventsToClientReporter } from '../../client/eventSender'; import { ReasonType } from '../../stoppedEvent'; +import { CDTPBreakpoint } from '../../cdtpDebuggee/cdtpPrimitives'; +import { CDTPBPRecipiesRegistry } from './registries/bpRecipieRegistry'; export type Dummy = VoteRelevance; // If we don't do this the .d.ts doesn't include VoteRelevance and the compilation fails. Remove this when the issue disappears... @@ -61,21 +63,31 @@ export class BPRecipieAtLoadedSourceLogic implements IBreakpointsInLoadedSource const runtimeSource = bpInScriptRecipie.location.script.runtimeSource; this._breakpointRegistry.registerBPRecipie(bpRecipie); - let breakpoints: IBreakpoint[]; + let breakpoints: CDTPBreakpoint[]; if (!runtimeSource.doesScriptHasUrl()) { breakpoints = [await this._targetBreakpoints.setBreakpoint(bpRecipieInBestLocation)]; } else if (runtimeSource.identifier.isLocalFilePath()) { breakpoints = await this._targetBreakpoints.setBreakpointByUrlRegexp(bpRecipieInBestLocation.mappedToUrlRegexp()); - } else { // The script has a URL and it's not a local file path, so we can leave it as-is - breakpoints = await this._targetBreakpoints.setBreakpointByUrl(bpRecipieInBestLocation.mappedToUrl()); + } else { + /** + * The script has a URL and it's not a local file path, so we could leave it as-is. + * We transform it into a regexp to add a GUID to it, so CDTP will let us add the same breakpoint/recipie two times (using different guids). + * That way we can always add the new breakpoints for a file, before removing the old ones (except if the script doesn't have an URL) + */ + breakpoints = await this._targetBreakpoints.setBreakpointByUrlRegexp(bpRecipieInBestLocation.mappedToUrlRegexp()); } - breakpoints.forEach(breakpoint => this._breakpointRegistry.registerBreakpointAsBinded(breakpoint)); + breakpoints.forEach(breakpoint => { + this._breakpointRegistry.registerBreakpointAsBinded(breakpoint); + this._bpRecipiesRegistry.register(bpRecipie.unmappedBPRecipie, breakpoint.recipie); + }); + return breakpoints; } - public async removeBreakpoint(_bpRecipie: BPRecipie): Promise { - // TODO: Implement this method return this._targetBreakpoints.removeBreakpoint(bpRecipie); + public async removeBreakpoint(clientBPRecipie: BPRecipie): Promise { + const debuggeeBPRecipie = this._bpRecipiesRegistry.getDebuggeeBPRecipie(clientBPRecipie); + this._targetBreakpoints.removeBreakpoint(debuggeeBPRecipie); } private async considerColumnAndSelectBestBPLocation(location: LocationInScript): Promise { @@ -105,6 +117,7 @@ export class BPRecipieAtLoadedSourceLogic implements IBreakpointsInLoadedSource @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: BPRecipieAtLoadedSourceLogicDependencies, @inject(TYPES.IBreakpointFeaturesSupport) private readonly _breakpointFeaturesSupport: IBreakpointFeaturesSupport, private readonly _breakpointRegistry: BreakpointsRegistry, + private readonly _bpRecipiesRegistry: CDTPBPRecipiesRegistry, @inject(TYPES.ITargetBreakpoints) private readonly _targetBreakpoints: IDebuggeeBreakpoints, @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { this.doesTargetSupportColumnBreakpointsCached = this._breakpointFeaturesSupport.supportsColumnBreakpoints; diff --git a/src/chrome/internal/breakpoints/bpRecipies.ts b/src/chrome/internal/breakpoints/bpRecipies.ts index cd6fb49a7..4e8d1707e 100644 --- a/src/chrome/internal/breakpoints/bpRecipies.ts +++ b/src/chrome/internal/breakpoints/bpRecipies.ts @@ -8,7 +8,7 @@ export class BPRecipiesCommonLogic { constructor(public readonly resource: TResource, public readonly breakpoints: BPRecipie[]) { this.breakpoints.forEach(breakpoint => { const bpResource = breakpoint.location.resource; - if (!(bpResource as any).isEquivalent(this.resource)) { + if (!(bpResource).isEquivalentTo(this.resource)) { // TODO: Figure out a way to remove this any throw new Error(`Expected all the breakpoints to have source ${resource} yet the breakpoint ${breakpoint} had ${bpResource} as it's source`); } }); diff --git a/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts b/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts index e4c8539cb..0a655efcb 100644 --- a/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts +++ b/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts @@ -1,40 +1,31 @@ -import { BPRecipieInUnresolvedSource, BPRecipie } from './bpRecipie'; +import { BPRecipieInSource, BPRecipie } from './bpRecipie'; import { BPRecipiesInUnresolvedSource } from './bpRecipies'; import { ISource } from '../sources/source'; import { ILoadedSource } from '../sources/loadedSource'; import { IBPActionWhenHit } from './bpActionWhenHit'; import { SetUsingProjection } from '../../collections/setUsingProjection'; +import assert = require('assert'); -export class ReplacementForExistingBPR { - constructor( - public readonly existingBP: BPRecipieInUnresolvedSource, - public readonly replacement: BPRecipieInUnresolvedSource) { } -} - -function canonicalizeBPLocation(breakpoint: BPRecipieInUnresolvedSource): string { - return JSON.stringify({ - lineNumber: breakpoint.location.lineNumber, - columnNumber: breakpoint.location.columnNumber - }); +function canonicalizeBPLocation(breakpoint: BPRecipieInSource): string { + return `${breakpoint.location.lineNumber}:${breakpoint.location.columnNumber}[${breakpoint.bpActionWhenHit}]`; } export class BPRsDeltaCalculator { - private readonly _currentBPRecipies: SetUsingProjection; + private readonly _currentBPRecipies: SetUsingProjection; constructor( public readonly requestedSourceIdentifier: ISource, private readonly _requestedBPRecipies: BPRecipiesInUnresolvedSource, - currentBPRecipies: BPRecipieInUnresolvedSource[]) { + currentBPRecipies: BPRecipieInSource[]) { this._currentBPRecipies = new SetUsingProjection(canonicalizeBPLocation, currentBPRecipies); } public calculate(): BPRsDeltaInRequestedSource { const match = { - replacementsForExistingOnes: [] as ReplacementForExistingBPR[], // TODO DIEGO - matchesForRequested: [] as BPRecipieInUnresolvedSource[], // Every iteration we'll add either the existing BP match, or the new BP as it's own match here - requestedToAdd: [] as BPRecipieInUnresolvedSource[], // Every time we don't find an existing match BP, we'll add the desired BP here - existingToLeaveAsIs: [] as BPRecipieInUnresolvedSource[], // Every time we do find an existing match BP, we'll add the existing BP here - existingToRemove: [] as BPRecipieInUnresolvedSource[] // Calculated at the end of the algorithm by doing (existingBreakpoints - existingToLeaveAsIs) + matchesForRequested: [] as BPRecipieInSource[], // Every iteration we'll add either the existing BP match, or the new BP as it's own match here + requestedToAdd: [] as BPRecipieInSource[], // Every time we don't find an existing match BP, we'll add the desired BP here + existingToLeaveAsIs: [] as BPRecipieInSource[], // Every time we do find an existing match BP, we'll add the existing BP here + existingToRemove: [] as BPRecipieInSource[] // Calculated at the end of the algorithm by doing (existingBreakpoints - existingToLeaveAsIs) }; this._requestedBPRecipies.breakpoints.forEach(requestedBP => { @@ -42,13 +33,9 @@ export class BPRsDeltaCalculator { let matchingBreakpoint; if (existingMatch !== undefined) { - if (requestedBP.bpActionWhenHit.isEquivalent(existingMatch.bpActionWhenHit)) { - match.existingToLeaveAsIs.push(existingMatch); - matchingBreakpoint = existingMatch; - } else { - match.replacementsForExistingOnes.push(new ReplacementForExistingBPR(existingMatch, requestedBP)); - matchingBreakpoint = requestedBP; - } + assert(requestedBP.isEquivalentTo(existingMatch), `The existing match ${existingMatch} is expected to be equivalent to the requested BP ${requestedBP}`); + match.existingToLeaveAsIs.push(existingMatch); + matchingBreakpoint = existingMatch; } else { match.requestedToAdd.push(requestedBP); matchingBreakpoint = requestedBP; @@ -56,12 +43,12 @@ export class BPRsDeltaCalculator { match.matchesForRequested.push(matchingBreakpoint); }); - const setOfExistingToLeaveAsIs = new Set(match.existingToLeaveAsIs.concat(match.replacementsForExistingOnes.map(b => b.existingBP))); + const setOfExistingToLeaveAsIs = new Set(match.existingToLeaveAsIs); match.existingToRemove = Array.from(this._currentBPRecipies).filter(bp => !setOfExistingToLeaveAsIs.has(bp)); // Do some minor validations of the result just in case - const delta = new BPRsDeltaInRequestedSource(this.requestedSourceIdentifier, match.replacementsForExistingOnes, match.matchesForRequested, + const delta = new BPRsDeltaInRequestedSource(this.requestedSourceIdentifier, match.matchesForRequested, match.requestedToAdd, match.existingToRemove, match.existingToLeaveAsIs); this.validateResult(delta); return delta; @@ -73,11 +60,11 @@ export class BPRsDeltaCalculator { errorMessage += 'Expected the matches for desired breakpoints list to have the same length as the desired breakpoints list\n'; } - if (match.requestedToAdd.length + match.existingToLeaveAsIs.length + match.existingToBeReplaced.length !== this._requestedBPRecipies.breakpoints.length) { + if (match.requestedToAdd.length + match.existingToLeaveAsIs.length !== this._requestedBPRecipies.breakpoints.length) { errorMessage += 'Expected the desired breakpoints to add plus the existing breakpoints to leave as-is to have the same quantity as the total desired breakpoints\n'; } - if (match.existingToLeaveAsIs.length + match.existingToBeReplaced.length + match.existingToRemove.length !== this._currentBPRecipies.size) { + if (match.existingToLeaveAsIs.length + match.existingToRemove.length !== this._currentBPRecipies.size) { errorMessage += 'Expected the existing breakpoints to leave as-is plus the existing breakpoints to remove to have the same quantity as the total existing breakpoints\n'; } @@ -86,8 +73,7 @@ export class BPRsDeltaCalculator { matchesForRequested: this.printLocations(match.matchesForRequested), requestedToAdd: this.printLocations(match.requestedToAdd), existingToRemove: this.printLocations(match.existingToRemove), - existingToLeaveAsIs: this.printLocations(match.existingToLeaveAsIs), - existingToBeReplaced: this.printLocationsOfReplacements(match.existingToBeReplaced), + existingToLeaveAsIs: this.printLocations(match.existingToLeaveAsIs) }; const additionalDetails = `\nDesired breakpoints = ${JSON.stringify(this._requestedBPRecipies.breakpoints.map(canonicalizeBPLocation))}` @@ -97,12 +83,7 @@ export class BPRsDeltaCalculator { } } - private printLocationsOfReplacements(existingToBeReplaced: ReplacementForExistingBPR[]): string[] { - return existingToBeReplaced.map(rp => - `At ${rp.existingBP.location.coordinates} change <${rp.existingBP.bpActionWhenHit}> to <${rp.replacement.bpActionWhenHit}>`); - } - - private printLocations(bpRecipies: BPRecipieInUnresolvedSource[]): string[] { + private printLocations(bpRecipies: BPRecipieInSource[]): string[] { return bpRecipies.map(bpRecipie => `${bpRecipie.location.coordinates}`); } @@ -113,7 +94,6 @@ export class BPRsDeltaCalculator { export abstract class BPRsDeltaCommonLogic { constructor(public readonly resource: TResource, - public readonly existingToBeReplaced: ReplacementForExistingBPR[], public readonly matchesForRequested: BPRecipie[], public readonly requestedToAdd: BPRecipie[], public readonly existingToRemove: BPRecipie[], diff --git a/src/chrome/internal/breakpoints/breakpointsLogic.ts b/src/chrome/internal/breakpoints/breakpointsLogic.ts index 4d35db40a..5a2e629b3 100644 --- a/src/chrome/internal/breakpoints/breakpointsLogic.ts +++ b/src/chrome/internal/breakpoints/breakpointsLogic.ts @@ -1,7 +1,7 @@ import { AnyBPRecipie } from './bpRecipie'; import { ITelemetryPropertyCollector, IComponent, ConnectedCDAConfiguration } from '../../..'; import { ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; -import { BPRecipiesInUnresolvedSource } from './bpRecipies'; +import { BPRecipiesInUnresolvedSource, BPRecipiesInLoadedSource } from './bpRecipies'; import { Breakpoint } from './breakpoint'; import { ReAddBPsWhenSourceIsLoaded, EventsConsumedByReAddBPsWhenSourceIsLoaded } from './features/reAddBPsWhenSourceIsLoaded'; import { asyncMap } from '../../collections/async'; @@ -14,10 +14,8 @@ import { IEventsToClientReporter } from '../../client/eventSender'; import { PauseScriptLoadsToSetBPs, PauseScriptLoadsToSetBPsDependencies } from './features/pauseScriptLoadsToSetBPs'; import { inject, injectable } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; - -export interface IOnPausedResult { - didPause: boolean; -} +import { IDebuggeeBreakpoints } from '../../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; +import { BPRsDeltaInRequestedSource } from './bpsDeltaCalculator'; export interface InternalDependencies extends EventsConsumedByReAddBPsWhenSourceIsLoaded, @@ -37,7 +35,7 @@ export class BreakpointsLogic implements IComponent { private readonly _clientBreakpointsRegistry = new ClientCurrentBPRecipiesRegistry(); - protected onAsyncBreakpointResolved(breakpoint: Breakpoint): void { + protected onBreakpointResolved(breakpoint: Breakpoint): void { this._breakpointRegistry.registerBreakpointAsBinded(breakpoint); this.onUnbounBPRecipieIsNowBound(breakpoint.recipie); } @@ -51,28 +49,18 @@ export class BreakpointsLogic implements IComponent { const bpsDelta = this._clientBreakpointsRegistry.updateBPRecipiesAndCalculateDelta(requestedBPs); const requestedBPsToAdd = new BPRecipiesInUnresolvedSource(bpsDelta.resource, bpsDelta.requestedToAdd); bpsDelta.requestedToAdd.forEach(requestedBP => this._breakpointRegistry.registerBPRecipie(requestedBP)); - bpsDelta.existingToBeReplaced.forEach(existingToBeReplaced => this._breakpointRegistry.registerBPRecipie(existingToBeReplaced.replacement)); await requestedBPsToAdd.tryGettingBPsInLoadedSource( async requestedBPsToAddInLoadedSources => { // Match desired breakpoints to existing breakpoints - - await asyncMap(requestedBPsToAddInLoadedSources.breakpoints, async requestedBP => { - // DIEGO TODO: Do we need to do one breakpoint at a time to avoid issues on CDTP, or can we do them in parallel now that we use a different algorithm? - await this._bprInLoadedSourceLogic.addBreakpointAtLoadedSource(requestedBP); - }); - await Promise.all(bpsDelta.existingToRemove.map(async existingBPToRemove => { - await this._bprInLoadedSourceLogic.removeBreakpoint(existingBPToRemove); - })); - - await asyncMap(bpsDelta.existingToBeReplaced, async existingToBeReplaced => { - // TODO: There is a race condition between the remove and the add line. We cannot add first and remove second, because even though - // the breakpoints have a different condition, the target won't let you add two breakpoints to the same exact location. - // We need to investigate if we can make the new breakpoint using a pseudo-regexp to make the target think that they are on different locations - // and thus workaround this issue - await this._bprInLoadedSourceLogic.removeBreakpoint(existingToBeReplaced.existingBP); - await this._bprInLoadedSourceLogic.addBreakpointAtLoadedSource(existingToBeReplaced.replacement.resolvedToLoadedSource()); - }); + if (requestedBPsToAddInLoadedSources.resource.doesScriptHasUrl()) { + await this.addNewBreakpointsForFile(requestedBPsToAddInLoadedSources); + await this.removeDeletedBreakpointsFromFile(bpsDelta); + } else { + // TODO: We need to pause-update-resume the debugger here to avoid a race condition + await this.removeDeletedBreakpointsFromFile(bpsDelta); + await this.addNewBreakpointsForFile(requestedBPsToAddInLoadedSources); + } }, () => { const existingUnbindedBPs = bpsDelta.existingToLeaveAsIs.filter(bp => !this._breakpointRegistry.getStatusOfBPRecipie(bp).isVerified()); @@ -86,10 +74,24 @@ export class BreakpointsLogic implements IComponent { return bpsDelta.matchesForRequested.map(bpRecipie => this._breakpointRegistry.getStatusOfBPRecipie(bpRecipie)); } + private async removeDeletedBreakpointsFromFile(bpsDelta: BPRsDeltaInRequestedSource) { + await asyncMap(bpsDelta.existingToRemove, async (existingBPToRemove) => { + await this._bprInLoadedSourceLogic.removeBreakpoint(existingBPToRemove); + }); + } + + private async addNewBreakpointsForFile(requestedBPsToAddInLoadedSources: BPRecipiesInLoadedSource) { + await asyncMap(requestedBPsToAddInLoadedSources.breakpoints, async (requestedBP) => { + // DIEGO TODO: Do we need to do one breakpoint at a time to avoid issues on CDTP, or can we do them in parallel now that we use a different algorithm? + await this._bprInLoadedSourceLogic.addBreakpointAtLoadedSource(requestedBP); + }); + } + public install(): this { this._unbindedBreakpointsLogic.install(); this._bpsWhileLoadingLogic.install(); this._dependencies.onNoPendingBreakpoints(() => this._bpsWhileLoadingLogic.disableIfNeccesary()); + this._debuggeeBreakpoints.onBreakpointResolvedSyncOrAsync(breakpoint => this.onBreakpointResolved(breakpoint)); this._bprInLoadedSourceLogic.install(); return this.configure(); } @@ -106,7 +108,7 @@ export class BreakpointsLogic implements IComponent { @inject(TYPES.PauseScriptLoadsToSetBPs) private readonly _bpsWhileLoadingLogic: PauseScriptLoadsToSetBPs, @inject(TYPES.BPRecipieInLoadedSourceLogic) private readonly _bprInLoadedSourceLogic: BPRecipieAtLoadedSourceLogic, @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter, + @inject(TYPES.ITargetBreakpoints) private readonly _debuggeeBreakpoints: IDebuggeeBreakpoints, @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration) { - this._dependencies.onAsyncBreakpointResolved(breakpoint => this.onAsyncBreakpointResolved(breakpoint)); } } \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts b/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts index 59e50f8e7..d483fd243 100644 --- a/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts +++ b/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts @@ -1,11 +1,11 @@ import { BPRecipiesInUnresolvedSource } from './bpRecipies'; import { BPRsDeltaCalculator, BPRsDeltaInRequestedSource } from './bpsDeltaCalculator'; -import { BPRecipieInUnresolvedSource } from './bpRecipie'; +import { BPRecipieInSource } from './bpRecipie'; import { newResourceIdentifierMap, IResourceIdentifier } from '../sources/resourceIdentifier'; export class ClientCurrentBPRecipiesRegistry { - private readonly _requestedSourcePathToCurrentBPRecipies = newResourceIdentifierMap(); + private readonly _requestedSourcePathToCurrentBPRecipies = newResourceIdentifierMap(); public updateBPRecipiesAndCalculateDelta(requestedBPRecipies: BPRecipiesInUnresolvedSource): BPRsDeltaInRequestedSource { const bpsDelta = this.calculateBPSDeltaFromExistingBPs(requestedBPRecipies); @@ -13,7 +13,7 @@ export class ClientCurrentBPRecipiesRegistry { return bpsDelta; } - private registerCurrentBPRecipies(requestedSourceIdentifier: IResourceIdentifier, bpRecipies: BPRecipieInUnresolvedSource[]): void { + private registerCurrentBPRecipies(requestedSourceIdentifier: IResourceIdentifier, bpRecipies: BPRecipieInSource[]): void { this._requestedSourcePathToCurrentBPRecipies.setAndReplaceIfExist(requestedSourceIdentifier, Array.from(bpRecipies)); } diff --git a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts index 58f6926ad..6b0e0dcd7 100644 --- a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts +++ b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts @@ -1,5 +1,5 @@ import { IComponent } from '../../features/feature'; -import { BPRecipieInUnresolvedSource, AnyBPRecipie } from '../bpRecipie'; +import { BPRecipieInSource, AnyBPRecipie } from '../bpRecipie'; import { BreakOnHitCount } from '../bpActionWhenHit'; import { ValidatedMap } from '../../../collections/validatedMap'; import { HitCountConditionParser, HitCountConditionFunction } from '../hitCountConditionParser'; @@ -12,11 +12,11 @@ import { TYPES } from '../../../dependencyInjection.ts/types'; import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; export interface HitCountBreakpointsDependencies { - registerAddBPRecipieHandler(handlerRequirements: (bpRecipie: BPRecipieInUnresolvedSource) => boolean, - handler: (bpRecipie: BPRecipieInUnresolvedSource) => Promise): void; + registerAddBPRecipieHandler(handlerRequirements: (bpRecipie: BPRecipieInSource) => boolean, + handler: (bpRecipie: BPRecipieInSource) => Promise): void; - addBPRecipie(bpRecipie: BPRecipieInUnresolvedSource): Promise; - notifyBPWasHit(bpRecipie: BPRecipieInUnresolvedSource): Promise; + addBPRecipie(bpRecipie: BPRecipieInSource): Promise; + notifyBPWasHit(bpRecipie: BPRecipieInSource): Promise; subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; publishGoingToPauseClient(): void; @@ -32,7 +32,7 @@ class HitCountBPData { } constructor( - public readonly hitBPRecipie: BPRecipieInUnresolvedSource, + public readonly hitBPRecipie: BPRecipieInSource, private readonly _shouldPauseCondition: HitCountConditionFunction) { } } @@ -54,11 +54,11 @@ export class HitCountBreakpoints implements IComponent { public install(): void { this._dependencies.registerAddBPRecipieHandler( bpRecipie => bpRecipie.bpActionWhenHit.isBreakOnHitCount(), - bpRecipie => this.addBPRecipie(bpRecipie as BPRecipieInUnresolvedSource)); + bpRecipie => this.addBPRecipie(bpRecipie as BPRecipieInSource)); this._dependencies.subscriberForAskForInformationAboutPaused(paused => this.askForInformationAboutPaused(paused)); } - private async addBPRecipie(bpRecipie: BPRecipieInUnresolvedSource): Promise { + private async addBPRecipie(bpRecipie: BPRecipieInSource): Promise { const underlyingBPRecipie = bpRecipie.withAlwaysBreakAction(); const shouldPauseCondition = new HitCountConditionParser(bpRecipie.bpActionWhenHit.pauseOnHitCondition).parse(); this._dependencies.addBPRecipie(underlyingBPRecipie); diff --git a/src/chrome/internal/breakpoints/registries/bpRecipieRegistry.ts b/src/chrome/internal/breakpoints/registries/bpRecipieRegistry.ts new file mode 100644 index 000000000..c884490c5 --- /dev/null +++ b/src/chrome/internal/breakpoints/registries/bpRecipieRegistry.ts @@ -0,0 +1,29 @@ +import { injectable } from 'inversify'; +import { ISource } from '../../sources/source'; +import { IBPRecipie } from '../bpRecipie'; +import { CDTPBPRecipie } from '../../../cdtpDebuggee/cdtpPrimitives'; +import { BidirectionalMap } from '../../../collections/bidirectionalMap'; + +type ClientBPRecipie = IBPRecipie; +type DebuggeeBPRecipie = CDTPBPRecipie; + +@injectable() +export class CDTPBPRecipiesRegistry { + private readonly _clientRecipieToDebuggeeRecipie = new BidirectionalMap(); + + public register(clientBPRecipie: ClientBPRecipie, debuggeeBPRecipie: DebuggeeBPRecipie): void { + this._clientRecipieToDebuggeeRecipie.set(clientBPRecipie, debuggeeBPRecipie); + } + + public unregister(clientBPRecipie: ClientBPRecipie): void { + this._clientRecipieToDebuggeeRecipie.deleteByLeft(clientBPRecipie); + } + + public getDebuggeeBPRecipie(clientBPRecipie: ClientBPRecipie): DebuggeeBPRecipie { + return this._clientRecipieToDebuggeeRecipie.getByLeft(clientBPRecipie); + } + + public toString(): string { + return `Client to Debuggee BP Recipies: ${this._clientRecipieToDebuggeeRecipie}`; + } +} diff --git a/src/chrome/internal/features/skipFiles.ts b/src/chrome/internal/features/skipFiles.ts index 573ef0682..b08f00518 100644 --- a/src/chrome/internal/features/skipFiles.ts +++ b/src/chrome/internal/features/skipFiles.ts @@ -1,8 +1,8 @@ -import { IToggleSkipFileStatusArgs, utils, CDTP, BaseSourceMapTransformer, parseResourceIdentifier, ConnectedCDAConfiguration } from '../../..'; +import { Protocol as CDTP } from 'devtools-protocol'; import { logger } from 'vscode-debugadapter/lib/logger'; import { IScript } from '../scripts/script'; import { StackTracesLogic, IStackTracePresentationLogicProvider } from '../stackTraces/stackTracesLogic'; -import { newResourceIdentifierMap, IResourceIdentifier } from '../sources/resourceIdentifier'; +import { newResourceIdentifierMap, IResourceIdentifier, parseResourceIdentifier } from '../sources/resourceIdentifier'; import { IComponent } from './feature'; import { LocationInLoadedSource } from '../locations/location'; import { ICallFramePresentationDetails } from '../stackTraces/callFramePresentation'; @@ -12,6 +12,10 @@ import { TYPES } from '../../dependencyInjection.ts/types'; import { ClientToInternal } from '../../client/clientToInternal'; import { ScriptParsedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; import { IBlackboxPatternsConfigurer } from '../../cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer'; +import { IToggleSkipFileStatusArgs } from '../../../debugAdapterInterfaces'; +import * as utils from '../../../utils'; +import { BaseSourceMapTransformer } from '../../../transformers/baseSourceMapTransformer'; +import { ConnectedCDAConfiguration } from '../../client/chromeDebugAdapter/cdaConfiguration'; const localize = nls.loadMessageBundle(); export interface EventsConsumedBySkipFilesLogic { @@ -149,7 +153,7 @@ export class SkipFilesLogic implements IComponent, ISta return currentStack.stackFrames.some(frame => { return frame.hasCodeFlow() && frame.codeFlow.location.source - && frame.codeFlow.location.source.isEquivalent(resolvedSource); + && frame.codeFlow.location.source.isEquivalentTo(resolvedSource); }); }, @@ -189,7 +193,7 @@ export class SkipFilesLogic implements IComponent, ISta if ((isSkippedFile && !inLibRange) || (!isSkippedFile && inLibRange)) { const details = await this.sourceMapTransformer.allSourcePathDetails(mappedUrl.canonicalized); - const detail = details.find(d => parseResourceIdentifier(d.inferredPath).isEquivalent(s)); + const detail = details.find(d => parseResourceIdentifier(d.inferredPath).isEquivalentTo(s)); libPositions.push({ lineNumber: detail.startPosition.line, columnNumber: detail.startPosition.column diff --git a/src/chrome/internal/locations/location.ts b/src/chrome/internal/locations/location.ts index 1244f3f39..a6c6cb9bd 100644 --- a/src/chrome/internal/locations/location.ts +++ b/src/chrome/internal/locations/location.ts @@ -6,11 +6,12 @@ import { logger } from 'vscode-debugadapter'; import { ColumnNumber, LineNumber, URLRegexp } from './subtypes'; import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; import { IResourceIdentifier, parseResourceIdentifier, URL } from '../sources/resourceIdentifier'; +import { IEquivalenceComparable } from '../../utils/equivalence'; export type integer = number; -export class Coordinates { - public isSameAs(location: Coordinates): boolean { +export class Coordinates implements IEquivalenceComparable { + public isEquivalentTo(location: Coordinates): boolean { return this.lineNumber === location.lineNumber && this.columnNumber === location.columnNumber; } @@ -31,11 +32,13 @@ export class Coordinates { } } -interface ILocation { +export interface ILocation extends IEquivalenceComparable { readonly lineNumber: integer; readonly columnNumber?: integer; readonly coordinates: Coordinates; readonly resource: T; + + isEquivalentTo(right: this): boolean; } export type ScriptOrSourceOrURLOrURLRegexp = IScript | ILoadedSource | ISource | URLRegexp | URL; @@ -46,7 +49,7 @@ export type Location = T extends IScript ? LocationInScript : // Used when receiving locations from the debugee T extends URLRegexp ? LocationInUrlRegexp : // Used when setting a breakpoint by URL in a local file path in windows, to make it case insensitive T extends URL ? LocationInUrl : // Used when setting a breakpoint by URL for case-insensitive URLs - never; + ILocation; // TODO: Figure out how to replace this by never (We run into some issues with the isEquivalentTo call if we do) abstract class LocationCommonLogic implements ILocation { public get lineNumber(): LineNumber { @@ -57,6 +60,18 @@ abstract class LocationCommonLogic imp return this.coordinates.columnNumber; } + public isEquivalentTo(right: this): boolean { + if (this.coordinates.isEquivalentTo(right.coordinates)) { + if (typeof this.resource === 'string' || typeof right.resource === 'string') { + return this.resource === right.resource; + } else { + return (this.resource).isEquivalentTo(right.resource); // TODO: Make this any safer + } + return true; + } + return false; + } + public toString(): string { return `${this.resource}:${this.coordinates}`; } @@ -80,7 +95,7 @@ export class LocationInSource extends LocationCommonLogic implements IL } public resolvedWith(loadedSource: ILoadedSource): LocationInLoadedSource { - if (this.resource.sourceIdentifier.isEquivalent(loadedSource.identifier)) { + if (this.resource.sourceIdentifier.isEquivalentTo(loadedSource.identifier)) { return new LocationInLoadedSource(loadedSource, this.coordinates); } else { throw new Error(`Can't resolve a location with a source (${this}) to a location with a loaded source that doesn't match the unresolved source: ${loadedSource}`); @@ -115,7 +130,7 @@ export class LocationInScript extends LocationCommonLogic implements IL public isSameAs(locationInScript: LocationInScript): boolean { return this.script === locationInScript.script && - this.coordinates.isSameAs(locationInScript.coordinates); + this.coordinates.isEquivalentTo(locationInScript.coordinates); } public toString(): string { diff --git a/src/chrome/internal/scripts/script.ts b/src/chrome/internal/scripts/script.ts index 6182a7d78..c2c6be837 100644 --- a/src/chrome/internal/scripts/script.ts +++ b/src/chrome/internal/scripts/script.ts @@ -10,11 +10,12 @@ import { ISourcesMapper } from './sourcesMapper'; import { IResourceIdentifier, IResourceLocation, newResourceIdentifierMap, parseResourceIdentifier, ResourceName } from '../sources/resourceIdentifier'; import { IExecutionContext } from './executionContext'; import { Lazy1 } from '../../utils/lazy'; +import { IEquivalenceComparable } from '../../utils/equivalence'; /** This interface represents a piece of code that is being executed in the debugee. Usually a script matches to a file or a url, but that is not always the case. * This interface solves the problem of finding the different loaded sources associated with a script, and being able to identify and compare both scripts and sources easily. */ -export interface IScript { +export interface IScript extends IEquivalenceComparable { readonly executionContext: IExecutionContext; readonly runtimeSource: ILoadedSource; // Source in Webserver readonly developmentSource: ILoadedSource; // Source in Workspace @@ -26,7 +27,7 @@ export interface IScript { getSource(sourceIdentifier: IResourceIdentifier): ILoadedSource; - isEquivalent(source: IScript): boolean; + isEquivalentTo(script: IScript): boolean; } export class Script implements IScript { @@ -51,7 +52,7 @@ export class Script implements IScript { */ let runtimeSource: (script: IScript) => ILoadedSource; let developmentSource: (script: IScript) => ILoadedSource; - if (locationInRuntimeEnvironment.isEquivalent(locationInDevelopmentEnvinronment) || locationInDevelopmentEnvinronment.textRepresentation === '') { + if (locationInDevelopmentEnvinronment.isEquivalentTo(locationInRuntimeEnvironment) || locationInDevelopmentEnvinronment.textRepresentation === '') { if (fs.existsSync(locationInRuntimeEnvironment.textRepresentation)) { developmentSource = runtimeSource = new Lazy1((script: IScript) => // Using Lazy1 will ensure both calls return the same instance new ScriptRunFromLocalStorage(script, locationInRuntimeEnvironment, 'TODO DIEGO')).function; @@ -109,7 +110,7 @@ export class Script implements IScript { return this._runtimeSource.identifier.textRepresentation; } - public isEquivalent(script: Script): boolean { + public isEquivalentTo(script: Script): boolean { return this === script; } diff --git a/src/chrome/internal/sources/loadedSource.ts b/src/chrome/internal/sources/loadedSource.ts index 8d8d2bc42..fe30ae419 100644 --- a/src/chrome/internal/sources/loadedSource.ts +++ b/src/chrome/internal/sources/loadedSource.ts @@ -2,17 +2,17 @@ import { IScript } from '../scripts/script'; import { CDTPScriptUrl } from './resourceIdentifierSubtypes'; import { IResourceIdentifier, parseResourceIdentifier, ResourceName } from './resourceIdentifier'; import { determineOrderingOfStrings } from '../../collections/utilities'; +import { IEquivalenceComparable } from '../../utils/equivalence'; /** This interface represents a source or text that is related to a script that the debugee is executing. The text can be the contents of the script itself, * or a file from which the script was loaded, or a file that was compiled to generate the contents of the script */ -export interface ILoadedSource { +export interface ILoadedSource extends IEquivalenceComparable { readonly script: IScript; readonly identifier: IResourceIdentifier; readonly origin: string; doesScriptHasUrl(): boolean; // TODO DIEGO: Figure out if we can delete this property isMappedSource(): boolean; - isEquivalent(source: ILoadedSource): boolean; } /** @@ -33,7 +33,7 @@ abstract class LoadedSourceWithURLCommonLogic implements ILoad return true; } - public isEquivalent(source: ILoadedSource): boolean { + public isEquivalentTo(source: ILoadedSource): boolean { return this === source; } @@ -70,7 +70,7 @@ export class NoURLScriptSource implements ILoadedSource { return false; } - public isEquivalent(source: NoURLScriptSource): boolean { + public isEquivalentTo(source: NoURLScriptSource): boolean { return this === source; } diff --git a/src/chrome/internal/sources/resourceIdentifier.ts b/src/chrome/internal/sources/resourceIdentifier.ts index 3e0bf9a71..05236d9e9 100644 --- a/src/chrome/internal/sources/resourceIdentifier.ts +++ b/src/chrome/internal/sources/resourceIdentifier.ts @@ -2,6 +2,7 @@ import * as path from 'path'; import { utils } from '../../..'; import { IValidatedMap } from '../../collections/validatedMap'; import { MapUsingProjection } from '../../collections/mapUsingProjection'; +import { IEquivalenceComparable } from '../../utils/equivalence'; /** Hierarchy: * IResourceIdentifier: Identifies a resource @@ -17,17 +18,17 @@ import { MapUsingProjection } from '../../collections/mapUsingProjection'; */ /** This interface represents a text to identify a particular resource. This class will properly compare urls and file paths, while preserving the original case that was used for the identifier */ -export interface IResourceIdentifier { +export interface IResourceIdentifier extends IEquivalenceComparable { readonly textRepresentation: TString; readonly canonicalized: string; - isEquivalent(right: IResourceIdentifier): boolean; + isEquivalentTo(right: IResourceIdentifier): boolean; isLocalFilePath(): boolean; } abstract class IsEquivalentCommonLogic { public abstract get canonicalized(): string; - public isEquivalent(right: IResourceIdentifier): boolean { + public isEquivalentTo(right: IResourceIdentifier): boolean { return this.canonicalized === right.canonicalized; } diff --git a/src/chrome/internal/sources/source.ts b/src/chrome/internal/sources/source.ts index 7a266304e..3b7845c1b 100644 --- a/src/chrome/internal/sources/source.ts +++ b/src/chrome/internal/sources/source.ts @@ -1,14 +1,14 @@ import { IResourceIdentifier } from './resourceIdentifier'; import { ILoadedSource } from './loadedSource'; import { SourceResolver } from './sourceResolver'; +import { IEquivalenceComparable } from '../../utils/equivalence'; /** * VS Code debug protocol sends breakpoint requests with a path?: string; or sourceReference?: number; Before we can use the path, we need to wait for the related script to be loaded so we can match it with a script id. * This set of classes will let us represent the information we get from either a path or a sourceReference, and then let us try to resolve it to a script id when possible. */ -export interface ISource { +export interface ISource extends IEquivalenceComparable { readonly sourceIdentifier: IResourceIdentifier; - isEquivalent(right: ISource): boolean; tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, failedAction: (sourceIdentifier: IResourceIdentifier) => R): R; } @@ -16,8 +16,8 @@ abstract class SourceCommonLogic implements ISource { public abstract tryResolving(succesfulAction: (loadedSource: ILoadedSource) => R, failedAction: (identifier: IResourceIdentifier) => R): R; public abstract get sourceIdentifier(): IResourceIdentifier; - public isEquivalent(right: ISource): boolean { - return this.sourceIdentifier.isEquivalent(right.sourceIdentifier); + public isEquivalentTo(right: ISource): boolean { + return this.sourceIdentifier.isEquivalentTo(right.sourceIdentifier); } } diff --git a/src/chrome/internal/sources/unresolvedSource.ts b/src/chrome/internal/sources/unresolvedSource.ts index dac05a6a9..982be4112 100644 --- a/src/chrome/internal/sources/unresolvedSource.ts +++ b/src/chrome/internal/sources/unresolvedSource.ts @@ -1,10 +1,11 @@ import { IResourceIdentifier } from './resourceIdentifier'; import { ILoadedSource } from './loadedSource'; import { SourceResolver } from './sourceResolver'; +import { IEquivalenceComparable } from '../../utils/equivalence'; -export interface IUnresolvedSource { +export interface IUnresolvedSource extends IEquivalenceComparable { readonly sourceIdentifier: IResourceIdentifier; - isEquivalent(right: IUnresolvedSource): boolean; + isEquivalentTo(right: IUnresolvedSource): boolean; tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, failedAction: (sourceIdentifier: IResourceIdentifier) => R): R; } @@ -12,8 +13,8 @@ abstract class UnresolvedSourceCommonLogic implements IUnresolvedSource { public abstract tryResolving(succesfulAction: (loadedSource: ILoadedSource) => R, failedAction: (identifier: IResourceIdentifier) => R): R; public abstract get sourceIdentifier(): IResourceIdentifier; - public isEquivalent(right: IUnresolvedSource): boolean { - return this.sourceIdentifier.isEquivalent(right.sourceIdentifier); + public isEquivalentTo(right: IUnresolvedSource): boolean { + return this.sourceIdentifier.isEquivalentTo(right.sourceIdentifier); } } diff --git a/src/chrome/internalSourceBreakpoint.ts b/src/chrome/internalSourceBreakpoint.ts index beb252b26..0267bba06 100644 --- a/src/chrome/internalSourceBreakpoint.ts +++ b/src/chrome/internalSourceBreakpoint.ts @@ -6,6 +6,7 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { IScript } from './internal/scripts/script'; import { CodeFlowStackTrace } from './internal/stackTraces/stackTrace'; import { parseResourceIdentifier } from './internal/sources/resourceIdentifier'; +import { createCDTPScriptUrl } from './internal/sources/resourceIdentifierSubtypes'; export class InternalSourceBreakpoint { static readonly LOGPOINT_URL = 'vscode.logpoint.js'; @@ -32,7 +33,8 @@ export class InternalSourceBreakpoint { } function isLogpointStack(stackTrace: CodeFlowStackTrace | null): boolean { - return stackTrace && stackTrace.codeFlowFrames.length > 0 && stackTrace.codeFlowFrames[0].script.runtimeSource.identifier.isEquivalent(parseResourceIdentifier(InternalSourceBreakpoint.LOGPOINT_URL)); + return stackTrace && stackTrace.codeFlowFrames.length > 0 + && stackTrace.codeFlowFrames[0].script.runtimeSource.identifier.isEquivalentTo(parseResourceIdentifier(createCDTPScriptUrl(InternalSourceBreakpoint.LOGPOINT_URL))); } export function stackTraceWithoutLogpointFrame(stackTrace: CodeFlowStackTrace): CodeFlowStackTrace { diff --git a/src/chrome/utils/equivalence.ts b/src/chrome/utils/equivalence.ts new file mode 100644 index 000000000..087c58423 --- /dev/null +++ b/src/chrome/utils/equivalence.ts @@ -0,0 +1,3 @@ +export interface IEquivalenceComparable { + isEquivalentTo(right: this): boolean; +} \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 4a8b93a54..2e8bb8987 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -488,7 +488,7 @@ export class ReverseHandles extends Handles { /** * Return a regex for the given path to set a breakpoint on */ -export function pathToRegex(aPath: string): string { +export function pathToRegex(aPath: string, guid = ''): string { const fileUrlPrefix = 'file:///'; const isFileUrl = aPath.startsWith(fileUrlPrefix); const isAbsolutePath = isAbsolute(aPath); @@ -522,6 +522,11 @@ export function pathToRegex(aPath: string): string { aPath = escapeRegexSpecialChars(fileUrlPrefix) + aPath; } + if (guid) { + // Add a guid to the regexp to make it unique, without modifying what it matches. This will allow us to add duplicated breakpoints using CDTP + aPath = aPath + `(?:${guid}){0}`; + } + return aPath; } From 7f97c12becf0af85fdd387552cb40df48cbe3ac6 Mon Sep 17 00:00:00 2001 From: digeff Date: Mon, 14 Jan 2019 09:43:20 -0800 Subject: [PATCH 08/23] Fix remove breakpoint --- .../features/cdtpDebuggeeBreakpoints.ts | 2 +- .../bpRecipieAtLoadedSourceLogic.ts | 2 +- .../internal/breakpoints/breakpointsLogic.ts | 10 ++++++---- .../breakpoints/breakpointsRegistry.ts | 18 +++++++++--------- src/index.ts | 2 -- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts index 82325cf13..4810472a0 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts @@ -18,7 +18,7 @@ import { CDTPSupportedResources, CDTPSupportedHitActions, CDTPBreakpoint } from import { Listeners } from '../../communication/listeners'; type SetBPInCDTPCall = (resource: TResource, position: Coordinates, cdtpConditionField: string) => Promise; -export type OnBreakpointResolvedListener = (breakpoint: Breakpoint) => void; +export type OnBreakpointResolvedListener = (breakpoint: CDTPBreakpoint) => void; export interface IDebuggeeBreakpoints { setBreakpoint(bpRecipie: BPRecipieInScript): Promise; diff --git a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts index 81c9b1ef0..8406fcabb 100644 --- a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts +++ b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts @@ -61,7 +61,7 @@ export class BPRecipieAtLoadedSourceLogic implements IBreakpointsInLoadedSource const bpRecipieInBestLocation = bpInScriptRecipie.withLocationReplaced(bestLocation); const runtimeSource = bpInScriptRecipie.location.script.runtimeSource; - this._breakpointRegistry.registerBPRecipie(bpRecipie); + this._breakpointRegistry.registerBPRecipie(bpRecipie.unmappedBPRecipie); let breakpoints: CDTPBreakpoint[]; if (!runtimeSource.doesScriptHasUrl()) { diff --git a/src/chrome/internal/breakpoints/breakpointsLogic.ts b/src/chrome/internal/breakpoints/breakpointsLogic.ts index 5a2e629b3..78f7028b7 100644 --- a/src/chrome/internal/breakpoints/breakpointsLogic.ts +++ b/src/chrome/internal/breakpoints/breakpointsLogic.ts @@ -1,4 +1,4 @@ -import { AnyBPRecipie } from './bpRecipie'; +import { IBPRecipie } from './bpRecipie'; import { ITelemetryPropertyCollector, IComponent, ConnectedCDAConfiguration } from '../../..'; import { ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; import { BPRecipiesInUnresolvedSource, BPRecipiesInLoadedSource } from './bpRecipies'; @@ -16,6 +16,8 @@ import { inject, injectable } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { IDebuggeeBreakpoints } from '../../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; import { BPRsDeltaInRequestedSource } from './bpsDeltaCalculator'; +import { CDTPBreakpoint } from '../../cdtpDebuggee/cdtpPrimitives'; +import { ISource } from '../sources/source'; export interface InternalDependencies extends EventsConsumedByReAddBPsWhenSourceIsLoaded, @@ -35,12 +37,12 @@ export class BreakpointsLogic implements IComponent { private readonly _clientBreakpointsRegistry = new ClientCurrentBPRecipiesRegistry(); - protected onBreakpointResolved(breakpoint: Breakpoint): void { + protected onBreakpointResolved(breakpoint: CDTPBreakpoint): void { this._breakpointRegistry.registerBreakpointAsBinded(breakpoint); - this.onUnbounBPRecipieIsNowBound(breakpoint.recipie); + this.onUnbounBPRecipieIsNowBound(breakpoint.recipie.unmappedBPRecipie); } - private onUnbounBPRecipieIsNowBound(bpRecipie: AnyBPRecipie): void { + private onUnbounBPRecipieIsNowBound(bpRecipie: IBPRecipie): void { const bpRecipieStatus = this._breakpointRegistry.getStatusOfBPRecipie(bpRecipie); this._eventsToClientReporter.sendBPStatusChanged({ reason: 'changed', bpRecipieStatus }); } diff --git a/src/chrome/internal/breakpoints/breakpointsRegistry.ts b/src/chrome/internal/breakpoints/breakpointsRegistry.ts index 14204593e..4609ec654 100644 --- a/src/chrome/internal/breakpoints/breakpointsRegistry.ts +++ b/src/chrome/internal/breakpoints/breakpointsRegistry.ts @@ -1,25 +1,25 @@ import { IBPRecipieStatus, BPRecipieIsBinded, BPRecipieIsUnbinded } from './bpRecipieStatus'; -import { IBreakpoint } from './breakpoint'; import { ValidatedMultiMap } from '../../collections/validatedMultiMap'; -import { BPRecipie, AnyBPRecipie } from './bpRecipie'; -import { ScriptOrSourceOrURLOrURLRegexp, LocationInScript } from '../locations/location'; +import { IBPRecipie } from './bpRecipie'; +import { LocationInScript } from '../locations/location'; import { injectable } from 'inversify'; +import { CDTPBreakpoint } from '../../cdtpDebuggee/cdtpPrimitives'; +import { ISource } from '../sources/source'; @injectable() export class BreakpointsRegistry { // TODO DIEGO: Figure out how to handle if two breakpoint rules set a breakpoint in the same location so it ends up being the same breakpoint id - private readonly _unmappedRecipieToBreakpoints = new ValidatedMultiMap>(); + private readonly _unmappedRecipieToBreakpoints = new ValidatedMultiMap, CDTPBreakpoint>(); - public registerBPRecipie(bpRecipie: BPRecipie): void { + public registerBPRecipie(bpRecipie: IBPRecipie): void { this._unmappedRecipieToBreakpoints.addKeyIfNotExistant(bpRecipie); } - public registerBreakpointAsBinded(bp: IBreakpoint): void { + public registerBreakpointAsBinded(bp: CDTPBreakpoint): void { this._unmappedRecipieToBreakpoints.add(bp.recipie.unmappedBPRecipie, bp); } - public getStatusOfBPRecipie(bpRecipie: AnyBPRecipie): IBPRecipieStatus { + public getStatusOfBPRecipie(bpRecipie: IBPRecipie): IBPRecipieStatus { const breakpoints = this._unmappedRecipieToBreakpoints.get(bpRecipie); if (breakpoints.size > 0) { return new BPRecipieIsBinded(bpRecipie, Array.from(breakpoints), 'TODO DIEGO'); @@ -28,7 +28,7 @@ export class BreakpointsRegistry { } } - public tryGettingBreakpointAtLocation(locationInScript: LocationInScript): IBreakpoint[] { + public tryGettingBreakpointAtLocation(locationInScript: LocationInScript): CDTPBreakpoint[] { // TODO DIEGO: Figure out if we need a faster algorithm for this const matchinbBps = []; for (const bps of this._unmappedRecipieToBreakpoints.values()) { diff --git a/src/index.ts b/src/index.ts index 81e0269d7..9c3866a90 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,7 +32,6 @@ import * as executionTimingsReporter from './executionTimingsReporter'; import { Protocol as CDTP } from 'devtools-protocol'; import { TargetVersions } from './chrome/chromeTargetDiscoveryStrategy'; import { Version } from "./chrome/utils/version"; -import { IOnPausedResult } from './chrome/internal/breakpoints/breakpointsLogic'; import { parseResourceIdentifier } from './chrome/internal/sources/resourceIdentifier'; import { ChromeDebugAdapter } from './chrome/client/chromeDebugAdapter/chromeDebugAdapterV2'; import { IExtensibilityPoints, OnlyProvideCustomLauncherExtensibilityPoints } from './chrome/extensibility/extensibilityPoints'; @@ -56,7 +55,6 @@ export { chromeConnection, ChromeDebugLogic, ChromeDebugSession, - IOnPausedResult, IChromeDebugSessionOpts, chromeTargetDiscoveryStrategy, chromeUtils, From 3ef980e2e6dfffeaf5af06020e162eb9bc3f0310 Mon Sep 17 00:00:00 2001 From: D Date: Tue, 15 Jan 2019 12:37:28 -0800 Subject: [PATCH 09/23] Clean-up the stack traces model --- .../cdtpConsoleEventsProvider.ts | 5 +- .../cdtpDebuggeeExecutionEventsProvider.ts | 10 ++-- .../cdtpExceptionThrownEventsProvider.ts | 4 +- .../eventsProviders/cdtpLogEventsProvider.ts | 5 +- .../cdtpOnScriptParsedEventProvider.ts | 4 +- .../features/cdtpDebugeeSteppingController.ts | 7 +-- .../features/cdtpInspectDebugeeState.ts | 6 +- .../features/cdtpUpdateDebugeeState.ts | 5 +- .../protocolParsers/cdtpStackTraceParser.ts | 8 +-- .../registries/cdtpCallFrameRegistry.ts | 11 ++-- src/chrome/chromeDebugAdapter.ts | 32 +++++------ .../client/chromeDebugAdapter/connectedCDA.ts | 6 +- src/chrome/client/clientToInternal.ts | 4 +- src/chrome/client/handlesRegistry.ts | 4 +- src/chrome/client/internalToClient.ts | 10 ++-- src/chrome/consoleHelper.ts | 9 ++- src/chrome/internal/features/skipFiles.ts | 2 +- src/chrome/internal/features/smartStep.ts | 5 +- src/chrome/internal/requests.ts | 8 +-- src/chrome/internal/stackTraces/callFrame.ts | 52 ++++++++++------- .../stackTraces/callFrameDescription.ts | 38 +++++++++++++ .../internal/stackTraces/callFrameFunction.ts | 38 +++++++++++++ .../internal/stackTraces/callFrameName.ts | 31 ---------- .../stackTraces/callFramePresentation.ts | 56 ++++++++++--------- .../stackTraces/codeFlowFramePresentation.ts | 18 ++++++ .../stackTraces/codeFlowStackTrace.ts | 12 ++++ src/chrome/internal/stackTraces/scopes.ts | 1 + src/chrome/internal/stackTraces/stackTrace.ts | 8 --- .../stackTraces/stackTracePresentation.ts | 36 ++++-------- .../stackTraces/stackTracePresentationRow.ts | 25 +++++++++ .../internal/stackTraces/stackTracesLogic.ts | 48 +++++----------- .../stepping/features/syncStepping.ts | 6 +- src/chrome/internal/stepping/stepping.ts | 5 +- src/chrome/internalSourceBreakpoint.ts | 7 +-- src/chrome/variables.ts | 6 +- 35 files changed, 294 insertions(+), 238 deletions(-) create mode 100644 src/chrome/internal/stackTraces/callFrameDescription.ts create mode 100644 src/chrome/internal/stackTraces/callFrameFunction.ts delete mode 100644 src/chrome/internal/stackTraces/callFrameName.ts create mode 100644 src/chrome/internal/stackTraces/codeFlowFramePresentation.ts create mode 100644 src/chrome/internal/stackTraces/codeFlowStackTrace.ts delete mode 100644 src/chrome/internal/stackTraces/stackTrace.ts create mode 100644 src/chrome/internal/stackTraces/stackTracePresentationRow.ts diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts index 0478fd4c4..ba8d328c8 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts @@ -2,8 +2,7 @@ import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagno import { Protocol as CDTP } from 'devtools-protocol'; import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; import { inject, injectable } from 'inversify'; -import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; -import { IScript } from '../../internal/scripts/script'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; import { TYPES } from '../../dependencyInjection.ts/types'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; @@ -15,7 +14,7 @@ export interface ConsoleAPICalledEvent { readonly args: CDTP.Runtime.RemoteObject[]; readonly executionContextId: CDTP.Runtime.ExecutionContextId; readonly timestamp: CDTP.Runtime.Timestamp; - readonly stackTrace?: CodeFlowStackTrace; + readonly stackTrace?: CodeFlowStackTrace; readonly context?: string; } diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts index 3f8e456aa..eb27a4847 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts @@ -4,7 +4,7 @@ import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; import { adaptToSinglIntoToMulti } from '../../../utils'; import { AnyBPRecipie } from '../../internal/breakpoints/bpRecipie'; import { CDTPBreakpointIdsRegistry } from '../registries/cdtpBreakpointIdsRegistry'; -import { ScriptCallFrame, ICallFrame, CodeFlowFrame } from '../../internal/stackTraces/callFrame'; +import { ScriptCallFrame, CodeFlowFrame } from '../../internal/stackTraces/callFrame'; import { asyncUndefinedOnFailure } from '../../utils/failures'; import { CDTPLocationParser } from '../protocolParsers/cdtpLocationParser'; import { Scope } from '../../internal/stackTraces/scopes'; @@ -12,7 +12,7 @@ import { IScript } from '../../internal/scripts/script'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { Protocol as CDTP } from 'devtools-protocol'; -import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; @@ -21,11 +21,11 @@ export type PauseEventReason = 'XHR' | 'DOM' | 'EventListener' | 'exception' | ' export class PausedEvent { constructor( - public readonly callFrames: ICallFrame[], + public readonly callFrames: ScriptCallFrame[], public readonly reason: PauseEventReason, public readonly data: any, public readonly hitBreakpoints: AnyBPRecipie[], - public readonly asyncStackTrace: CodeFlowStackTrace | undefined, + public readonly asyncStackTrace: CodeFlowStackTrace | undefined, public readonly asyncStackTraceId: CDTP.Runtime.StackTraceId | undefined, public readonly asyncCallStackTraceId: CDTP.Runtime.StackTraceId | undefined) { } } @@ -74,7 +74,7 @@ export class CDTDebuggeeExecutionEventsProvider extends CDTPEventsEmitterDiagnos return this._breakpointIdRegistry.getRecipieByBreakpointId(hitBreakpoint); } - private async toCallFrame(index: number, callFrame: CDTP.Debugger.CallFrame): Promise> { + private async toCallFrame(index: number, callFrame: CDTP.Debugger.CallFrame): Promise { const frame = new ScriptCallFrame(await this.toCodeFlowFrame(index, callFrame), await asyncMap(callFrame.scopeChain, scope => this.toScope(scope)), callFrame.this, callFrame.returnValue); diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts index 434523e26..537ea7abe 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts @@ -7,7 +7,7 @@ import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { integer } from '../cdtpPrimitives'; import { IScript } from '../../internal/scripts/script'; -import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; export interface ExceptionThrownEvent { @@ -22,7 +22,7 @@ export interface ExceptionDetails { readonly columnNumber: integer; readonly script?: IScript; readonly url?: string; - readonly stackTrace?: CodeFlowStackTrace; + readonly stackTrace?: CodeFlowStackTrace; readonly exception?: CDTP.Runtime.RemoteObject; readonly executionContextId?: CDTP.Runtime.ExecutionContextId; } diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts index 1552a9b86..1bc4b5a2a 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts @@ -3,8 +3,7 @@ import { Protocol as CDTP } from 'devtools-protocol'; import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; import { integer } from '../cdtpPrimitives'; -import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; -import { IScript } from '../../internal/scripts/script'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; import { TYPES } from '../../dependencyInjection.ts/types'; import { inject } from 'inversify'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; @@ -20,7 +19,7 @@ export interface LogEntry { readonly timestamp: CDTP.Runtime.Timestamp; readonly url?: string; readonly lineNumber?: integer; - readonly stackTrace?: CodeFlowStackTrace; + readonly stackTrace?: CodeFlowStackTrace; readonly networkRequestId?: CDTP.Network.RequestId; readonly workerId?: string; readonly args?: CDTP.Runtime.RemoteObject[]; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts index b62aaa4e8..ec50ad0aa 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts @@ -9,7 +9,7 @@ import { TYPES } from '../../dependencyInjection.ts/types'; import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; import { inject } from 'inversify'; import { integer } from '../cdtpPrimitives'; -import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; import { IExecutionContext } from '../../internal/scripts/executionContext'; import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; @@ -31,7 +31,7 @@ export interface ScriptParsedEvent { readonly hasSourceURL?: boolean; readonly isModule?: boolean; readonly length?: integer; - readonly stackTrace?: CodeFlowStackTrace; + readonly stackTrace?: CodeFlowStackTrace; } export type ScriptParsedListener = (params: ScriptParsedEvent) => void; diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts b/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts index 60e76c87a..640ab512a 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts @@ -1,6 +1,5 @@ import { Protocol as CDTP } from 'devtools-protocol'; -import { ICallFrame } from '../../internal/stackTraces/callFrame'; -import { IScript } from '../../internal/scripts/script'; +import { ScriptCallFrame } from '../../internal/stackTraces/callFrame'; import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; @@ -9,7 +8,7 @@ export interface IDebugeeSteppingController { stepOver(): Promise; stepInto(params: { breakOnAsyncCall: boolean }): Promise; stepOut(): Promise; - restartFrame(callFrame: ICallFrame): Promise; + restartFrame(callFrame: ScriptCallFrame): Promise; pauseOnAsyncCall(params: CDTP.Debugger.PauseOnAsyncCallRequest): Promise; } @@ -37,7 +36,7 @@ export class CDTPDebugeeSteppingController implements IDebugeeSteppingController return this.api.Debugger.stepOut(); } - public restartFrame(frame: ICallFrame): Promise { + public restartFrame(frame: ScriptCallFrame): Promise { return this.api.Debugger.restartFrame({ callFrameId: this._callFrameRegistry.getFrameId(frame) }); } } diff --git a/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts b/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts index 814c711ba..e1a91c21f 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts @@ -3,10 +3,10 @@ import { Protocol as CDTP } from 'devtools-protocol'; import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; -import { ICallFrame, ScriptOrLoadedSource } from '../../internal/stackTraces/callFrame'; +import { ScriptCallFrame } from '../../internal/stackTraces/callFrame'; export interface EvaluateOnCallFrameRequest { - readonly frame: ICallFrame; + readonly frame: ScriptCallFrame; readonly expression: string; readonly objectGroup?: string; readonly includeCommandLineAPI?: boolean; @@ -64,7 +64,7 @@ export class CDTPInspectDebugeeState implements IInspectDebugeeState { public evaluateOnCallFrame(params: EvaluateOnCallFrameRequest): Promise { return this.api.Debugger.evaluateOnCallFrame({ - callFrameId: this._callFrameRegistry.getFrameId(params.frame.unmappedCallFrame), + callFrameId: this._callFrameRegistry.getFrameId(params.frame), expression: this.addSourceUriToEvaluates.addURLIfMissing(params.expression), objectGroup: params.objectGroup, includeCommandLineAPI: params.includeCommandLineAPI, diff --git a/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts b/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts index 4ac754aa0..d88a9fb31 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts @@ -1,16 +1,15 @@ import { Protocol as CDTP } from 'devtools-protocol'; - import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; import { TYPES } from '../../dependencyInjection.ts/types'; import { injectable, inject } from 'inversify'; -import { ICallFrame, ScriptOrLoadedSource } from '../../internal/stackTraces/callFrame'; +import { ScriptCallFrame } from '../../internal/stackTraces/callFrame'; import { integer } from '../cdtpPrimitives'; export interface SetVariableValueRequest { readonly scopeNumber: integer; readonly variableName: string; readonly newValue: CDTP.Runtime.CallArgument; - readonly frame: ICallFrame; + readonly frame: ScriptCallFrame; } export interface IUpdateDebugeeState { diff --git a/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts index cc6d62ae3..fc0452a0b 100644 --- a/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts +++ b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts @@ -1,9 +1,9 @@ import { Protocol as CDTP } from 'devtools-protocol'; import { IScript, } from '../../internal/scripts/script'; -import { CodeFlowStackTrace } from '../../internal/stackTraces/stackTrace'; +import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; import { CodeFlowFrame } from '../../internal/stackTraces/callFrame'; -import { createCallFrameName } from '../../internal/stackTraces/callFrameName'; +import { createCallFrameFunction } from '../../internal/stackTraces/callFrameFunction'; import { CDTPLocationParser, HasScriptLocation } from './cdtpLocationParser'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { asyncMap } from '../../collections/async'; @@ -11,7 +11,7 @@ import { asyncMap } from '../../collections/async'; export class CDTPStackTraceParser { private readonly _cdtpLocationParser = new CDTPLocationParser(this._scriptsRegistry); - public async toStackTraceCodeFlow(stackTrace: CDTP.Runtime.StackTrace): Promise> { + public async toStackTraceCodeFlow(stackTrace: CDTP.Runtime.StackTrace): Promise { return { codeFlowFrames: await asyncMap(stackTrace.callFrames, (callFrame, index) => this.runtimeCallFrameToCodeFlowFrame(index, callFrame)), description: stackTrace.description, @@ -25,7 +25,7 @@ export class CDTPStackTraceParser { public async toCodeFlowFrame(index: number, callFrame: CDTP.Runtime.CallFrame | CDTP.Debugger.CallFrame, location: HasScriptLocation): Promise> { const scriptLocation = await this._cdtpLocationParser.getLocationInScript(location); - const name = createCallFrameName(scriptLocation.script, callFrame.functionName); + const name = createCallFrameFunction(scriptLocation.script, callFrame.functionName); return new CodeFlowFrame(index, name, scriptLocation); } diff --git a/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts b/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts index d65820719..2b3d220be 100644 --- a/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts +++ b/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts @@ -1,18 +1,17 @@ -import { IScript } from '../../internal/scripts/script'; import { Protocol as CDTP } from 'devtools-protocol'; import { ValidatedMap } from '../../collections/validatedMap'; -import { ICallFrame, ScriptOrLoadedSource } from '../../internal/stackTraces/callFrame'; +import { ScriptCallFrame } from '../../internal/stackTraces/callFrame'; import { injectable } from 'inversify'; @injectable() export class CDTPCallFrameRegistry { - private readonly _callFrameToId = new ValidatedMap, CDTP.Debugger.CallFrameId>(); + private readonly _callFrameToId = new ValidatedMap(); - public registerFrameId(callFrameId: CDTP.Debugger.CallFrameId, frame: ICallFrame): void { + public registerFrameId(callFrameId: CDTP.Debugger.CallFrameId, frame: ScriptCallFrame): void { this._callFrameToId.set(frame, callFrameId); } - public getFrameId(frame: ICallFrame): CDTP.Debugger.CallFrameId { - return this._callFrameToId.get(frame.unmappedCallFrame); + public getFrameId(frame: ScriptCallFrame): CDTP.Debugger.CallFrameId { + return this._callFrameToId.get(frame); } } \ No newline at end of file diff --git a/src/chrome/chromeDebugAdapter.ts b/src/chrome/chromeDebugAdapter.ts index de2ec7c2b..da17b0de6 100644 --- a/src/chrome/chromeDebugAdapter.ts +++ b/src/chrome/chromeDebugAdapter.ts @@ -39,8 +39,8 @@ import { LocationInLoadedSource } from './internal/locations/location'; import { EvaluateArguments, CompletionsArguments } from './internal/requests'; import { EventSender } from './client/eventSender'; import { parseResourceIdentifier, ConnectedCDAConfiguration } from '..'; -import { ICallFrame, ScriptOrLoadedSource } from './internal/stackTraces/callFrame'; -import { CodeFlowStackTrace } from './internal/stackTraces/stackTrace'; +import { LoadedSourceCallFrame } from './internal/stackTraces/callFrame'; +import { CodeFlowStackTrace } from './internal/stackTraces/codeFlowStackTrace'; import { IResourceIdentifier } from './internal/sources/resourceIdentifier'; import { FormattedExceptionParser } from './internal/formattedExceptionParser'; import { DeleteMeScriptsRegistry } from './internal/scripts/scriptsRegistry'; @@ -391,7 +391,7 @@ export class ChromeDebugLogic { } } - private async logObjects(objs: CDTP.Runtime.RemoteObject[], isError = false, stackTrace?: CodeFlowStackTrace): Promise { + private async logObjects(objs: CDTP.Runtime.RemoteObject[], isError = false, stackTrace?: CodeFlowStackTrace): Promise { // This is an asynchronous method, so ensure that we handle one at a time so that they are sent out in the same order that they came in. this._currentLogMessage = this._currentLogMessage .then(async () => { @@ -548,17 +548,11 @@ export class ChromeDebugLogic { ] } */ - public scopes(currentFrame: ICallFrame): IScopesResponseBody { + public scopes(currentFrame: LoadedSourceCallFrame): IScopesResponseBody { if (!currentFrame || !currentFrame.location) { throw errors.stackFrameNotValid(); } - const scriptCallFrame = currentFrame.unmappedCallFrame; - - const currentScript = scriptCallFrame.location.script; - const currentScriptUrl = currentScript.runtimeSource.identifier.textRepresentation; - const currentScriptPath = currentScriptUrl; - const scopes = currentFrame.scopeChain.map((scope, i) => { // The first scope should include 'this'. Keep the RemoteObject reference for use by the variables request const thisObj = i === 0 && currentFrame.frameThis; @@ -590,8 +584,8 @@ export class ChromeDebugLogic { } const scopesResponse = { scopes }; - if (currentScriptPath) { - this._sourceMapTransformer.scopesResponse(currentScriptPath, scopesResponse); + if (currentFrame.source.doesScriptHasUrl()) { + this._sourceMapTransformer.scopesResponse(currentFrame.source.script.url, scopesResponse); this._lineColTransformer.scopeResponse(scopesResponse); } @@ -826,13 +820,13 @@ export class ChromeDebugLogic { return this._inspectDebugeeState.evaluate(args); } - private async waitThenDoEvaluate(expression: string, frame?: ICallFrame, extraArgs?: Partial): Promise { + private async waitThenDoEvaluate(expression: string, frame?: LoadedSourceCallFrame, extraArgs?: Partial): Promise { const waitThenEval = this._waitAfterStep.then(() => this.doEvaluate(expression, frame, extraArgs)); this._waitAfterStep = waitThenEval.then(() => { }, () => { }); // to Promise and handle failed evals return waitThenEval; } - private async doEvaluate(expression: string, frame: ICallFrame, extraArgs?: Partial): Promise { + private async doEvaluate(expression: string, frame: LoadedSourceCallFrame, extraArgs?: Partial): Promise { if (frame) { if (!frame) { return utils.errP(errors.evalNotAvailableMsg); @@ -856,9 +850,9 @@ export class ChromeDebugLogic { } } - public async evaluateOnCallFrame(expression: string, frame: ICallFrame, extraArgs?: Partial): Promise { + public async evaluateOnCallFrame(expression: string, frame: LoadedSourceCallFrame, extraArgs?: Partial): Promise { let args: EvaluateOnCallFrameRequest = { - frame, + frame: frame.unmappedCallFrame, expression, // silent because of an issue where node will sometimes hang when breaking on exceptions in console messages. Fixed somewhere between 8 and 8.4 silent: true, @@ -890,16 +884,16 @@ export class ChromeDebugLogic { .then(value => ({ value })); } - public setVariableValue(frame: ICallFrame, scopeNumber: number, variableName: string, value: string): Promise { + public setVariableValue(frame: LoadedSourceCallFrame, scopeNumber: number, variableName: string, value: string): Promise { let evalResultObject: CDTP.Runtime.RemoteObject; - return this._inspectDebugeeState.evaluateOnCallFrame({ frame, expression: value, silent: true }).then(evalResponse => { + return this._inspectDebugeeState.evaluateOnCallFrame({ frame: frame.unmappedCallFrame, expression: value, silent: true }).then(evalResponse => { if (evalResponse.exceptionDetails) { const errMsg = ChromeUtils.errorMessageFromExceptionDetails(evalResponse.exceptionDetails); return Promise.reject(errors.errorFromEvaluate(errMsg)); } else { evalResultObject = evalResponse.result; const newValue = ChromeUtils.remoteObjectToCallArgument(evalResultObject); - return this._updateDebugeeState.setVariableValue({ frame, scopeNumber, variableName, newValue }); + return this._updateDebugeeState.setVariableValue({ frame: frame.unmappedCallFrame, scopeNumber, variableName, newValue }); } }, error => Promise.reject(errors.errorFromEvaluate(error.message))) diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts index e2701ff04..7dda78917 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts @@ -121,7 +121,7 @@ export class ConnectedCDA implements IDebugAdapterState { public async restartFrame(args: DebugProtocol.RestartFrameRequest): Promise { const callFrame = this._clientToInternal.getCallFrameById(args.arguments.frameId); - if (callFrame.hasCallFrame()) { + if (callFrame.isCallFrame()) { return this._stepping.restartFrame(callFrame.callFrame.unmappedCallFrame); } else { throw new Error(`Cannot restart to a frame that doesn't have state information`); @@ -139,10 +139,10 @@ export class ConnectedCDA implements IDebugAdapterState { public scopes(args: DebugProtocol.ScopesArguments, _?: ITelemetryPropertyCollector, _2?: number): PromiseOrNot { const frame = this._clientToInternal.getCallFrameById(args.frameId); - if (frame.hasCallFrame()) { + if (frame.isCallFrame()) { return this._chromeDebugAdapter.scopes(frame.callFrame); } else { - const reason = frame.hasCodeFlow() + const reason = frame.isNotLabel() ? 'a code flow frame only has code flow information' : 'a label frame is only a description of the different sections of the call stack'; throw new Error(`Can't get scopes for the frame because ${reason}`); diff --git a/src/chrome/client/clientToInternal.ts b/src/chrome/client/clientToInternal.ts index ddc32c378..02f2f9af9 100644 --- a/src/chrome/client/clientToInternal.ts +++ b/src/chrome/client/clientToInternal.ts @@ -7,13 +7,13 @@ import { LineColTransformer } from '../../transformers/lineNumberTransformer'; import { BPRecipiesInUnresolvedSource } from '../internal/breakpoints/bpRecipies'; import { IBPActionWhenHit, AlwaysBreak, ConditionalBreak } from '../internal/breakpoints/bpActionWhenHit'; import { HandlesRegistry } from './handlesRegistry'; -import { FramePresentationOrLabel } from '../internal/stackTraces/stackTracePresentation'; import { createLineNumber, createColumnNumber } from '../internal/locations/subtypes'; import { parseResourceIdentifier } from '../internal/sources/resourceIdentifier'; import { PauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions, PauseOnAllRejections, DoNotPauseOnAnyRejections, PauseOnPromiseRejectionsStrategy } from '../internal/exceptions/strategies'; import { injectable, inject } from 'inversify'; import { TYPES } from '../dependencyInjection.ts/types'; import { ISource, SourceAlreadyResolvedToLoadedSource } from '../internal/sources/source'; +import { StackTracePresentationRow } from '../internal/stackTraces/StackTracePresentationRow'; @injectable() export class ClientToInternal { @@ -36,7 +36,7 @@ export class ClientToInternal { } // V1 reseted the frames on an onPaused event. Figure out if that is the right thing to do - public getCallFrameById(frameId: number): FramePresentationOrLabel { + public getCallFrameById(frameId: number): StackTracePresentationRow { return this._handlesRegistry.frames.getObjectById(frameId); } diff --git a/src/chrome/client/handlesRegistry.ts b/src/chrome/client/handlesRegistry.ts index 5b216f140..8989fd01d 100644 --- a/src/chrome/client/handlesRegistry.ts +++ b/src/chrome/client/handlesRegistry.ts @@ -1,8 +1,8 @@ import { ILoadedSource } from '../internal/sources/loadedSource'; import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; import { BidirectionalMap } from '../collections/bidirectionalMap'; -import { FramePresentationOrLabel } from '../internal/stackTraces/stackTracePresentation'; import { injectable } from 'inversify'; +import { StackTracePresentationRow } from '../internal/stackTraces/stackTracePresentationRow'; export class BidirectionalHandles { private readonly _idToObject = new BidirectionalMap(); @@ -36,7 +36,7 @@ export class HandlesRegistry { // TODO DIEGO: V1 reseted the frames on an onPaused event. Figure out if that is the right thing to do // We use different prefixes so it's easier to identify the IDs in the logs... public readonly breakpoints = new BidirectionalHandles>>(888 * prefixMultiplier); - public readonly frames = new BidirectionalHandles>(123 * prefixMultiplier); + public readonly frames = new BidirectionalHandles(123 * prefixMultiplier); public readonly sources = new BidirectionalHandles(555 * prefixMultiplier); public toString(): string { diff --git a/src/chrome/client/internalToClient.ts b/src/chrome/client/internalToClient.ts index 2e2c7ad02..a9038f6fe 100644 --- a/src/chrome/client/internalToClient.ts +++ b/src/chrome/client/internalToClient.ts @@ -8,12 +8,12 @@ import { RemoveProperty } from '../../typeUtils'; import { IBPRecipieStatus } from '../internal/breakpoints/bpRecipieStatus'; import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; import { HandlesRegistry } from './handlesRegistry'; -import { FramePresentationOrLabel, StackTraceLabel } from '../internal/stackTraces/stackTracePresentation'; import { IExceptionInformation } from '../internal/exceptions/pauseOnException'; import { IFormattedExceptionLineDescription } from '../internal/formattedExceptionParser'; import { injectable, inject } from 'inversify'; import { TYPES } from '../dependencyInjection.ts/types'; import { Source } from 'vscode-debugadapter'; +import { StackTracePresentationRow, StackTraceLabel } from '../internal/stackTraces/StackTracePresentationRow'; interface ClientLocationInSource { source: DebugProtocol.Source; @@ -27,15 +27,15 @@ export class InternalToClient { public readonly toSourceTrees = asyncAdaptToSinglIntoToMulti(this, this.toSourceTree); public readonly toBPRecipiesStatus = asyncAdaptToSinglIntoToMulti(this, this.toBPRecipieStatus); - public getFrameId(stackFrame: FramePresentationOrLabel): number { + public getFrameId(stackFrame: StackTracePresentationRow): number { return this._handlesRegistry.frames.getIdByObject(stackFrame); } - public async toStackFrame(stackFrame: FramePresentationOrLabel): Promise { - if (stackFrame.hasCodeFlow()) { + public async toStackFrame(stackFrame: StackTracePresentationRow): Promise { + if (stackFrame.isNotLabel()) { const clientStackFrame: RemoveProperty = { id: this.getFrameId(stackFrame), - name: stackFrame.name, + name: stackFrame.description, presentationHint: stackFrame.presentationHint }; diff --git a/src/chrome/consoleHelper.ts b/src/chrome/consoleHelper.ts index bdc120f4f..9abbeaa18 100644 --- a/src/chrome/consoleHelper.ts +++ b/src/chrome/consoleHelper.ts @@ -5,8 +5,7 @@ import { Protocol as CDTP } from 'devtools-protocol'; import * as Color from 'color'; import * as variables from './variables'; -import { IScript } from './internal/scripts/script'; -import { CodeFlowStackTrace } from './internal/stackTraces/stackTrace'; +import { CodeFlowStackTrace } from './internal/stackTraces/codeFlowStackTrace'; import { ExceptionDetails } from './cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider'; export function formatExceptionDetails(e: ExceptionDetails): string { @@ -20,7 +19,7 @@ export function formatExceptionDetails(e: ExceptionDetails): string { export const clearConsoleCode = '\u001b[2J'; -export function formatConsoleArguments(type: CDTP.Runtime.ConsoleAPICalledEvent['type'], args: CDTP.Runtime.RemoteObject[], stackTrace?: CodeFlowStackTrace): { args: CDTP.Runtime.RemoteObject[], isError: boolean } { +export function formatConsoleArguments(type: CDTP.Runtime.ConsoleAPICalledEvent['type'], args: CDTP.Runtime.RemoteObject[], stackTrace?: CodeFlowStackTrace): { args: CDTP.Runtime.RemoteObject[], isError: boolean } { switch (type) { case 'log': case 'debug': @@ -209,14 +208,14 @@ function formatArg(formatSpec: string, arg: CDTP.Runtime.RemoteObject): string | } } -function stackTraceToString(stackTrace: CodeFlowStackTrace): string { +function stackTraceToString(stackTrace: CodeFlowStackTrace): string { if (!stackTrace) { return ''; } return stackTrace.codeFlowFrames .map(frame => { - const fnName = frame.name; + const fnName = frame.functionDescription; const fileName = frame.script.developmentSource.identifier.textRepresentation; return ` at ${fnName} (${fileName}:${frame.lineNumber + 1}:${frame.columnNumber})`; }) diff --git a/src/chrome/internal/features/skipFiles.ts b/src/chrome/internal/features/skipFiles.ts index b08f00518..65e15f371 100644 --- a/src/chrome/internal/features/skipFiles.ts +++ b/src/chrome/internal/features/skipFiles.ts @@ -151,7 +151,7 @@ export class SkipFilesLogic implements IComponent, ISta const currentStack = await this.stackTracesLogic.stackTrace({ threadId: undefined }); return currentStack.stackFrames.some(frame => { - return frame.hasCodeFlow() + return frame.isNotLabel() && frame.codeFlow.location.source && frame.codeFlow.location.source.isEquivalentTo(resolvedSource); }); diff --git a/src/chrome/internal/features/smartStep.ts b/src/chrome/internal/features/smartStep.ts index c7089deed..63894aea5 100644 --- a/src/chrome/internal/features/smartStep.ts +++ b/src/chrome/internal/features/smartStep.ts @@ -1,7 +1,6 @@ import { BasePathTransformer } from '../../../transformers/basePathTransformer'; import { BaseSourceMapTransformer } from '../../../transformers/baseSourceMapTransformer'; -import { IScript } from '../scripts/script'; -import { ICallFrame } from '../stackTraces/callFrame'; +import { ScriptCallFrame } from '../stackTraces/callFrame'; import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { InformationAboutPausedProvider } from './takeProperActionOnPausedEvent'; import { logger } from 'vscode-debugadapter'; @@ -76,7 +75,7 @@ export class SmartStepLogic implements IComponent, IStackTracePresentationLogicP throw new Error('Not implemented TODO DIEGO'); } - public async shouldSkip(frame: ICallFrame): Promise { + public async shouldSkip(frame: ScriptCallFrame): Promise { if (!this._isEnabled) return false; const clientPath = this._pathTransformer.getClientPathFromTargetPath(frame.location.script.runtimeSource.identifier) diff --git a/src/chrome/internal/requests.ts b/src/chrome/internal/requests.ts index 211047023..314c4486f 100644 --- a/src/chrome/internal/requests.ts +++ b/src/chrome/internal/requests.ts @@ -1,10 +1,8 @@ -import { IScript } from './scripts/script'; -import { ILoadedSource } from './sources/loadedSource'; -import { ICallFrame } from './stackTraces/callFrame'; +import { LoadedSourceCallFrame } from './stackTraces/callFrame'; export interface EvaluateArguments { readonly expression: string; - readonly frame?: ICallFrame; + readonly frame?: LoadedSourceCallFrame; readonly context?: string; readonly format?: { /** Display the value in hex. */ @@ -13,7 +11,7 @@ export interface EvaluateArguments { } export interface CompletionsArguments { - readonly frame?: ICallFrame; + readonly frame?: LoadedSourceCallFrame; readonly text: string; readonly column: number; readonly line?: number; diff --git a/src/chrome/internal/stackTraces/callFrame.ts b/src/chrome/internal/stackTraces/callFrame.ts index f4306e954..9f700b8f1 100644 --- a/src/chrome/internal/stackTraces/callFrame.ts +++ b/src/chrome/internal/stackTraces/callFrame.ts @@ -2,18 +2,27 @@ import { Location } from '../locations/location'; import { ILoadedSource } from '../sources/loadedSource'; import { IScript } from '../scripts/script'; import { Protocol as CDTP } from 'devtools-protocol'; - -import { ICallFrameName } from './callFrameName'; +import { ICallFrameFunction } from './callFrameFunction'; import { Scope } from './scopes'; import { integer } from '../../cdtpDebuggee/cdtpPrimitives'; -export type ScriptOrLoadedSource = IScript | ILoadedSource; // Used for stack traces +/** CDTP has two types of stack traces: + * 1. CDTP.Runtime stack traces have only information about which code was executed, but not the state associated with it + * 2. CDTP.Debugger stack traces which have all the information that CDTP.Runtime has, and it also includes state information + * + * We represent this by modeling the information that both contain in CodeFlowFrame and the information that only CDTP.Debugger + * contains on CallFrame (which has an embedded CodeFlowFrame) + */ + +export type ScriptOrLoadedSource = IScript | ILoadedSource; -/** This interface represents the code flow (which code was executed) of a call frame */ +/** This class represents the code flow (which code was executed) of a call frame. + * (This has similar properties as the stack traces from the CDTP.Runtime domain) + */ export class CodeFlowFrame { constructor( public readonly index: integer, - public readonly nameStrategy: ICallFrameName, + public readonly callFrameFunction: ICallFrameFunction, public readonly location: Location) { } public get source(): TResource extends ILoadedSource ? TResource : never { @@ -32,28 +41,32 @@ export class CodeFlowFrame { return this.location.position.columnNumber; } - public get name(): string { - return this.nameStrategy.name; + public get functionDescription(): string { + return this.callFrameFunction.description; } } +/** This interface represents both the code flow and the state of a call frame. + * (This has similar properties as the stack traces from the CDTP.Debugger domain) + */ export interface ICallFrame { readonly index: number; - readonly source: TResource extends ILoadedSource ? TResource : never; readonly location: Location; readonly lineNumber: number; readonly columnNumber: number; - readonly name: string; readonly codeFlow: CodeFlowFrame; readonly scopeChain: Scope[]; readonly frameThis?: CDTP.Runtime.RemoteObject; readonly returnValue?: CDTP.Runtime.RemoteObject; - readonly unmappedCallFrame: ICallFrame; } +export type CallFrame = + TResource extends ILoadedSource ? LoadedSourceCallFrame : + TResource extends IScript ? ScriptCallFrame : + ICallFrame; // TODO: Figure out how to change this for never + abstract class CallFrameCommonLogic implements ICallFrame { public abstract get scopeChain(): Scope[]; - public abstract get unmappedCallFrame(): ICallFrame; public abstract get codeFlow(): CodeFlowFrame; public get source(): TResource extends ILoadedSource ? TResource : never { @@ -76,23 +89,24 @@ abstract class CallFrameCommonLogic impl return this.codeFlow.index; } - public get name(): string { - return this.codeFlow.name; + public get functionDescription(): string { + return this.codeFlow.functionDescription; } } export class ScriptCallFrame extends CallFrameCommonLogic { - public get unmappedCallFrame(): ICallFrame { - return this; - } - constructor( public readonly codeFlow: CodeFlowFrame, public readonly scopeChain: Scope[], - public readonly frameThis?: CDTP.Runtime.RemoteObject, // This is optional only to support Runtime.StackTraces aka StackTraceCodeFlow + public readonly frameThis: CDTP.Runtime.RemoteObject, public readonly returnValue?: CDTP.Runtime.RemoteObject) { super(); } + + public mappedToSource(): LoadedSourceCallFrame { + const codeFlow = new CodeFlowFrame(this.index, this.codeFlow.callFrameFunction, this.location.mappedToSource()); + return new LoadedSourceCallFrame(this, codeFlow); + } } export class LoadedSourceCallFrame extends CallFrameCommonLogic { @@ -109,7 +123,7 @@ export class LoadedSourceCallFrame extends CallFrameCommonLogic { } constructor( - public readonly unmappedCallFrame: ICallFrame, + public readonly unmappedCallFrame: ScriptCallFrame, public readonly codeFlow: CodeFlowFrame) { super(); } diff --git a/src/chrome/internal/stackTraces/callFrameDescription.ts b/src/chrome/internal/stackTraces/callFrameDescription.ts new file mode 100644 index 000000000..ce50e9514 --- /dev/null +++ b/src/chrome/internal/stackTraces/callFrameDescription.ts @@ -0,0 +1,38 @@ +import * as path from 'path'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { ScriptCallFrame } from './callFrame'; + +/** The clients can requests the stack traces frames descriptions in different formats. + * We use this class to create the description for the call frame according to the parameters supplied by the client. + */ + +const ImplementsCallFrameDescriptionFormatter = Symbol(); +export interface ICallFrameDescriptionFormatter { + readonly description: string; + + [ImplementsCallFrameDescriptionFormatter]: void; +} + +export class CustomCallFrameDescriptionFormatter implements ICallFrameDescriptionFormatter { + [ImplementsCallFrameDescriptionFormatter]: void; + + public get description(): string { + const locationInLoadedSource = this._callFrame.location.mappedToSource(); + + let formattedDescription = this._callFrame.functionDescription; + + if (this._formatArgs) { + if (this._formatArgs.module) { + formattedDescription += ` [${path.basename(locationInLoadedSource.source.identifier.textRepresentation)}]`; + } + + if (this._formatArgs.line) { + formattedDescription += ` Line ${locationInLoadedSource.position.lineNumber}`; + } + } + + return formattedDescription; + } + + constructor(private readonly _callFrame: ScriptCallFrame, private readonly _formatArgs?: DebugProtocol.StackFrameFormat) { } +} diff --git a/src/chrome/internal/stackTraces/callFrameFunction.ts b/src/chrome/internal/stackTraces/callFrameFunction.ts new file mode 100644 index 000000000..d9a275586 --- /dev/null +++ b/src/chrome/internal/stackTraces/callFrameFunction.ts @@ -0,0 +1,38 @@ +import { IScript } from '../scripts/script'; + +/** We use these classes to generate a proper description for the function + * based on wheter it is named, and the script where it's at is named + */ +const ImplementsCallFrameFunction = Symbol(); +export interface ICallFrameFunction { + readonly description: string; + [ImplementsCallFrameFunction]: void; +} + +class CallFrameForNamedFunction implements ICallFrameFunction { + [ImplementsCallFrameFunction]: void; + + constructor(public readonly description: string) { } +} + +class CallFrameForUnamedFunctionInUnnamedScript implements ICallFrameFunction { + [ImplementsCallFrameFunction]: void; + + public readonly description = '(eval code)'; +} + +class CallFrameForUnamedFunctionInNamedScript implements ICallFrameFunction { + [ImplementsCallFrameFunction]: void; + + public readonly description = '(anonymous function)'; +} + +export function createCallFrameFunction(script: IScript, functionName: string) { + if (functionName) { + return new CallFrameForNamedFunction(functionName); + } else if (script.runtimeSource.doesScriptHasUrl()) { + return new CallFrameForUnamedFunctionInNamedScript(); + } else { + return new CallFrameForUnamedFunctionInUnnamedScript(); + } +} diff --git a/src/chrome/internal/stackTraces/callFrameName.ts b/src/chrome/internal/stackTraces/callFrameName.ts deleted file mode 100644 index 702a3f6a0..000000000 --- a/src/chrome/internal/stackTraces/callFrameName.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { IScript } from '../scripts/script'; - -export interface ICallFrameName { - readonly name: string; -} - -export class NamedFunctionCallFrameName implements ICallFrameName { - constructor(public readonly name: string) { } -} - -export class UnamedFunctionInEvalScriptCallFrameName implements ICallFrameName { - public readonly name = '(eval code)'; -} - -export class UnamedFunctionInFileCallFrameName implements ICallFrameName { - public readonly name = '(anonymous function)'; -} - -export class FormattedName implements ICallFrameName { - constructor(public readonly name: string) { } -} - -export function createCallFrameName(script: IScript, functionName: string) { - if (functionName) { - return new NamedFunctionCallFrameName(functionName); - } else if (script.runtimeSource.doesScriptHasUrl()) { - return new UnamedFunctionInFileCallFrameName(); - } else { - return new UnamedFunctionInEvalScriptCallFrameName(); - } -} diff --git a/src/chrome/internal/stackTraces/callFramePresentation.ts b/src/chrome/internal/stackTraces/callFramePresentation.ts index 7a49f52f9..57ec31be8 100644 --- a/src/chrome/internal/stackTraces/callFramePresentation.ts +++ b/src/chrome/internal/stackTraces/callFramePresentation.ts @@ -1,40 +1,35 @@ import { Location } from '../locations/location'; - import { ILoadedSource } from '../sources/loadedSource'; - -import { CodeFlowFrame, ICallFrame, ScriptOrLoadedSource } from './callFrame'; - -import { CodeFlowFramePresentationRow } from './stackTracePresentation'; +import { CodeFlowFrame, ICallFrame, CallFrame } from './callFrame'; +import { StackTracePresentationRow, CallFramePresentationHint } from './stackTracePresentationRow'; +import { ICallFrameDescriptionFormatter } from './callFrameDescription'; export type SourcePresentationHint = 'normal' | 'emphasize' | 'deemphasize'; -export type CallFramePresentationHint = 'normal' | 'label' | 'subtle'; export interface ICallFramePresentationDetails { readonly additionalSourceOrigins: string[]; readonly sourcePresentationHint: SourcePresentationHint; } -export interface ICodeFlowFramePresentation extends CodeFlowFramePresentationRow { - readonly name: string; +export interface ICodeFlowFramePresentation extends StackTracePresentationRow { + readonly description: string; readonly source: ILoadedSource; - readonly location: Location; + readonly location: Location; readonly lineNumber: number; readonly columnNumber: number; + readonly codeFlow: CodeFlowFrame; } -export abstract class CodeFlowFramePresentationCommonLogic implements ICodeFlowFramePresentation { - public abstract get codeFlow(): CodeFlowFrame; - public abstract hasCallFrame(): this is CallFramePresentation; - - public get name(): string { - return this.codeFlow.name; - } +export abstract class FramePresentationCommonLogic implements ICodeFlowFramePresentation { + public abstract get codeFlow(): CodeFlowFrame; + public abstract isCallFrame(): this is CallFramePresentation; + public abstract get description(): string; public get source(): ILoadedSource { return this.codeFlow.source; } - public get location(): Location { + public get location(): Location { return this.codeFlow.location; } @@ -46,7 +41,7 @@ export abstract class CodeFlowFramePresentationCommonLogic { + public isNotLabel(): this is ICodeFlowFramePresentation { return true; } @@ -55,30 +50,39 @@ export abstract class CodeFlowFramePresentationCommonLogic extends CodeFlowFramePresentationCommonLogic implements CodeFlowFramePresentationRow { - public get codeFlow(): CodeFlowFrame { - return this.callFrame.codeFlow; +export class CallFramePresentation extends FramePresentationCommonLogic implements StackTracePresentationRow { + public get codeFlow(): CodeFlowFrame { + return (>this.callFrame).codeFlow; // TODO: Figure out how to remove the cast } - public hasCallFrame(): this is CallFramePresentation { + public isCallFrame(): this is CallFramePresentation { return true; } + public get description(): string { + return this._descriptionFormatter.description; + } + constructor( - public readonly callFrame: ICallFrame, + public readonly callFrame: CallFrame, + private readonly _descriptionFormatter: ICallFrameDescriptionFormatter, additionalPresentationDetails?: ICallFramePresentationDetails, presentationHint?: CallFramePresentationHint) { super(additionalPresentationDetails, presentationHint); } } -export class CodeFlowFramePresentation extends CodeFlowFramePresentationCommonLogic implements CodeFlowFramePresentationRow { - public hasCallFrame(): this is CallFramePresentation { +export class CodeFlowFramePresentation extends FramePresentationCommonLogic implements StackTracePresentationRow { + public get description(): string { + return this.codeFlow.functionDescription; + } + + public isCallFrame(): this is CallFramePresentation { return false; } constructor( - public readonly codeFlow: CodeFlowFrame, + public readonly codeFlow: CodeFlowFrame, additionalPresentationDetails?: ICallFramePresentationDetails, presentationHint?: CallFramePresentationHint) { super(additionalPresentationDetails, presentationHint); diff --git a/src/chrome/internal/stackTraces/codeFlowFramePresentation.ts b/src/chrome/internal/stackTraces/codeFlowFramePresentation.ts new file mode 100644 index 000000000..955bde3a5 --- /dev/null +++ b/src/chrome/internal/stackTraces/codeFlowFramePresentation.ts @@ -0,0 +1,18 @@ +import { ILoadedSource } from '../sources/loadedSource'; +import { CodeFlowFrame } from './callFrame'; +import { StackTracePresentationRow, CallFramePresentationHint } from './stackTracePresentationRow'; +import { FramePresentationCommonLogic, CallFramePresentation, ICallFramePresentationDetails } from './callFramePresentation'; + +export class CodeFlowFramePresentation extends FramePresentationCommonLogic implements StackTracePresentationRow { + constructor(public readonly codeFlow: CodeFlowFrame, additionalPresentationDetails?: ICallFramePresentationDetails, presentationHint?: CallFramePresentationHint) { + super(additionalPresentationDetails, presentationHint); + } + + public get description(): string { + return this.codeFlow.functionDescription; + } + + public isCallFrame(): this is CallFramePresentation { + return false; + } +} diff --git a/src/chrome/internal/stackTraces/codeFlowStackTrace.ts b/src/chrome/internal/stackTraces/codeFlowStackTrace.ts new file mode 100644 index 000000000..ec866997d --- /dev/null +++ b/src/chrome/internal/stackTraces/codeFlowStackTrace.ts @@ -0,0 +1,12 @@ +import { CodeFlowFrame } from './callFrame'; +import { IScript } from '../scripts/script'; + +/** This class represents a stack trace that only has code flow information, but no state + * (This is the information provided by the CDTP.Runtime domain and/or async stack traces) + */ +export class CodeFlowStackTrace { + constructor( + public readonly codeFlowFrames: CodeFlowFrame[], + public readonly description?: string, + public readonly parent?: CodeFlowStackTrace) { } +} diff --git a/src/chrome/internal/stackTraces/scopes.ts b/src/chrome/internal/stackTraces/scopes.ts index ed1f20186..681df21c3 100644 --- a/src/chrome/internal/stackTraces/scopes.ts +++ b/src/chrome/internal/stackTraces/scopes.ts @@ -1,6 +1,7 @@ import { LocationInScript } from '../locations/location'; import { Protocol as CDTP } from 'devtools-protocol'; +/** This class represents a variable's scope (Globals, locals, block variables, etc...) */ export class Scope { constructor( public readonly type: ('global' | 'local' | 'with' | 'closure' | 'catch' | 'block' | 'script' | 'eval' | 'module'), diff --git a/src/chrome/internal/stackTraces/stackTrace.ts b/src/chrome/internal/stackTraces/stackTrace.ts deleted file mode 100644 index c6bc1ad6f..000000000 --- a/src/chrome/internal/stackTraces/stackTrace.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CodeFlowFrame, ScriptOrLoadedSource } from './callFrame'; - -export class CodeFlowStackTrace { - constructor( - public readonly codeFlowFrames: CodeFlowFrame[], - public readonly description?: string, - public readonly parent?: CodeFlowStackTrace) { } -} diff --git a/src/chrome/internal/stackTraces/stackTracePresentation.ts b/src/chrome/internal/stackTraces/stackTracePresentation.ts index 7617839d6..f71c845d5 100644 --- a/src/chrome/internal/stackTraces/stackTracePresentation.ts +++ b/src/chrome/internal/stackTraces/stackTracePresentation.ts @@ -1,27 +1,11 @@ -import { ILoadedSource } from '../sources/loadedSource'; -import { ICodeFlowFramePresentation, CodeFlowFramePresentation, CallFramePresentation } from './callFramePresentation'; -import { ScriptOrLoadedSource } from './callFrame'; - -export interface CodeFlowFramePresentationRow { - hasCodeFlow(): this is ICodeFlowFramePresentation; - hasCallFrame(): this is CallFramePresentation; -} - -export class StackTraceLabel implements CodeFlowFramePresentationRow { - public hasCallFrame(): this is CallFramePresentation { - return false; - } - - public hasCodeFlow(): this is ICodeFlowFramePresentation { - return false; - } - - constructor(public readonly description: string) { } -} - -export type FramePresentationOrLabel = CodeFlowFramePresentation | CallFramePresentation | StackTraceLabel; - -export interface StackTracePresentation { - readonly stackFrames: FramePresentationOrLabel[]; - readonly totalFrames?: number; +import { StackTracePresentationRow } from './stackTracePresentationRow'; + +/** The stack traces we sent to the client will be represented by this classes and it is a combination of: + * 1. CallFrames with state information from the sync frames. + * 2. CodeFlowFrames without state information from async frames. + * 3. Labels that we use to [Show more frames] or [Frames skipped by smartStep], etc... + */ + export interface StackTracePresentation { + readonly stackFrames: StackTracePresentationRow[]; + readonly totalFrames: number; } diff --git a/src/chrome/internal/stackTraces/stackTracePresentationRow.ts b/src/chrome/internal/stackTraces/stackTracePresentationRow.ts new file mode 100644 index 000000000..55cce713c --- /dev/null +++ b/src/chrome/internal/stackTraces/stackTracePresentationRow.ts @@ -0,0 +1,25 @@ +import { ICodeFlowFramePresentation, CallFramePresentation } from './callFramePresentation'; + +export type CallFramePresentationHint = 'normal' | 'label' | 'subtle'; + +// Row of a stack trace that we send to the client +export interface StackTracePresentationRow { + readonly presentationHint?: CallFramePresentationHint; + isNotLabel(): this is ICodeFlowFramePresentation; + isCallFrame(): this is CallFramePresentation; +} + +// Row of a stack trace that is a label e.g.: [Show more frames] or [Frames skipped by smartStep], etc... +export class StackTraceLabel implements StackTracePresentationRow { + public readonly presentationHint = 'label'; + + public isCallFrame(): this is CallFramePresentation { + return false; + } + + public isNotLabel(): this is ICodeFlowFramePresentation { + return false; + } + + constructor(public readonly description: string) { } +} diff --git a/src/chrome/internal/stackTraces/stackTracesLogic.ts b/src/chrome/internal/stackTraces/stackTracesLogic.ts index a30069f9c..8c2a4b430 100644 --- a/src/chrome/internal/stackTraces/stackTracesLogic.ts +++ b/src/chrome/internal/stackTraces/stackTracesLogic.ts @@ -2,19 +2,16 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { injectable, inject } from 'inversify'; import * as errors from '../../../errors'; -import * as path from 'path'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; -import { StackTracePresentation, FramePresentationOrLabel, StackTraceLabel } from './stackTracePresentation'; -import { ILoadedSource } from '../sources/loadedSource'; -import { CodeFlowStackTrace } from './stackTrace'; +import { StackTracePresentation } from './stackTracePresentation'; +import { CodeFlowStackTrace } from './codeFlowStackTrace'; import { IScript } from '../scripts/script'; -import { CodeFlowFrame, ICallFrame, ScriptCallFrame, LoadedSourceCallFrame } from './callFrame'; +import { CodeFlowFrame, ScriptCallFrame } from './callFrame'; import { LocationInLoadedSource } from '../locations/location'; -import { CallFramePresentation, CallFramePresentationHint, SourcePresentationHint, ICallFramePresentationDetails } from './callFramePresentation'; -import { FormattedName } from './callFrameName'; +import { CallFramePresentation, SourcePresentationHint, ICallFramePresentationDetails } from './callFramePresentation'; import { IComponent, ComponentConfiguration } from '../features/feature'; import { InformationAboutPausedProvider } from '../features/takeProperActionOnPausedEvent'; import { asyncMap } from '../../collections/async'; @@ -22,6 +19,8 @@ import { TYPES } from '../../dependencyInjection.ts/types'; import { ConnectedCDAConfiguration } from '../../..'; import { Vote, Abstained } from '../../communication/collaborativeDecision'; import { IAsyncDebuggingConfigurer } from '../../cdtpDebuggee/features/CDTPAsyncDebuggingConfigurer'; +import { CustomCallFrameDescriptionFormatter } from './callFrameDescription'; +import { StackTracePresentationRow, StackTraceLabel, CallFramePresentationHint } from './stackTracePresentationRow'; export interface EventsConsumedByStackTrace { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; @@ -56,7 +55,7 @@ export class StackTracesLogic implements IComponent { return Promise.reject(errors.noCallStackAvailable()); } - const syncFames: FramePresentationOrLabel[] = await asyncMap(this._currentPauseEvent.callFrames, frame => this.toPresentation(frame, args.format)); + const syncFames: StackTracePresentationRow[] = await asyncMap(this._currentPauseEvent.callFrames, frame => this.toPresentation(frame, args.format)); const asyncStackTrace = this._currentPauseEvent.asyncStackTrace; let stackFrames = asyncStackTrace ? syncFames.concat(await this.asyncCallFrames(asyncStackTrace, args.format)) : syncFames; @@ -77,8 +76,8 @@ export class StackTracesLogic implements IComponent { return stackTraceResponse; } - private async asyncCallFrames(stackTrace: CodeFlowStackTrace, formatArgs?: DebugProtocol.StackFrameFormat): Promise[]> { - const asyncFrames: FramePresentationOrLabel[] = await asyncMap(stackTrace.codeFlowFrames, + private async asyncCallFrames(stackTrace: CodeFlowStackTrace, formatArgs?: DebugProtocol.StackFrameFormat): Promise { + const asyncFrames: StackTracePresentationRow[] = await asyncMap(stackTrace.codeFlowFrames, frame => this.toPresentation(this.codeFlowToCallFrame(frame), formatArgs)); asyncFrames.unshift(new StackTraceLabel(stackTrace.description)); @@ -86,34 +85,18 @@ export class StackTracesLogic implements IComponent { return asyncFrames.concat(stackTrace.parent ? await this.asyncCallFrames(stackTrace.parent, formatArgs) : []); } - private codeFlowToCallFrame(frame: CodeFlowFrame): ICallFrame { + private codeFlowToCallFrame(frame: CodeFlowFrame): ScriptCallFrame { return new ScriptCallFrame(frame, [], undefined, undefined); } - private formatStackFrameName(name: string, locationInLoadedSource: LocationInLoadedSource, formatArgs?: DebugProtocol.StackFrameFormat): string { - let formattedName = name; - if (formatArgs) { - if (formatArgs.module) { - formattedName += ` [${path.basename(locationInLoadedSource.source.identifier.textRepresentation)}]`; - } - - if (formatArgs.line) { - formattedName += ` Line ${locationInLoadedSource.position.lineNumber}`; - } - } - - return formattedName; - } - - private async toPresentation(frame: ICallFrame, formatArgs?: DebugProtocol.StackFrameFormat): Promise> { + private async toPresentation(frame: ScriptCallFrame, formatArgs?: DebugProtocol.StackFrameFormat): Promise { // DIEGO TODO: Make getReadonlyOrigin work again // this.getReadonlyOrigin(frame.location.script.runtimeSource.identifier.textRepresentation) - const locationInLoadedSource = frame.location.mappedToSource(); - let presentationHint: CallFramePresentationHint = 'normal'; // Apply hints to skipped frames const getSkipReason = (reason: string) => localize('skipReason', "(skipped by '{0}')", reason); + const locationInLoadedSource = frame.location.mappedToSource(); const providedDetails: ICallFramePresentationDetails[] = [].concat(await asyncMap([this._stackTracePresentationLogicProviders], provider => provider.getCallFrameAdditionalDetails(locationInLoadedSource))); const actualDetails = providedDetails.length === 0 @@ -129,11 +112,8 @@ export class StackTracesLogic implements IComponent { sourcePresentationHint: actualDetails[0].sourcePresentationHint // We know that actualDetails.length > 0 }; - const formattedName = this.formatStackFrameName(frame.name, locationInLoadedSource, formatArgs); - const codeFlow = new CodeFlowFrame(frame.index, new FormattedName(formattedName), locationInLoadedSource); - const callFrame = new LoadedSourceCallFrame(frame, codeFlow); - - return new CallFramePresentation(callFrame, presentationDetails, presentationHint); + return new CallFramePresentation(frame.mappedToSource(), + new CustomCallFrameDescriptionFormatter(frame, formatArgs), presentationDetails, presentationHint); } public async install(): Promise { diff --git a/src/chrome/internal/stepping/features/syncStepping.ts b/src/chrome/internal/stepping/features/syncStepping.ts index 18f41cad3..dcb1e7205 100644 --- a/src/chrome/internal/stepping/features/syncStepping.ts +++ b/src/chrome/internal/stepping/features/syncStepping.ts @@ -1,6 +1,4 @@ -import { ICallFrame } from '../../stackTraces/callFrame'; - -import { IScript } from '../../scripts/script'; +import { ScriptCallFrame } from '../../stackTraces/callFrame'; import { InformationAboutPausedProvider, } from '../../features/takeProperActionOnPausedEvent'; import { IComponent } from '../../features/feature'; import { Abstained, Vote } from '../../../communication/collaborativeDecision'; @@ -53,7 +51,7 @@ export class SyncStepping implements IComponent { return new Abstained(this); } - public async restartFrame(callFrame: ICallFrame): Promise { + public async restartFrame(callFrame: ScriptCallFrame): Promise { this._status = this._status.startStepping(); await this._debugeeStepping.restartFrame(callFrame); await this._debugeeStepping.stepInto({ breakOnAsyncCall: true }); diff --git a/src/chrome/internal/stepping/stepping.ts b/src/chrome/internal/stepping/stepping.ts index 579c77429..8d48b61bc 100644 --- a/src/chrome/internal/stepping/stepping.ts +++ b/src/chrome/internal/stepping/stepping.ts @@ -1,8 +1,7 @@ import { IComponent } from '../features/feature'; import { AsyncStepping } from './features/asyncStepping'; import { SyncStepping } from './features/syncStepping'; -import { ICallFrame } from '../stackTraces/callFrame'; -import { IScript } from '../scripts/script'; +import { ScriptCallFrame } from '../stackTraces/callFrame'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; @@ -28,7 +27,7 @@ export class Stepping implements IComponent { return this._syncStepping.pause(); } - public restartFrame(callFrame: ICallFrame): Promise { + public restartFrame(callFrame: ScriptCallFrame): Promise { return this._syncStepping.restartFrame(callFrame); } diff --git a/src/chrome/internalSourceBreakpoint.ts b/src/chrome/internalSourceBreakpoint.ts index 0267bba06..e4a5b39f4 100644 --- a/src/chrome/internalSourceBreakpoint.ts +++ b/src/chrome/internalSourceBreakpoint.ts @@ -3,8 +3,7 @@ *--------------------------------------------------------*/ import { DebugProtocol } from 'vscode-debugprotocol'; -import { IScript } from './internal/scripts/script'; -import { CodeFlowStackTrace } from './internal/stackTraces/stackTrace'; +import { CodeFlowStackTrace } from './internal/stackTraces/codeFlowStackTrace'; import { parseResourceIdentifier } from './internal/sources/resourceIdentifier'; import { createCDTPScriptUrl } from './internal/sources/resourceIdentifierSubtypes'; @@ -32,12 +31,12 @@ export class InternalSourceBreakpoint { } } -function isLogpointStack(stackTrace: CodeFlowStackTrace | null): boolean { +function isLogpointStack(stackTrace: CodeFlowStackTrace | null): boolean { return stackTrace && stackTrace.codeFlowFrames.length > 0 && stackTrace.codeFlowFrames[0].script.runtimeSource.identifier.isEquivalentTo(parseResourceIdentifier(createCDTPScriptUrl(InternalSourceBreakpoint.LOGPOINT_URL))); } -export function stackTraceWithoutLogpointFrame(stackTrace: CodeFlowStackTrace): CodeFlowStackTrace { +export function stackTraceWithoutLogpointFrame(stackTrace: CodeFlowStackTrace): CodeFlowStackTrace { if (isLogpointStack(stackTrace)) { return { ...stackTrace, diff --git a/src/chrome/variables.ts b/src/chrome/variables.ts index 2eea8bc4c..041212c16 100644 --- a/src/chrome/variables.ts +++ b/src/chrome/variables.ts @@ -8,7 +8,7 @@ import { Handles } from 'vscode-debugadapter'; import { ChromeDebugLogic, VariableContext } from './chromeDebugAdapter'; import { Protocol as CDTP } from 'devtools-protocol'; import * as utils from '../utils'; -import { ICallFrame, ScriptOrLoadedSource } from './internal/stackTraces/callFrame'; +import { LoadedSourceCallFrame } from './internal/stackTraces/callFrame'; export interface IVariableContainer { expand(adapter: ChromeDebugLogic, filter?: string, start?: number, count?: number): Promise; @@ -47,10 +47,10 @@ export class LoggedObjects extends BaseVariableContainer { export class ScopeContainer extends BaseVariableContainer { private _thisObj: CDTP.Runtime.RemoteObject; private _returnValue: CDTP.Runtime.RemoteObject; - private _frameId: ICallFrame; + private _frameId: LoadedSourceCallFrame; private _origScopeIndex: number; - public constructor(frameId: ICallFrame, origScopeIndex: number, objectId: string, thisObj?: CDTP.Runtime.RemoteObject, returnValue?: CDTP.Runtime.RemoteObject) { + public constructor(frameId: LoadedSourceCallFrame, origScopeIndex: number, objectId: string, thisObj?: CDTP.Runtime.RemoteObject, returnValue?: CDTP.Runtime.RemoteObject) { super(objectId, ''); this._thisObj = thisObj; this._returnValue = returnValue; From 34f891103d425860e9c335dfc98e2cadb2f46752 Mon Sep 17 00:00:00 2001 From: digeff Date: Thu, 17 Jan 2019 12:26:35 -0800 Subject: [PATCH 10/23] Applied Stack Traces model feedback --- .../protocolParsers/cdtpStackTraceParser.ts | 4 +- .../client/chromeDebugAdapter/connectedCDA.ts | 10 ++- src/chrome/client/internalToClient.ts | 3 +- src/chrome/consoleHelper.ts | 3 +- src/chrome/internal/features/skipFiles.ts | 4 +- src/chrome/internal/stackTraces/callFrame.ts | 13 ++-- .../stackTraces/callFrameDescription.ts | 38 ------------ .../internal/stackTraces/callFrameFunction.ts | 38 ------------ .../stackTraces/callFramePresentation.ts | 61 +++++-------------- .../stackTraces/codeFlowFramePresentation.ts | 18 ------ .../stackTraces/formatCallFrameDescription.ts | 25 ++++++++ .../stackTraces/stackTracePresentationRow.ts | 12 ---- .../internal/stackTraces/stackTracesLogic.ts | 3 +- 13 files changed, 57 insertions(+), 175 deletions(-) delete mode 100644 src/chrome/internal/stackTraces/callFrameDescription.ts delete mode 100644 src/chrome/internal/stackTraces/callFrameFunction.ts delete mode 100644 src/chrome/internal/stackTraces/codeFlowFramePresentation.ts create mode 100644 src/chrome/internal/stackTraces/formatCallFrameDescription.ts diff --git a/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts index fc0452a0b..65d80e4a3 100644 --- a/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts +++ b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts @@ -3,7 +3,6 @@ import { Protocol as CDTP } from 'devtools-protocol'; import { IScript, } from '../../internal/scripts/script'; import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; import { CodeFlowFrame } from '../../internal/stackTraces/callFrame'; -import { createCallFrameFunction } from '../../internal/stackTraces/callFrameFunction'; import { CDTPLocationParser, HasScriptLocation } from './cdtpLocationParser'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { asyncMap } from '../../collections/async'; @@ -25,8 +24,7 @@ export class CDTPStackTraceParser { public async toCodeFlowFrame(index: number, callFrame: CDTP.Runtime.CallFrame | CDTP.Debugger.CallFrame, location: HasScriptLocation): Promise> { const scriptLocation = await this._cdtpLocationParser.getLocationInScript(location); - const name = createCallFrameFunction(scriptLocation.script, callFrame.functionName); - return new CodeFlowFrame(index, name, scriptLocation); + return new CodeFlowFrame(index, callFrame.functionName, scriptLocation); } constructor(private _scriptsRegistry: CDTPScriptsRegistry) { } diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts index 7dda78917..a3ba1435e 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts @@ -23,6 +23,7 @@ import { IDebuggeeRunner } from '../../debugeeStartup/debugeeLauncher'; import { StepProgressEventsEmitter } from '../../../executionTimingsReporter'; import { TelemetryPropertyCollector, ITelemetryPropertyCollector } from '../../../telemetry'; import { ICommunicator, utils } from '../../..'; +import { CallFramePresentation } from '../../internal/stackTraces/callFramePresentation'; // TODO DIEGO: Remember to call here and only here this._lineColTransformer.convertDebuggerLocationToClient(stackFrame); for all responses @injectable() @@ -121,7 +122,7 @@ export class ConnectedCDA implements IDebugAdapterState { public async restartFrame(args: DebugProtocol.RestartFrameRequest): Promise { const callFrame = this._clientToInternal.getCallFrameById(args.arguments.frameId); - if (callFrame.isCallFrame()) { + if (callFrame instanceof CallFramePresentation) { return this._stepping.restartFrame(callFrame.callFrame.unmappedCallFrame); } else { throw new Error(`Cannot restart to a frame that doesn't have state information`); @@ -139,13 +140,10 @@ export class ConnectedCDA implements IDebugAdapterState { public scopes(args: DebugProtocol.ScopesArguments, _?: ITelemetryPropertyCollector, _2?: number): PromiseOrNot { const frame = this._clientToInternal.getCallFrameById(args.frameId); - if (frame.isCallFrame()) { + if (frame instanceof CallFramePresentation) { return this._chromeDebugAdapter.scopes(frame.callFrame); } else { - const reason = frame.isNotLabel() - ? 'a code flow frame only has code flow information' - : 'a label frame is only a description of the different sections of the call stack'; - throw new Error(`Can't get scopes for the frame because ${reason}`); + throw new Error(`Can't get scopes for the frame because a label frame is only a description of the different sections of the call stack`); } } diff --git a/src/chrome/client/internalToClient.ts b/src/chrome/client/internalToClient.ts index a9038f6fe..18f93512d 100644 --- a/src/chrome/client/internalToClient.ts +++ b/src/chrome/client/internalToClient.ts @@ -14,6 +14,7 @@ import { injectable, inject } from 'inversify'; import { TYPES } from '../dependencyInjection.ts/types'; import { Source } from 'vscode-debugadapter'; import { StackTracePresentationRow, StackTraceLabel } from '../internal/stackTraces/StackTracePresentationRow'; +import { CallFramePresentation } from '../internal/stackTraces/callFramePresentation'; interface ClientLocationInSource { source: DebugProtocol.Source; @@ -32,7 +33,7 @@ export class InternalToClient { } public async toStackFrame(stackFrame: StackTracePresentationRow): Promise { - if (stackFrame.isNotLabel()) { + if (stackFrame instanceof CallFramePresentation) { const clientStackFrame: RemoveProperty = { id: this.getFrameId(stackFrame), name: stackFrame.description, diff --git a/src/chrome/consoleHelper.ts b/src/chrome/consoleHelper.ts index 9abbeaa18..11f26041f 100644 --- a/src/chrome/consoleHelper.ts +++ b/src/chrome/consoleHelper.ts @@ -7,6 +7,7 @@ import * as Color from 'color'; import * as variables from './variables'; import { CodeFlowStackTrace } from './internal/stackTraces/codeFlowStackTrace'; import { ExceptionDetails } from './cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider'; +import { functionDescription } from './internal/stackTraces/callFramePresentation'; export function formatExceptionDetails(e: ExceptionDetails): string { if (!e.exception) { @@ -215,7 +216,7 @@ function stackTraceToString(stackTrace: CodeFlowStackTrace): string { return stackTrace.codeFlowFrames .map(frame => { - const fnName = frame.functionDescription; + const fnName = functionDescription(frame.functionName, frame.script); const fileName = frame.script.developmentSource.identifier.textRepresentation; return ` at ${fnName} (${fileName}:${frame.lineNumber + 1}:${frame.columnNumber})`; }) diff --git a/src/chrome/internal/features/skipFiles.ts b/src/chrome/internal/features/skipFiles.ts index 65e15f371..c1ead6e4b 100644 --- a/src/chrome/internal/features/skipFiles.ts +++ b/src/chrome/internal/features/skipFiles.ts @@ -5,7 +5,7 @@ import { StackTracesLogic, IStackTracePresentationLogicProvider } from '../stack import { newResourceIdentifierMap, IResourceIdentifier, parseResourceIdentifier } from '../sources/resourceIdentifier'; import { IComponent } from './feature'; import { LocationInLoadedSource } from '../locations/location'; -import { ICallFramePresentationDetails } from '../stackTraces/callFramePresentation'; +import { ICallFramePresentationDetails, CallFramePresentation } from '../stackTraces/callFramePresentation'; import * as nls from 'vscode-nls'; import { injectable, inject, LazyServiceIdentifer } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; @@ -151,7 +151,7 @@ export class SkipFilesLogic implements IComponent, ISta const currentStack = await this.stackTracesLogic.stackTrace({ threadId: undefined }); return currentStack.stackFrames.some(frame => { - return frame.isNotLabel() + return (frame instanceof CallFramePresentation) && frame.codeFlow.location.source && frame.codeFlow.location.source.isEquivalentTo(resolvedSource); }); diff --git a/src/chrome/internal/stackTraces/callFrame.ts b/src/chrome/internal/stackTraces/callFrame.ts index 9f700b8f1..75ad3d5d5 100644 --- a/src/chrome/internal/stackTraces/callFrame.ts +++ b/src/chrome/internal/stackTraces/callFrame.ts @@ -2,7 +2,6 @@ import { Location } from '../locations/location'; import { ILoadedSource } from '../sources/loadedSource'; import { IScript } from '../scripts/script'; import { Protocol as CDTP } from 'devtools-protocol'; -import { ICallFrameFunction } from './callFrameFunction'; import { Scope } from './scopes'; import { integer } from '../../cdtpDebuggee/cdtpPrimitives'; @@ -22,7 +21,7 @@ export type ScriptOrLoadedSource = IScript | ILoadedSource; export class CodeFlowFrame { constructor( public readonly index: integer, - public readonly callFrameFunction: ICallFrameFunction, + public readonly functionName: string | undefined, public readonly location: Location) { } public get source(): TResource extends ILoadedSource ? TResource : never { @@ -40,10 +39,6 @@ export class CodeFlowFrame { public get columnNumber(): number { return this.location.position.columnNumber; } - - public get functionDescription(): string { - return this.callFrameFunction.description; - } } /** This interface represents both the code flow and the state of a call frame. @@ -89,8 +84,8 @@ abstract class CallFrameCommonLogic impl return this.codeFlow.index; } - public get functionDescription(): string { - return this.codeFlow.functionDescription; + public get functionName(): string { + return this.codeFlow.functionName; } } @@ -104,7 +99,7 @@ export class ScriptCallFrame extends CallFrameCommonLogic { } public mappedToSource(): LoadedSourceCallFrame { - const codeFlow = new CodeFlowFrame(this.index, this.codeFlow.callFrameFunction, this.location.mappedToSource()); + const codeFlow = new CodeFlowFrame(this.index, this.codeFlow.functionName, this.location.mappedToSource()); return new LoadedSourceCallFrame(this, codeFlow); } } diff --git a/src/chrome/internal/stackTraces/callFrameDescription.ts b/src/chrome/internal/stackTraces/callFrameDescription.ts deleted file mode 100644 index ce50e9514..000000000 --- a/src/chrome/internal/stackTraces/callFrameDescription.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as path from 'path'; -import { DebugProtocol } from 'vscode-debugprotocol'; -import { ScriptCallFrame } from './callFrame'; - -/** The clients can requests the stack traces frames descriptions in different formats. - * We use this class to create the description for the call frame according to the parameters supplied by the client. - */ - -const ImplementsCallFrameDescriptionFormatter = Symbol(); -export interface ICallFrameDescriptionFormatter { - readonly description: string; - - [ImplementsCallFrameDescriptionFormatter]: void; -} - -export class CustomCallFrameDescriptionFormatter implements ICallFrameDescriptionFormatter { - [ImplementsCallFrameDescriptionFormatter]: void; - - public get description(): string { - const locationInLoadedSource = this._callFrame.location.mappedToSource(); - - let formattedDescription = this._callFrame.functionDescription; - - if (this._formatArgs) { - if (this._formatArgs.module) { - formattedDescription += ` [${path.basename(locationInLoadedSource.source.identifier.textRepresentation)}]`; - } - - if (this._formatArgs.line) { - formattedDescription += ` Line ${locationInLoadedSource.position.lineNumber}`; - } - } - - return formattedDescription; - } - - constructor(private readonly _callFrame: ScriptCallFrame, private readonly _formatArgs?: DebugProtocol.StackFrameFormat) { } -} diff --git a/src/chrome/internal/stackTraces/callFrameFunction.ts b/src/chrome/internal/stackTraces/callFrameFunction.ts deleted file mode 100644 index d9a275586..000000000 --- a/src/chrome/internal/stackTraces/callFrameFunction.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { IScript } from '../scripts/script'; - -/** We use these classes to generate a proper description for the function - * based on wheter it is named, and the script where it's at is named - */ -const ImplementsCallFrameFunction = Symbol(); -export interface ICallFrameFunction { - readonly description: string; - [ImplementsCallFrameFunction]: void; -} - -class CallFrameForNamedFunction implements ICallFrameFunction { - [ImplementsCallFrameFunction]: void; - - constructor(public readonly description: string) { } -} - -class CallFrameForUnamedFunctionInUnnamedScript implements ICallFrameFunction { - [ImplementsCallFrameFunction]: void; - - public readonly description = '(eval code)'; -} - -class CallFrameForUnamedFunctionInNamedScript implements ICallFrameFunction { - [ImplementsCallFrameFunction]: void; - - public readonly description = '(anonymous function)'; -} - -export function createCallFrameFunction(script: IScript, functionName: string) { - if (functionName) { - return new CallFrameForNamedFunction(functionName); - } else if (script.runtimeSource.doesScriptHasUrl()) { - return new CallFrameForUnamedFunctionInNamedScript(); - } else { - return new CallFrameForUnamedFunctionInUnnamedScript(); - } -} diff --git a/src/chrome/internal/stackTraces/callFramePresentation.ts b/src/chrome/internal/stackTraces/callFramePresentation.ts index 57ec31be8..d91e22c15 100644 --- a/src/chrome/internal/stackTraces/callFramePresentation.ts +++ b/src/chrome/internal/stackTraces/callFramePresentation.ts @@ -2,7 +2,9 @@ import { Location } from '../locations/location'; import { ILoadedSource } from '../sources/loadedSource'; import { CodeFlowFrame, ICallFrame, CallFrame } from './callFrame'; import { StackTracePresentationRow, CallFramePresentationHint } from './stackTracePresentationRow'; -import { ICallFrameDescriptionFormatter } from './callFrameDescription'; +import { formatCallFrameDescription } from './formatCallFrameDescription'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { IScript } from '../scripts/script'; export type SourcePresentationHint = 'normal' | 'emphasize' | 'deemphasize'; @@ -11,20 +13,7 @@ export interface ICallFramePresentationDetails { readonly sourcePresentationHint: SourcePresentationHint; } -export interface ICodeFlowFramePresentation extends StackTracePresentationRow { - readonly description: string; - readonly source: ILoadedSource; - readonly location: Location; - readonly lineNumber: number; - readonly columnNumber: number; - readonly codeFlow: CodeFlowFrame; -} - -export abstract class FramePresentationCommonLogic implements ICodeFlowFramePresentation { - public abstract get codeFlow(): CodeFlowFrame; - public abstract isCallFrame(): this is CallFramePresentation; - public abstract get description(): string; - +export class CallFramePresentation implements StackTracePresentationRow { public get source(): ILoadedSource { return this.codeFlow.source; } @@ -41,16 +30,6 @@ export abstract class FramePresentationCommonLogic implements ICodeFlowFramePres return this.codeFlow.columnNumber; } - public isNotLabel(): this is ICodeFlowFramePresentation { - return true; - } - - constructor( - public readonly additionalPresentationDetails?: ICallFramePresentationDetails, - public readonly presentationHint?: CallFramePresentationHint) { } -} - -export class CallFramePresentation extends FramePresentationCommonLogic implements StackTracePresentationRow { public get codeFlow(): CodeFlowFrame { return (>this.callFrame).codeFlow; // TODO: Figure out how to remove the cast } @@ -60,31 +39,23 @@ export class CallFramePresentation extends FramePresentationCommonLogic implemen } public get description(): string { - return this._descriptionFormatter.description; + return formatCallFrameDescription(this.callFrame, this._descriptionFormatArgs); } constructor( public readonly callFrame: CallFrame, - private readonly _descriptionFormatter: ICallFrameDescriptionFormatter, - additionalPresentationDetails?: ICallFramePresentationDetails, - presentationHint?: CallFramePresentationHint) { - super(additionalPresentationDetails, presentationHint); + private readonly _descriptionFormatArgs?: DebugProtocol.StackFrameFormat, + public readonly additionalPresentationDetails?: ICallFramePresentationDetails, + public readonly presentationHint?: CallFramePresentationHint) { } } -export class CodeFlowFramePresentation extends FramePresentationCommonLogic implements StackTracePresentationRow { - public get description(): string { - return this.codeFlow.functionDescription; - } - - public isCallFrame(): this is CallFramePresentation { - return false; +export function functionDescription(functionName: string | undefined, functionModule: IScript): string { + if (functionName) { + return functionName; + } else if (functionModule.runtimeSource.doesScriptHasUrl()) { + return '(anonymous function)'; + } else { + return '(eval code)'; } - - constructor( - public readonly codeFlow: CodeFlowFrame, - additionalPresentationDetails?: ICallFramePresentationDetails, - presentationHint?: CallFramePresentationHint) { - super(additionalPresentationDetails, presentationHint); - } -} +} \ No newline at end of file diff --git a/src/chrome/internal/stackTraces/codeFlowFramePresentation.ts b/src/chrome/internal/stackTraces/codeFlowFramePresentation.ts deleted file mode 100644 index 955bde3a5..000000000 --- a/src/chrome/internal/stackTraces/codeFlowFramePresentation.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ILoadedSource } from '../sources/loadedSource'; -import { CodeFlowFrame } from './callFrame'; -import { StackTracePresentationRow, CallFramePresentationHint } from './stackTracePresentationRow'; -import { FramePresentationCommonLogic, CallFramePresentation, ICallFramePresentationDetails } from './callFramePresentation'; - -export class CodeFlowFramePresentation extends FramePresentationCommonLogic implements StackTracePresentationRow { - constructor(public readonly codeFlow: CodeFlowFrame, additionalPresentationDetails?: ICallFramePresentationDetails, presentationHint?: CallFramePresentationHint) { - super(additionalPresentationDetails, presentationHint); - } - - public get description(): string { - return this.codeFlow.functionDescription; - } - - public isCallFrame(): this is CallFramePresentation { - return false; - } -} diff --git a/src/chrome/internal/stackTraces/formatCallFrameDescription.ts b/src/chrome/internal/stackTraces/formatCallFrameDescription.ts new file mode 100644 index 000000000..ae7a4ae75 --- /dev/null +++ b/src/chrome/internal/stackTraces/formatCallFrameDescription.ts @@ -0,0 +1,25 @@ +import * as path from 'path'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { LoadedSourceCallFrame } from './callFrame'; +import { functionDescription } from './callFramePresentation'; + +/** The clients can requests the stack traces frames descriptions in different formats. + * We use this function to create the description for the call frame according to the parameters supplied by the client. + */ +export function formatCallFrameDescription(callFrame: LoadedSourceCallFrame, formatArgs?: DebugProtocol.StackFrameFormat): string { + const location = callFrame.location; + + let formattedDescription = functionDescription(callFrame.codeFlow.functionName, location.source.script); + + if (formatArgs) { + if (formatArgs.module) { + formattedDescription += ` [${path.basename(location.source.identifier.textRepresentation)}]`; + } + + if (formatArgs.line) { + formattedDescription += ` Line ${location.position.lineNumber}`; + } + } + + return formattedDescription; +} diff --git a/src/chrome/internal/stackTraces/stackTracePresentationRow.ts b/src/chrome/internal/stackTraces/stackTracePresentationRow.ts index 55cce713c..2a0a837f0 100644 --- a/src/chrome/internal/stackTraces/stackTracePresentationRow.ts +++ b/src/chrome/internal/stackTraces/stackTracePresentationRow.ts @@ -1,25 +1,13 @@ -import { ICodeFlowFramePresentation, CallFramePresentation } from './callFramePresentation'; - export type CallFramePresentationHint = 'normal' | 'label' | 'subtle'; // Row of a stack trace that we send to the client export interface StackTracePresentationRow { readonly presentationHint?: CallFramePresentationHint; - isNotLabel(): this is ICodeFlowFramePresentation; - isCallFrame(): this is CallFramePresentation; } // Row of a stack trace that is a label e.g.: [Show more frames] or [Frames skipped by smartStep], etc... export class StackTraceLabel implements StackTracePresentationRow { public readonly presentationHint = 'label'; - public isCallFrame(): this is CallFramePresentation { - return false; - } - - public isNotLabel(): this is ICodeFlowFramePresentation { - return false; - } - constructor(public readonly description: string) { } } diff --git a/src/chrome/internal/stackTraces/stackTracesLogic.ts b/src/chrome/internal/stackTraces/stackTracesLogic.ts index 8c2a4b430..9cb5ee067 100644 --- a/src/chrome/internal/stackTraces/stackTracesLogic.ts +++ b/src/chrome/internal/stackTraces/stackTracesLogic.ts @@ -19,7 +19,6 @@ import { TYPES } from '../../dependencyInjection.ts/types'; import { ConnectedCDAConfiguration } from '../../..'; import { Vote, Abstained } from '../../communication/collaborativeDecision'; import { IAsyncDebuggingConfigurer } from '../../cdtpDebuggee/features/CDTPAsyncDebuggingConfigurer'; -import { CustomCallFrameDescriptionFormatter } from './callFrameDescription'; import { StackTracePresentationRow, StackTraceLabel, CallFramePresentationHint } from './stackTracePresentationRow'; export interface EventsConsumedByStackTrace { @@ -113,7 +112,7 @@ export class StackTracesLogic implements IComponent { }; return new CallFramePresentation(frame.mappedToSource(), - new CustomCallFrameDescriptionFormatter(frame, formatArgs), presentationDetails, presentationHint); + formatArgs, presentationDetails, presentationHint); } public async install(): Promise { From aa61fbc29736504e2833d5f4a4d6b87db07953ee Mon Sep 17 00:00:00 2001 From: digeff Date: Thu, 17 Jan 2019 16:37:45 -0800 Subject: [PATCH 11/23] Merge fixes --- src/transformers/basePathTransformer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/transformers/basePathTransformer.ts b/src/transformers/basePathTransformer.ts index 9f795771b..fb835108c 100644 --- a/src/transformers/basePathTransformer.ts +++ b/src/transformers/basePathTransformer.ts @@ -5,7 +5,7 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { IResourceIdentifier } from '../chrome/internal/sources/resourceIdentifier'; -import { StackTracePresentation } from '../chrome/internal/stackTraces/stackTracePresentation'; +import { IStackTracePresentation } from '../chrome/internal/stackTraces/stackTracePresentation'; import { IComponent } from '../chrome/internal/features/feature'; import { injectable } from 'inversify'; @@ -28,7 +28,7 @@ export class BasePathTransformer implements IComponent { return this.getClientPathFromTargetPath(targetPath) || targetPath; } - public stackTraceResponse(_response: StackTracePresentation): void { + public stackTraceResponse(_response: IStackTracePresentation): void { } public async fixSource(_source: DebugProtocol.Source): Promise { From 36bd267df3389623a76d6e48854b19af9f2625ee Mon Sep 17 00:00:00 2001 From: digeff Date: Thu, 17 Jan 2019 16:52:54 -0800 Subject: [PATCH 12/23] Add copyright --- src/chrome/cdtpDebuggee/cdtpPrimitives.ts | 4 ++++ .../eventsProviders/cdtpConsoleEventsProvider.ts | 4 ++++ .../eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts | 4 ++++ .../eventsProviders/cdtpExceptionThrownEventsProvider.ts | 4 ++++ .../eventsProviders/cdtpExecutionContextEventsProvider.ts | 4 ++++ .../cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts | 4 ++++ .../eventsProviders/cdtpOnScriptParsedEventProvider.ts | 4 ++++ src/chrome/cdtpDebuggee/features/CDTPSchema.ts | 6 +++++- .../cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer.ts | 4 ++++ .../cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts | 4 ++++ .../cdtpDebuggee/features/cdtpBreakpointFeaturesSupport.ts | 4 ++++ src/chrome/cdtpDebuggee/features/cdtpBrowserNavigator.ts | 4 ++++ .../features/cdtpDOMInstrumentationBreakpoints.ts | 4 ++++ .../cdtpDebuggee/features/cdtpDebugeeExecutionController.ts | 4 ++++ .../features/cdtpDebugeeRuntimeVersionProvider.ts | 4 ++++ .../cdtpDebuggee/features/cdtpDebugeeSteppingController.ts | 4 ++++ src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts | 4 ++++ src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts | 4 ++++ .../cdtpDebuggee/features/cdtpNetworkCacheConfiguration.ts | 4 ++++ .../features/cdtpPauseOnExceptionsConfigurer.ts | 6 +++++- src/chrome/cdtpDebuggee/features/cdtpPausedOverlay.ts | 4 ++++ src/chrome/cdtpDebuggee/features/cdtpRuntime.ts | 6 +++++- .../cdtpDebuggee/features/cdtpScriptSourcesRetriever.ts | 6 +++++- src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts | 6 +++++- .../cdtpDebuggee/infrastructure/cdtpDiagnosticsModule.ts | 6 +++++- .../cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts | 6 +++++- .../cdtpDebuggee/protocolParsers/cdtpLocationParser.ts | 6 +++++- .../cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts | 6 +++++- .../cdtpDebuggee/registries/cdtpBreakpointIdsRegistry.ts | 6 +++++- src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts | 6 +++++- src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts | 6 +++++- src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts | 6 +++++- src/chrome/client/chromeDebugAdapter/cdaState.ts | 6 +++++- .../client/chromeDebugAdapter/chromeDebugAdapterV2.ts | 6 +++++- src/chrome/client/chromeDebugAdapter/connectedCDA.ts | 6 +++++- src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts | 6 +++++- src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts | 6 +++++- .../client/chromeDebugAdapter/unconnectedCDACommonLogic.ts | 4 ++++ src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts | 4 ++++ src/chrome/client/clientToInternal.ts | 4 ++++ src/chrome/client/delayMessagesUntilInitializedSession.ts | 4 ++++ src/chrome/client/doNotPauseWhileSteppingSession.ts | 4 ++++ src/chrome/client/eventSender.ts | 4 ++++ src/chrome/client/handlesRegistry.ts | 4 ++++ src/chrome/client/internalToClient.ts | 4 ++++ src/chrome/client/requests.ts | 4 ++++ src/chrome/client/session.ts | 4 ++++ src/chrome/collections/async.ts | 4 ++++ src/chrome/collections/bidirectionalMap.ts | 4 ++++ src/chrome/collections/mapUsingProjection.ts | 4 ++++ src/chrome/collections/printing.ts | 4 ++++ src/chrome/collections/printting.ts | 4 ++++ src/chrome/collections/setUsingProjection.ts | 4 ++++ src/chrome/collections/utilities.ts | 4 ++++ src/chrome/collections/validatedMap.ts | 4 ++++ src/chrome/collections/validatedMultiMap.ts | 4 ++++ src/chrome/communication/channel.ts | 4 ++++ src/chrome/communication/channelIdentifier.ts | 4 ++++ src/chrome/communication/collaborativeDecision.ts | 4 ++++ src/chrome/communication/communicator.ts | 4 ++++ src/chrome/communication/internalChannels.ts | 4 ++++ src/chrome/communication/listeners.ts | 4 ++++ src/chrome/communication/notificationsCommunicator.ts | 4 ++++ src/chrome/communication/requestsCommunicator.ts | 4 ++++ src/chrome/communication/targetChannels.ts | 4 ++++ src/chrome/communication/transformedListenerRegistry.ts | 4 ++++ src/chrome/debugeeStartup/debugeeLauncher.ts | 4 ++++ src/chrome/dependencyInjection.ts/bind.ts | 4 ++++ src/chrome/dependencyInjection.ts/di.ts | 4 ++++ src/chrome/dependencyInjection.ts/types.ts | 4 ++++ src/chrome/extensibility/extensibilityPoints.ts | 4 ++++ src/chrome/internal/breakpoints/bpActionWhenHit.ts | 4 ++++ src/chrome/internal/breakpoints/bpRecipie.ts | 4 ++++ .../internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts | 4 ++++ src/chrome/internal/breakpoints/bpRecipieStatus.ts | 4 ++++ src/chrome/internal/breakpoints/bpRecipies.ts | 4 ++++ src/chrome/internal/breakpoints/bpsDeltaCalculator.ts | 4 ++++ src/chrome/internal/breakpoints/breakpoint.ts | 4 ++++ src/chrome/internal/breakpoints/breakpointsLogic.ts | 4 ++++ src/chrome/internal/breakpoints/breakpointsRegistry.ts | 4 ++++ .../internal/breakpoints/clientCurrentBPRecipiesRegistry.ts | 4 ++++ .../internal/breakpoints/features/hitCountBreakpoints.ts | 4 ++++ .../breakpoints/features/pauseScriptLoadsToSetBPs.ts | 4 ++++ .../breakpoints/features/reAddBPsWhenSourceIsLoaded.ts | 4 ++++ src/chrome/internal/breakpoints/hitCountConditionParser.ts | 4 ++++ .../internal/breakpoints/registries/bpRecipieRegistry.ts | 4 ++++ src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts | 4 ++++ src/chrome/internal/domains/supportedDomains.ts | 4 ++++ src/chrome/internal/exceptions/pauseOnException.ts | 4 ++++ src/chrome/internal/exceptions/strategies.ts | 4 ++++ src/chrome/internal/features/feature.ts | 4 ++++ src/chrome/internal/features/skipFiles.ts | 4 ++++ src/chrome/internal/features/smartStep.ts | 4 ++++ .../internal/features/takeProperActionOnPausedEvent.ts | 4 ++++ src/chrome/internal/formattedExceptionParser.ts | 4 ++++ src/chrome/internal/locations/location.ts | 4 ++++ src/chrome/internal/locations/rangeInScript.ts | 4 ++++ src/chrome/internal/locations/subtypes.ts | 4 ++++ src/chrome/internal/requests.ts | 4 ++++ src/chrome/internal/scripts/executionContext.ts | 4 ++++ src/chrome/internal/scripts/script.ts | 4 ++++ src/chrome/internal/scripts/scriptsRegistry.ts | 4 ++++ src/chrome/internal/scripts/sourcesMapper.ts | 4 ++++ src/chrome/internal/services/logging.ts | 4 ++++ src/chrome/internal/sources/features/dotScriptsCommand.ts | 4 ++++ .../sources/features/notifyClientOfLoadedSources.ts | 4 ++++ src/chrome/internal/sources/loadedSource.ts | 4 ++++ src/chrome/internal/sources/resourceIdentifier.ts | 4 ++++ src/chrome/internal/sources/resourceIdentifierSubtypes.ts | 4 ++++ src/chrome/internal/sources/source.ts | 4 ++++ src/chrome/internal/sources/sourceResolver.ts | 4 ++++ src/chrome/internal/sources/sourcesLogic.ts | 4 ++++ src/chrome/internal/sources/sourcesTextLogic.ts | 4 ++++ src/chrome/internal/sources/sourcesTreeNodeLogic.ts | 4 ++++ src/chrome/internal/sources/unresolvedSource.ts | 4 ++++ .../internal/stackTraces/formatCallFrameDescription.ts | 4 ++++ src/chrome/internal/stackTraces/stackTracesLogic.ts | 4 ++++ src/chrome/internal/stepping/features/asyncStepping.ts | 4 ++++ src/chrome/internal/stepping/features/syncStepping.ts | 4 ++++ src/chrome/internal/stepping/stepping.ts | 4 ++++ src/chrome/logging/executionLogger.ts | 4 ++++ src/chrome/logging/methodsCalledLogger.ts | 4 ++++ src/chrome/utils/combine.ts | 4 ++++ src/chrome/utils/equivalence.ts | 4 ++++ src/chrome/utils/failures.ts | 4 ++++ src/chrome/utils/lazy.ts | 4 ++++ src/chrome/utils/localization.ts | 4 ++++ src/chrome/utils/namespaceReverseLookupCreator.ts | 4 ++++ src/chrome/utils/promises.ts | 4 ++++ src/chrome/utils/version.ts | 4 ++++ src/typeUtils.ts | 4 ++++ src/validation.ts | 4 ++++ 132 files changed, 546 insertions(+), 18 deletions(-) diff --git a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts index b2b9351e3..d2e9c4f61 100644 --- a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts +++ b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IScript } from '../internal/scripts/script'; import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; import { URLRegexp } from '../internal/locations/subtypes'; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts index ba8d328c8..7e3cd07d1 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; import { Protocol as CDTP } from 'devtools-protocol'; import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts index eb27a4847..4877f886c 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; import { asyncMap } from '../../collections/async'; import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts index 537ea7abe..bfc983d1b 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider.ts index 8ee9db842..f280b76d4 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; import { Protocol as CDTP } from 'devtools-protocol'; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts index 1bc4b5a2a..d89bb5809 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; import { Protocol as CDTP } from 'devtools-protocol'; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts index ec50ad0aa..781e7896d 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { CDTP, parseResourceIdentifier, BasePathTransformer, BaseSourceMapTransformer } from '../../..'; import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; diff --git a/src/chrome/cdtpDebuggee/features/CDTPSchema.ts b/src/chrome/cdtpDebuggee/features/CDTPSchema.ts index 920845245..a37a63a24 100644 --- a/src/chrome/cdtpDebuggee/features/CDTPSchema.ts +++ b/src/chrome/cdtpDebuggee/features/CDTPSchema.ts @@ -1,4 +1,8 @@ -import { Protocol as CDTP } from 'devtools-protocol'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { Protocol as CDTP } from 'devtools-protocol'; export class CDTPSchema { constructor(protected api: CDTP.SchemaApi) { } diff --git a/src/chrome/cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer.ts b/src/chrome/cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer.ts index 6ce247294..ccee93feb 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { inject, injectable } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts b/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts index c973a29ee..64a6e18a7 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { IScript } from '../../internal/scripts/script'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpBreakpointFeaturesSupport.ts b/src/chrome/cdtpDebuggee/features/cdtpBreakpointFeaturesSupport.ts index df6853739..e3abca386 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpBreakpointFeaturesSupport.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpBreakpointFeaturesSupport.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { Protocol as CDTP } from 'devtools-protocol'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpBrowserNavigator.ts b/src/chrome/cdtpDebuggee/features/cdtpBrowserNavigator.ts index 64eb07fe9..4f24a170d 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpBrowserNavigator.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpBrowserNavigator.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { injectable, inject } from 'inversify'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints.ts index 43f1202c2..adc5f900b 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { injectable, inject } from 'inversify'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebugeeExecutionController.ts b/src/chrome/cdtpDebuggee/features/cdtpDebugeeExecutionController.ts index 6974880e2..10ed4eb24 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebugeeExecutionController.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebugeeExecutionController.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts b/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts index 6fa8097f0..164f1d8a7 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { injectable, inject } from 'inversify'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts b/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts index 640ab512a..99c95b12b 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebugeeSteppingController.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { ScriptCallFrame } from '../../internal/stackTraces/callFrame'; import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts index d4859bf1d..205c3fa68 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp, BPRecipie, IBPRecipie } from '../../internal/breakpoints/bpRecipie'; import { AlwaysBreak, ConditionalBreak } from '../../internal/breakpoints/bpActionWhenHit'; import { BreakpointInScript, BreakpointInUrl, BreakpointInUrlRegexp, Breakpoint } from '../../internal/breakpoints/breakpoint'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts b/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts index e1a91c21f..dc1bf1770 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpNetworkCacheConfiguration.ts b/src/chrome/cdtpDebuggee/features/cdtpNetworkCacheConfiguration.ts index 14c818396..e9b4f2499 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpNetworkCacheConfiguration.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpNetworkCacheConfiguration.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; export interface INetworkCacheConfiguration { diff --git a/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts b/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts index 6299928b9..9dba4b272 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts @@ -1,4 +1,8 @@ -import { Protocol as CDTP } from 'devtools-protocol'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { Protocol as CDTP } from 'devtools-protocol'; import { PauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions } from '../../internal/exceptions/strategies'; import { inject, injectable } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpPausedOverlay.ts b/src/chrome/cdtpDebuggee/features/cdtpPausedOverlay.ts index 31be29214..6a2beb824 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpPausedOverlay.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpPausedOverlay.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { CDTPEnableableDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; import { Protocol as CDTP } from 'devtools-protocol'; import { TYPES } from '../../dependencyInjection.ts/types'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpRuntime.ts b/src/chrome/cdtpDebuggee/features/cdtpRuntime.ts index 4e7cc8894..900a38b62 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpRuntime.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpRuntime.ts @@ -1,4 +1,8 @@ -import { Protocol as CDTP } from 'devtools-protocol'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { Protocol as CDTP } from 'devtools-protocol'; export interface IRuntime { runIfWaitingForDebugger(): Promise; diff --git a/src/chrome/cdtpDebuggee/features/cdtpScriptSourcesRetriever.ts b/src/chrome/cdtpDebuggee/features/cdtpScriptSourcesRetriever.ts index 5242d6496..01d7a1646 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpScriptSourcesRetriever.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpScriptSourcesRetriever.ts @@ -1,4 +1,8 @@ -import { Protocol as CDTP } from 'devtools-protocol'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { Protocol as CDTP } from 'devtools-protocol'; import { IScript } from '../../internal/scripts/script'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { inject, injectable } from 'inversify'; diff --git a/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts b/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts index d88a9fb31..2a931fe1a 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts @@ -1,4 +1,8 @@ -import { Protocol as CDTP } from 'devtools-protocol'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { Protocol as CDTP } from 'devtools-protocol'; import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; import { TYPES } from '../../dependencyInjection.ts/types'; import { injectable, inject } from 'inversify'; diff --git a/src/chrome/cdtpDebuggee/infrastructure/cdtpDiagnosticsModule.ts b/src/chrome/cdtpDebuggee/infrastructure/cdtpDiagnosticsModule.ts index a7091be48..dc319c3b9 100644 --- a/src/chrome/cdtpDebuggee/infrastructure/cdtpDiagnosticsModule.ts +++ b/src/chrome/cdtpDebuggee/infrastructure/cdtpDiagnosticsModule.ts @@ -1,4 +1,8 @@ -import { TransformedListenerRegistry } from '../../communication/transformedListenerRegistry'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { TransformedListenerRegistry } from '../../communication/transformedListenerRegistry'; import { PromiseOrNot } from '../../utils/promises'; import { injectable } from 'inversify'; import { CDTPDomainsEnabler } from './cdtpDomainsEnabler'; diff --git a/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts b/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts index ebf4e4c66..498de5cfb 100644 --- a/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts +++ b/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts @@ -1,4 +1,8 @@ -import { IEnableableApi } from './cdtpDiagnosticsModule'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { IEnableableApi } from './cdtpDiagnosticsModule'; import { Protocol as CDTP } from 'devtools-protocol'; import { TYPES } from '../../dependencyInjection.ts/types'; import { inject, injectable } from 'inversify'; diff --git a/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts b/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts index 4232edb2c..b999bee0f 100644 --- a/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts +++ b/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts @@ -1,4 +1,8 @@ -import { Position, LocationInScript } from '../../internal/locations/location'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { Position, LocationInScript } from '../../internal/locations/location'; import { createColumnNumber, createLineNumber } from '../../internal/locations/subtypes'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { Protocol as CDTP } from 'devtools-protocol'; diff --git a/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts index 65d80e4a3..f0377396c 100644 --- a/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts +++ b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts @@ -1,4 +1,8 @@ -import { Protocol as CDTP } from 'devtools-protocol'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { Protocol as CDTP } from 'devtools-protocol'; import { IScript, } from '../../internal/scripts/script'; import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; diff --git a/src/chrome/cdtpDebuggee/registries/cdtpBreakpointIdsRegistry.ts b/src/chrome/cdtpDebuggee/registries/cdtpBreakpointIdsRegistry.ts index 9fb88c9de..9159b286f 100644 --- a/src/chrome/cdtpDebuggee/registries/cdtpBreakpointIdsRegistry.ts +++ b/src/chrome/cdtpDebuggee/registries/cdtpBreakpointIdsRegistry.ts @@ -1,4 +1,8 @@ -import { BidirectionalMap } from '../../collections/bidirectionalMap'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { BidirectionalMap } from '../../collections/bidirectionalMap'; import { Protocol as CDTP } from 'devtools-protocol'; import { injectable } from 'inversify'; import { CDTPBPRecipie } from '../cdtpPrimitives'; diff --git a/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts b/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts index 2b3d220be..2641e188d 100644 --- a/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts +++ b/src/chrome/cdtpDebuggee/registries/cdtpCallFrameRegistry.ts @@ -1,4 +1,8 @@ -import { Protocol as CDTP } from 'devtools-protocol'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { Protocol as CDTP } from 'devtools-protocol'; import { ValidatedMap } from '../../collections/validatedMap'; import { ScriptCallFrame } from '../../internal/stackTraces/callFrame'; import { injectable } from 'inversify'; diff --git a/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts b/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts index 6eeb5a717..0fe4fe486 100644 --- a/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts +++ b/src/chrome/cdtpDebuggee/registries/cdtpScriptsRegistry.ts @@ -1,4 +1,8 @@ -import { Protocol as CDTP } from 'devtools-protocol'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { Protocol as CDTP } from 'devtools-protocol'; import { IScript } from '../../internal/scripts/script'; import { ValidatedMap } from '../../collections/validatedMap'; import { ExecutionContext, IExecutionContext } from '../../internal/scripts/executionContext'; diff --git a/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts b/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts index 5a502ba43..7a82a9ea9 100644 --- a/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts +++ b/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts @@ -1,4 +1,8 @@ -import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; import { IClientCapabilities, ILaunchRequestArgs, IAttachRequestArgs } from '../../../debugAdapterInterfaces'; import { ChromeConnection } from '../../chromeConnection'; import { LoggingConfiguration } from '../../internal/services/logging'; diff --git a/src/chrome/client/chromeDebugAdapter/cdaState.ts b/src/chrome/client/chromeDebugAdapter/cdaState.ts index e10d02998..3219c4655 100644 --- a/src/chrome/client/chromeDebugAdapter/cdaState.ts +++ b/src/chrome/client/chromeDebugAdapter/cdaState.ts @@ -1,4 +1,8 @@ -import { ITelemetryPropertyCollector, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IEvaluateResponseBody, IGetLoadedSourcesResponseBody, IDebugAdapterState, ILaunchRequestArgs, IAttachRequestArgs, IExceptionInfoResponseBody } from '../../../debugAdapterInterfaces'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { ITelemetryPropertyCollector, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IEvaluateResponseBody, IGetLoadedSourcesResponseBody, IDebugAdapterState, ILaunchRequestArgs, IAttachRequestArgs, IExceptionInfoResponseBody } from '../../../debugAdapterInterfaces'; import { DebugProtocol } from 'vscode-debugprotocol'; import { PromiseOrNot } from '../../utils/promises'; import { ChromeDebugLogic } from '../../chromeDebugAdapter'; diff --git a/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts b/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts index 0278a6b1e..7f0230538 100644 --- a/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts +++ b/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts @@ -1,4 +1,8 @@ -import { +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { IDebugAdapter, ITelemetryPropertyCollector, PromiseOrNot, ILaunchRequestArgs, IAttachRequestArgs, IThreadsResponseBody, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IEvaluateResponseBody, IExceptionInfoResponseBody, IGetLoadedSourcesResponseBody, IDebugAdapterState diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts index a3ba1435e..99b080de0 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts @@ -1,4 +1,8 @@ -import * as errors from '../../../errors'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import * as errors from '../../../errors'; import { DebugProtocol } from 'vscode-debugprotocol'; import { ChromeDebugLogic } from '../../chromeDebugAdapter'; import { ClientToInternal } from '../clientToInternal'; diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts b/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts index 317b281cd..831a6e916 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts @@ -1,4 +1,8 @@ -import { EventsConsumedByStackTrace } from '../../internal/stackTraces/stackTracesLogic'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { EventsConsumedByStackTrace } from '../../internal/stackTraces/stackTracesLogic'; import { EventsConsumedBySkipFilesLogic } from '../../internal/features/skipFiles'; import { EventsConsumedByBreakpointsLogic } from '../../internal/breakpoints/breakpointsLogic'; import { ICommunicator } from '../../communication/communicator'; diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts index d5e14b720..734d37103 100644 --- a/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts @@ -1,4 +1,8 @@ -import { InitializedEvent, Logger } from 'vscode-debugadapter'; +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + + import { InitializedEvent, Logger } from 'vscode-debugadapter'; import { ChromeDebugLogic, ChromeDebugSession, IAttachRequestArgs, IDebugAdapterState, ILaunchRequestArgs, ITelemetryPropertyCollector, LineColTransformer, utils, BaseSourceMapTransformer, BasePathTransformer } from '../../..'; import { IClientCapabilities } from '../../../debugAdapterInterfaces'; import * as errors from '../../../errors'; diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts index 3cf7de75f..2565b3e6a 100644 --- a/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ITelemetryPropertyCollector, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IEvaluateResponseBody, IGetLoadedSourcesResponseBody } from '../../../debugAdapterInterfaces'; import { DebugProtocol } from 'vscode-debugprotocol'; import { ChromeDebugLogic, ILaunchRequestArgs, IAttachRequestArgs, IExceptionInfoResponseBody, IDebugAdapterState } from '../../..'; diff --git a/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts b/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts index 9fbb6e6be..2a34225b7 100644 --- a/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { UnconnectedCDACommonLogic } from './unconnectedCDACommonLogic'; import { ChromeConnection } from '../../chromeConnection'; import { IDebugAdapterState, ChromeDebugLogic, ITelemetryPropertyCollector, IInitializeRequestArgs, ChromeDebugSession } from '../../..'; diff --git a/src/chrome/client/clientToInternal.ts b/src/chrome/client/clientToInternal.ts index 071261090..ea16f326c 100644 --- a/src/chrome/client/clientToInternal.ts +++ b/src/chrome/client/clientToInternal.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ILoadedSource } from '../internal/sources/loadedSource'; import { BPRecipieInSource } from '../internal/breakpoints/bpRecipie'; import { DebugProtocol } from 'vscode-debugprotocol'; diff --git a/src/chrome/client/delayMessagesUntilInitializedSession.ts b/src/chrome/client/delayMessagesUntilInitializedSession.ts index b5990c513..24f8f1a35 100644 --- a/src/chrome/client/delayMessagesUntilInitializedSession.ts +++ b/src/chrome/client/delayMessagesUntilInitializedSession.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { DebugProtocol } from 'vscode-debugprotocol'; import { InitializedEvent } from 'vscode-debugadapter'; import { WrappedSessionCommonLogic } from './session'; diff --git a/src/chrome/client/doNotPauseWhileSteppingSession.ts b/src/chrome/client/doNotPauseWhileSteppingSession.ts index 97c76bcdc..7b0b7aa64 100644 --- a/src/chrome/client/doNotPauseWhileSteppingSession.ts +++ b/src/chrome/client/doNotPauseWhileSteppingSession.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { WrappedSessionCommonLogic } from './session'; import { DebugProtocol } from 'vscode-debugprotocol'; import { utils } from '../..'; diff --git a/src/chrome/client/eventSender.ts b/src/chrome/client/eventSender.ts index 9eb790cc1..1f2809291 100644 --- a/src/chrome/client/eventSender.ts +++ b/src/chrome/client/eventSender.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ILoadedSource } from '../internal/sources/loadedSource'; import { ISession } from './session'; import { LoadedSourceEvent, OutputEvent, BreakpointEvent } from 'vscode-debugadapter'; diff --git a/src/chrome/client/handlesRegistry.ts b/src/chrome/client/handlesRegistry.ts index 9fa25299c..62c902d68 100644 --- a/src/chrome/client/handlesRegistry.ts +++ b/src/chrome/client/handlesRegistry.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ILoadedSource } from '../internal/sources/loadedSource'; import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; import { BidirectionalMap } from '../collections/bidirectionalMap'; diff --git a/src/chrome/client/internalToClient.ts b/src/chrome/client/internalToClient.ts index 5efb9bb9d..7e4de67d7 100644 --- a/src/chrome/client/internalToClient.ts +++ b/src/chrome/client/internalToClient.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { DebugProtocol } from 'vscode-debugprotocol'; import { utils, LineColTransformer, IExceptionInfoResponseBody } from '../..'; import * as pathModule from 'path'; diff --git a/src/chrome/client/requests.ts b/src/chrome/client/requests.ts index e4a6c92c7..e76bb0fa6 100644 --- a/src/chrome/client/requests.ts +++ b/src/chrome/client/requests.ts @@ -1,2 +1,6 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export const AvailableCommands = new Set(['runInTerminal', 'initialize', 'configurationDone', 'launch', 'attach', 'restart', 'disconnect', 'terminate', 'setBreakpoints', 'setFunctionBreakpoints', 'setExceptionBreakpoints', 'continue', 'next', 'stepIn', 'stepOut', 'stepBack', 'reverseContinue', 'restartFrame', 'goto', 'pause', 'stackTrace', 'scopes', 'variables', 'setVariable', 'source', 'threads', 'terminateThreads', 'modules', 'loadedSources', 'evaluate', 'setExpression', 'stepInTargets', 'gotoTargets', 'completions', 'exceptionInfo']); export type CommandText = 'runInTerminal' | 'initialize' | 'configurationDone' | 'launch' | 'attach' | 'restart' | 'disconnect' | 'terminate' | 'setBreakpoints' | 'setFunctionBreakpoints' | 'setExceptionBreakpoints' | 'continue' | 'next' | 'stepIn' | 'stepOut' | 'stepBack' | 'reverseContinue' | 'restartFrame' | 'goto' | 'pause' | 'stackTrace' | 'scopes' | 'variables' | 'setVariable' | 'source' | 'threads' | 'terminateThreads' | 'modules' | 'loadedSources' | 'evaluate' | 'setExpression' | 'stepInTargets' | 'gotoTargets' | 'completions' | 'exceptionInfo'; diff --git a/src/chrome/client/session.ts b/src/chrome/client/session.ts index 20b53406d..3ae68a919 100644 --- a/src/chrome/client/session.ts +++ b/src/chrome/client/session.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { DebugProtocol } from 'vscode-debugprotocol'; export interface ISession { diff --git a/src/chrome/collections/async.ts b/src/chrome/collections/async.ts index 5ef9898b4..e4e76a714 100644 --- a/src/chrome/collections/async.ts +++ b/src/chrome/collections/async.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export function asyncMap(array: ReadonlyArray, callbackfn: (value: T, index: number, array: ReadonlyArray) => Promise | U, thisArg?: any): Promise { return Promise.all(array.map(callbackfn, thisArg)); diff --git a/src/chrome/collections/bidirectionalMap.ts b/src/chrome/collections/bidirectionalMap.ts index cdaae1568..20a1fd164 100644 --- a/src/chrome/collections/bidirectionalMap.ts +++ b/src/chrome/collections/bidirectionalMap.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import * as assert from 'assert'; import { ValidatedMap } from './validatedMap'; import { printMap } from './printing'; diff --git a/src/chrome/collections/mapUsingProjection.ts b/src/chrome/collections/mapUsingProjection.ts index df9577930..8b6c93a79 100644 --- a/src/chrome/collections/mapUsingProjection.ts +++ b/src/chrome/collections/mapUsingProjection.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ValidatedMap, IValidatedMap } from './validatedMap'; import { IProjection } from './setUsingProjection'; import { printMap } from './printing'; diff --git a/src/chrome/collections/printing.ts b/src/chrome/collections/printing.ts index 99cd6b0b2..fc98b2c5f 100644 --- a/src/chrome/collections/printing.ts +++ b/src/chrome/collections/printing.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + /** Methods to print the contents of a collection for logging and debugging purposes (This is not intended for the end-user to see) */ export function printMap(typeDescription: string, map: { entries(): IterableIterator<[K, V]> }): string { const elementsPrintted = Array.from(map.entries()).map(entry => `${entry[0]}: ${entry[1]}`).join('; '); diff --git a/src/chrome/collections/printting.ts b/src/chrome/collections/printting.ts index 99cd6b0b2..fc98b2c5f 100644 --- a/src/chrome/collections/printting.ts +++ b/src/chrome/collections/printting.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + /** Methods to print the contents of a collection for logging and debugging purposes (This is not intended for the end-user to see) */ export function printMap(typeDescription: string, map: { entries(): IterableIterator<[K, V]> }): string { const elementsPrintted = Array.from(map.entries()).map(entry => `${entry[0]}: ${entry[1]}`).join('; '); diff --git a/src/chrome/collections/setUsingProjection.ts b/src/chrome/collections/setUsingProjection.ts index 2e2ae1378..1b9375824 100644 --- a/src/chrome/collections/setUsingProjection.ts +++ b/src/chrome/collections/setUsingProjection.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ValidatedMap, IValidatedMap } from './validatedMap'; import { printSet } from './printing'; diff --git a/src/chrome/collections/utilities.ts b/src/chrome/collections/utilities.ts index 535dc5f23..79965158d 100644 --- a/src/chrome/collections/utilities.ts +++ b/src/chrome/collections/utilities.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ValidatedMultiMap } from './validatedMultiMap'; export function groupByKey(elements: T[], obtainKey: (element: T) => K): ValidatedMultiMap { diff --git a/src/chrome/collections/validatedMap.ts b/src/chrome/collections/validatedMap.ts index 87c9bcb45..caa1e12f1 100644 --- a/src/chrome/collections/validatedMap.ts +++ b/src/chrome/collections/validatedMap.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { printMap } from './printing'; import { breakWhileDebugging } from '../../validation'; diff --git a/src/chrome/collections/validatedMultiMap.ts b/src/chrome/collections/validatedMultiMap.ts index aec71f4e7..3b501904b 100644 --- a/src/chrome/collections/validatedMultiMap.ts +++ b/src/chrome/collections/validatedMultiMap.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ValidatedMap } from './validatedMap'; import { printMap } from './printing'; diff --git a/src/chrome/communication/channel.ts b/src/chrome/communication/channel.ts index 87a5e83ee..67c5e11a9 100644 --- a/src/chrome/communication/channel.ts +++ b/src/chrome/communication/channel.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { RequestChannelIdentifier } from './requestsCommunicator'; import { NamespaceReverseLookupCreator, NamespaceTree } from '../utils/namespaceReverseLookupCreator'; import { NotificationChannelIdentifier } from './notificationsCommunicator'; diff --git a/src/chrome/communication/channelIdentifier.ts b/src/chrome/communication/channelIdentifier.ts index 8d003e477..c4a8b2a9b 100644 --- a/src/chrome/communication/channelIdentifier.ts +++ b/src/chrome/communication/channelIdentifier.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export interface ChannelIdentifier { } \ No newline at end of file diff --git a/src/chrome/communication/collaborativeDecision.ts b/src/chrome/communication/collaborativeDecision.ts index 80b358523..73269b755 100644 --- a/src/chrome/communication/collaborativeDecision.ts +++ b/src/chrome/communication/collaborativeDecision.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ValidatedMultiMap } from '../collections/validatedMultiMap'; import { groupByKey } from '../collections/utilities'; import { PromiseOrNot } from '../utils/promises'; diff --git a/src/chrome/communication/communicator.ts b/src/chrome/communication/communicator.ts index 6f643f41b..41304c43a 100644 --- a/src/chrome/communication/communicator.ts +++ b/src/chrome/communication/communicator.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { NotificationsCommunicator, NotificationChannelIdentifier, PublisherFunction, SubscriberFunction, PublisherWithParamsFunction } from './notificationsCommunicator'; import { RequestsCommunicator, RequestChannelIdentifier, RequestHandlerCallback } from './requestsCommunicator'; import { IExecutionLogger } from '../logging/executionLogger'; diff --git a/src/chrome/communication/internalChannels.ts b/src/chrome/communication/internalChannels.ts index d23d94158..1355fb940 100644 --- a/src/chrome/communication/internalChannels.ts +++ b/src/chrome/communication/internalChannels.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { NotificationChannelIdentifier } from './notificationsCommunicator'; import { BPRecipie } from '../internal/breakpoints/bpRecipie'; import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; diff --git a/src/chrome/communication/listeners.ts b/src/chrome/communication/listeners.ts index f1d787ab6..2a6006b2e 100644 --- a/src/chrome/communication/listeners.ts +++ b/src/chrome/communication/listeners.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + type Callback = (args: Args) => Result; export class Listeners { diff --git a/src/chrome/communication/notificationsCommunicator.ts b/src/chrome/communication/notificationsCommunicator.ts index 739cf0711..aa278b574 100644 --- a/src/chrome/communication/notificationsCommunicator.ts +++ b/src/chrome/communication/notificationsCommunicator.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ValidatedMap } from '../collections/validatedMap'; import { ChannelIdentifier } from './channelIdentifier'; import { getChannelName } from './channel'; diff --git a/src/chrome/communication/requestsCommunicator.ts b/src/chrome/communication/requestsCommunicator.ts index a41acb3f9..4329990e8 100644 --- a/src/chrome/communication/requestsCommunicator.ts +++ b/src/chrome/communication/requestsCommunicator.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ValidatedMap } from '../collections/validatedMap'; import { ChannelIdentifier } from './channelIdentifier'; import { getChannelName } from './channel'; diff --git a/src/chrome/communication/targetChannels.ts b/src/chrome/communication/targetChannels.ts index d4d7abec9..a472f2057 100644 --- a/src/chrome/communication/targetChannels.ts +++ b/src/chrome/communication/targetChannels.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; import { NotificationChannelIdentifier } from './notificationsCommunicator'; import { Breakpoint } from '../internal/breakpoints/breakpoint'; diff --git a/src/chrome/communication/transformedListenerRegistry.ts b/src/chrome/communication/transformedListenerRegistry.ts index 8aa32c94a..85962342a 100644 --- a/src/chrome/communication/transformedListenerRegistry.ts +++ b/src/chrome/communication/transformedListenerRegistry.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Listeners } from './listeners'; import { PromiseOrNot } from '../utils/promises'; diff --git a/src/chrome/debugeeStartup/debugeeLauncher.ts b/src/chrome/debugeeStartup/debugeeLauncher.ts index 893de13f9..3243130a0 100644 --- a/src/chrome/debugeeStartup/debugeeLauncher.ts +++ b/src/chrome/debugeeStartup/debugeeLauncher.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ITelemetryPropertyCollector } from '../../telemetry'; import { ILaunchRequestArgs } from '../../debugAdapterInterfaces'; diff --git a/src/chrome/dependencyInjection.ts/bind.ts b/src/chrome/dependencyInjection.ts/bind.ts index 80cf02be6..07eb32ec7 100644 --- a/src/chrome/dependencyInjection.ts/bind.ts +++ b/src/chrome/dependencyInjection.ts/bind.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Container, interfaces } from 'inversify'; import { TYPES } from './types'; import { EventSender } from '../client/eventSender'; diff --git a/src/chrome/dependencyInjection.ts/di.ts b/src/chrome/dependencyInjection.ts/di.ts index dce88adb0..4c79a1e45 100644 --- a/src/chrome/dependencyInjection.ts/di.ts +++ b/src/chrome/dependencyInjection.ts/di.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Container, interfaces } from 'inversify'; import { bindAll } from './bind'; diff --git a/src/chrome/dependencyInjection.ts/types.ts b/src/chrome/dependencyInjection.ts/types.ts index c694a16e5..ba055d4c8 100644 --- a/src/chrome/dependencyInjection.ts/types.ts +++ b/src/chrome/dependencyInjection.ts/types.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import 'reflect-metadata'; // TODO: Add all necesary types so we can use inversifyjs to create our components diff --git a/src/chrome/extensibility/extensibilityPoints.ts b/src/chrome/extensibility/extensibilityPoints.ts index ffdf9f6c2..0586f8cea 100644 --- a/src/chrome/extensibility/extensibilityPoints.ts +++ b/src/chrome/extensibility/extensibilityPoints.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ChromeConnection, ITargetFilter } from '../chromeConnection'; import { BasePathTransformer } from '../../transformers/basePathTransformer'; import { BaseSourceMapTransformer } from '../../transformers/baseSourceMapTransformer'; diff --git a/src/chrome/internal/breakpoints/bpActionWhenHit.ts b/src/chrome/internal/breakpoints/bpActionWhenHit.ts index db495abd8..560ee11f6 100644 --- a/src/chrome/internal/breakpoints/bpActionWhenHit.ts +++ b/src/chrome/internal/breakpoints/bpActionWhenHit.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IEquivalenceComparable } from '../../utils/equivalence'; export interface IBPActionWhenHit extends IEquivalenceComparable { diff --git a/src/chrome/internal/breakpoints/bpRecipie.ts b/src/chrome/internal/breakpoints/bpRecipie.ts index d2a1cb9d4..5fe348875 100644 --- a/src/chrome/internal/breakpoints/bpRecipie.ts +++ b/src/chrome/internal/breakpoints/bpRecipie.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ISource } from '../sources/source'; import { Location, ScriptOrSourceOrURLOrURLRegexp, LocationInUrl, LocationInUrlRegexp, LocationInScript, ILocation } from '../locations/location'; import { ILoadedSource } from '../sources/loadedSource'; diff --git a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts index cecf48db2..a849ea88f 100644 --- a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts +++ b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { BPRecipieInLoadedSource, BPRecipie } from './bpRecipie'; import { ConditionalBreak, AlwaysBreak } from './bpActionWhenHit'; import { IBreakpoint } from './breakpoint'; diff --git a/src/chrome/internal/breakpoints/bpRecipieStatus.ts b/src/chrome/internal/breakpoints/bpRecipieStatus.ts index 30b716d80..6a123994a 100644 --- a/src/chrome/internal/breakpoints/bpRecipieStatus.ts +++ b/src/chrome/internal/breakpoints/bpRecipieStatus.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IBPRecipie, AnyBPRecipie } from './bpRecipie'; import { ILoadedSource } from '../sources/loadedSource'; diff --git a/src/chrome/internal/breakpoints/bpRecipies.ts b/src/chrome/internal/breakpoints/bpRecipies.ts index 4e8d1707e..959c624e1 100644 --- a/src/chrome/internal/breakpoints/bpRecipies.ts +++ b/src/chrome/internal/breakpoints/bpRecipies.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ILoadedSource } from '../sources/loadedSource'; import { ISource } from '../sources/source'; import { BPRecipie } from './bpRecipie'; diff --git a/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts b/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts index 77b0f8f1d..c42db4dfb 100644 --- a/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts +++ b/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { BPRecipieInSource, BPRecipie } from './bpRecipie'; import { BPRecipiesInUnresolvedSource } from './bpRecipies'; import { ISource } from '../sources/source'; diff --git a/src/chrome/internal/breakpoints/breakpoint.ts b/src/chrome/internal/breakpoints/breakpoint.ts index b837d6924..29c93a5af 100644 --- a/src/chrome/internal/breakpoints/breakpoint.ts +++ b/src/chrome/internal/breakpoints/breakpoint.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; import { IBPRecipie } from './bpRecipie'; import { ILoadedSource } from '../sources/loadedSource'; diff --git a/src/chrome/internal/breakpoints/breakpointsLogic.ts b/src/chrome/internal/breakpoints/breakpointsLogic.ts index 78f7028b7..3731fd63f 100644 --- a/src/chrome/internal/breakpoints/breakpointsLogic.ts +++ b/src/chrome/internal/breakpoints/breakpointsLogic.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IBPRecipie } from './bpRecipie'; import { ITelemetryPropertyCollector, IComponent, ConnectedCDAConfiguration } from '../../..'; import { ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; diff --git a/src/chrome/internal/breakpoints/breakpointsRegistry.ts b/src/chrome/internal/breakpoints/breakpointsRegistry.ts index 4609ec654..61f87a2d9 100644 --- a/src/chrome/internal/breakpoints/breakpointsRegistry.ts +++ b/src/chrome/internal/breakpoints/breakpointsRegistry.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IBPRecipieStatus, BPRecipieIsBinded, BPRecipieIsUnbinded } from './bpRecipieStatus'; import { ValidatedMultiMap } from '../../collections/validatedMultiMap'; import { IBPRecipie } from './bpRecipie'; diff --git a/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts b/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts index d483fd243..2077667f4 100644 --- a/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts +++ b/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { BPRecipiesInUnresolvedSource } from './bpRecipies'; import { BPRsDeltaCalculator, BPRsDeltaInRequestedSource } from './bpsDeltaCalculator'; diff --git a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts index 6b0e0dcd7..83ca1ead9 100644 --- a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts +++ b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IComponent } from '../../features/feature'; import { BPRecipieInSource, AnyBPRecipie } from '../bpRecipie'; import { BreakOnHitCount } from '../bpActionWhenHit'; diff --git a/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts index 70358d9f7..1cac3e4e2 100644 --- a/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts +++ b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { asyncMap } from '../../../collections/async'; import { ILoadedSource } from '../../sources/loadedSource'; import { IComponent } from '../../features/feature'; diff --git a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts index 6e4d6d54e..431e5e16f 100644 --- a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts +++ b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { BPRecipiesInUnresolvedSource } from '../bpRecipies'; import { ILoadedSource } from '../../sources/loadedSource'; import { asyncMap } from '../../../collections/async'; diff --git a/src/chrome/internal/breakpoints/hitCountConditionParser.ts b/src/chrome/internal/breakpoints/hitCountConditionParser.ts index e33488581..efff4cb74 100644 --- a/src/chrome/internal/breakpoints/hitCountConditionParser.ts +++ b/src/chrome/internal/breakpoints/hitCountConditionParser.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export type HitCountConditionFunction = (numHits: number) => boolean; export class HitCountConditionParser { diff --git a/src/chrome/internal/breakpoints/registries/bpRecipieRegistry.ts b/src/chrome/internal/breakpoints/registries/bpRecipieRegistry.ts index c884490c5..3afe4eac7 100644 --- a/src/chrome/internal/breakpoints/registries/bpRecipieRegistry.ts +++ b/src/chrome/internal/breakpoints/registries/bpRecipieRegistry.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { injectable } from 'inversify'; import { ISource } from '../../sources/source'; import { IBPRecipie } from '../bpRecipie'; diff --git a/src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts b/src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts index 8aabf31d6..483f5eb0c 100644 --- a/src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts +++ b/src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + // import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp, IBPRecipie, BPRecipie } from './bpRecipie'; // import { AlwaysBreak, ConditionalBreak } from './bpBehavior'; // import { BreakpointInScript, BreakpointInUrl, BreakpointInUrlRegexp, IBreakpoint } from './breakpoint'; diff --git a/src/chrome/internal/domains/supportedDomains.ts b/src/chrome/internal/domains/supportedDomains.ts index 48194139c..7835828bb 100644 --- a/src/chrome/internal/domains/supportedDomains.ts +++ b/src/chrome/internal/domains/supportedDomains.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IComponent } from '../features/feature'; import { Protocol as CDTP } from 'devtools-protocol'; diff --git a/src/chrome/internal/exceptions/pauseOnException.ts b/src/chrome/internal/exceptions/pauseOnException.ts index 4bbbdaa3d..d3a763d8b 100644 --- a/src/chrome/internal/exceptions/pauseOnException.ts +++ b/src/chrome/internal/exceptions/pauseOnException.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { InformationAboutPausedProvider, NotifyStoppedCommonLogic } from '../features/takeProperActionOnPausedEvent'; import { IComponent } from '../features/feature'; import * as errors from '../../../errors'; diff --git a/src/chrome/internal/exceptions/strategies.ts b/src/chrome/internal/exceptions/strategies.ts index 6e9630b9c..aec0619bd 100644 --- a/src/chrome/internal/exceptions/strategies.ts +++ b/src/chrome/internal/exceptions/strategies.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export interface PauseOnExceptionsStrategy { } diff --git a/src/chrome/internal/features/feature.ts b/src/chrome/internal/features/feature.ts index d4b991d40..1bc7ad8a2 100644 --- a/src/chrome/internal/features/feature.ts +++ b/src/chrome/internal/features/feature.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ConnectedCDAConfiguration } from '../../client/chromeDebugAdapter/cdaConfiguration'; import { PromiseOrNot } from '../../utils/promises'; diff --git a/src/chrome/internal/features/skipFiles.ts b/src/chrome/internal/features/skipFiles.ts index c1ead6e4b..e7425d0a1 100644 --- a/src/chrome/internal/features/skipFiles.ts +++ b/src/chrome/internal/features/skipFiles.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { logger } from 'vscode-debugadapter/lib/logger'; import { IScript } from '../scripts/script'; diff --git a/src/chrome/internal/features/smartStep.ts b/src/chrome/internal/features/smartStep.ts index 63894aea5..1d350e458 100644 --- a/src/chrome/internal/features/smartStep.ts +++ b/src/chrome/internal/features/smartStep.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { BasePathTransformer } from '../../../transformers/basePathTransformer'; import { BaseSourceMapTransformer } from '../../../transformers/baseSourceMapTransformer'; import { ScriptCallFrame } from '../stackTraces/callFrame'; diff --git a/src/chrome/internal/features/takeProperActionOnPausedEvent.ts b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts index 694b08c16..04216bd6b 100644 --- a/src/chrome/internal/features/takeProperActionOnPausedEvent.ts +++ b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IComponent } from './feature'; import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { IEventsToClientReporter } from '../../client/eventSender'; diff --git a/src/chrome/internal/formattedExceptionParser.ts b/src/chrome/internal/formattedExceptionParser.ts index c0473743c..ce6293ce0 100644 --- a/src/chrome/internal/formattedExceptionParser.ts +++ b/src/chrome/internal/formattedExceptionParser.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { parseResourceIdentifier } from '../..'; import { LocationInScript, Position, LocationInLoadedSource } from './locations/location'; import { IResourceIdentifier } from './sources/resourceIdentifier'; diff --git a/src/chrome/internal/locations/location.ts b/src/chrome/internal/locations/location.ts index e8d16b1e5..3b8ec8d4e 100644 --- a/src/chrome/internal/locations/location.ts +++ b/src/chrome/internal/locations/location.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import * as Validation from '../../../validation'; import { IScript } from '../scripts/script'; import { ISource } from '../sources/source'; diff --git a/src/chrome/internal/locations/rangeInScript.ts b/src/chrome/internal/locations/rangeInScript.ts index 5b94bdfdb..d5238d08c 100644 --- a/src/chrome/internal/locations/rangeInScript.ts +++ b/src/chrome/internal/locations/rangeInScript.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Position, LocationInScript } from './location'; import { IScript } from '../scripts/script'; diff --git a/src/chrome/internal/locations/subtypes.ts b/src/chrome/internal/locations/subtypes.ts index 2671c2012..4db6eabe4 100644 --- a/src/chrome/internal/locations/subtypes.ts +++ b/src/chrome/internal/locations/subtypes.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + // We use these types to have the compiler check that we are not sending a ColumnNumber where a LineNumber is expected const lineIndexSymbol = Symbol(); diff --git a/src/chrome/internal/requests.ts b/src/chrome/internal/requests.ts index 314c4486f..2bed390fc 100644 --- a/src/chrome/internal/requests.ts +++ b/src/chrome/internal/requests.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { LoadedSourceCallFrame } from './stackTraces/callFrame'; export interface EvaluateArguments { diff --git a/src/chrome/internal/scripts/executionContext.ts b/src/chrome/internal/scripts/executionContext.ts index d15780ba4..512272cf6 100644 --- a/src/chrome/internal/scripts/executionContext.ts +++ b/src/chrome/internal/scripts/executionContext.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + /** This interface represents the execution context in CDTP where a script is executed. A new context is created when a page is refreshed, etc... * We keep track of this because only scripts of non destroyed execution contexts should be displayed to the user */ diff --git a/src/chrome/internal/scripts/script.ts b/src/chrome/internal/scripts/script.ts index c2c6be837..2c183f23b 100644 --- a/src/chrome/internal/scripts/script.ts +++ b/src/chrome/internal/scripts/script.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import * as fs from 'fs'; import { ILoadedSource, MappedSource, ScriptRunFromLocalStorage, DynamicScript, diff --git a/src/chrome/internal/scripts/scriptsRegistry.ts b/src/chrome/internal/scripts/scriptsRegistry.ts index 966bdf3d0..bf85b631e 100644 --- a/src/chrome/internal/scripts/scriptsRegistry.ts +++ b/src/chrome/internal/scripts/scriptsRegistry.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Protocol as CDTP } from 'devtools-protocol'; import { IScript } from './script'; diff --git a/src/chrome/internal/scripts/sourcesMapper.ts b/src/chrome/internal/scripts/sourcesMapper.ts index f655d11c2..bd1efdd7a 100644 --- a/src/chrome/internal/scripts/sourcesMapper.ts +++ b/src/chrome/internal/scripts/sourcesMapper.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { LineNumber, ColumnNumber, createColumnNumber, createLineNumber } from '../locations/subtypes'; import { SourceMap } from '../../../sourceMaps/sourceMap'; diff --git a/src/chrome/internal/services/logging.ts b/src/chrome/internal/services/logging.ts index 25f18440c..ddf5025ea 100644 --- a/src/chrome/internal/services/logging.ts +++ b/src/chrome/internal/services/logging.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { Logger, logger } from 'vscode-debugadapter'; import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; diff --git a/src/chrome/internal/sources/features/dotScriptsCommand.ts b/src/chrome/internal/sources/features/dotScriptsCommand.ts index 000b1207d..245d222b0 100644 --- a/src/chrome/internal/sources/features/dotScriptsCommand.ts +++ b/src/chrome/internal/sources/features/dotScriptsCommand.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { inject, injectable } from 'inversify'; import { parseResourceIdentifier } from '../../../..'; import { BaseSourceMapTransformer } from '../../../../transformers/baseSourceMapTransformer'; diff --git a/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts index 950e81b45..5ae86a649 100644 --- a/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts +++ b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IComponent } from '../../features/feature'; import { IScript } from '../../scripts/script'; import { telemetry } from '../../../../telemetry'; diff --git a/src/chrome/internal/sources/loadedSource.ts b/src/chrome/internal/sources/loadedSource.ts index fe30ae419..2f520ff2e 100644 --- a/src/chrome/internal/sources/loadedSource.ts +++ b/src/chrome/internal/sources/loadedSource.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IScript } from '../scripts/script'; import { CDTPScriptUrl } from './resourceIdentifierSubtypes'; import { IResourceIdentifier, parseResourceIdentifier, ResourceName } from './resourceIdentifier'; diff --git a/src/chrome/internal/sources/resourceIdentifier.ts b/src/chrome/internal/sources/resourceIdentifier.ts index 05236d9e9..e6ec25225 100644 --- a/src/chrome/internal/sources/resourceIdentifier.ts +++ b/src/chrome/internal/sources/resourceIdentifier.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import * as path from 'path'; import { utils } from '../../..'; import { IValidatedMap } from '../../collections/validatedMap'; diff --git a/src/chrome/internal/sources/resourceIdentifierSubtypes.ts b/src/chrome/internal/sources/resourceIdentifierSubtypes.ts index 632f41f2e..910a8d6d5 100644 --- a/src/chrome/internal/sources/resourceIdentifierSubtypes.ts +++ b/src/chrome/internal/sources/resourceIdentifierSubtypes.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IResourceIdentifier } from './resourceIdentifier'; // We use this class so the compiler will check that we don't send a file path where the URL provided by CDTP is expected diff --git a/src/chrome/internal/sources/source.ts b/src/chrome/internal/sources/source.ts index 3b7845c1b..cdfbb9ca8 100644 --- a/src/chrome/internal/sources/source.ts +++ b/src/chrome/internal/sources/source.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IResourceIdentifier } from './resourceIdentifier'; import { ILoadedSource } from './loadedSource'; import { SourceResolver } from './sourceResolver'; diff --git a/src/chrome/internal/sources/sourceResolver.ts b/src/chrome/internal/sources/sourceResolver.ts index de8dbdaa6..1c45c4641 100644 --- a/src/chrome/internal/sources/sourceResolver.ts +++ b/src/chrome/internal/sources/sourceResolver.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ILoadedSource } from './loadedSource'; import { ISource, SourceToBeResolvedViaPath } from './source'; import { newResourceIdentifierMap, IResourceIdentifier } from './resourceIdentifier'; diff --git a/src/chrome/internal/sources/sourcesLogic.ts b/src/chrome/internal/sources/sourcesLogic.ts index 6116cc251..f1829e7a9 100644 --- a/src/chrome/internal/sources/sourcesLogic.ts +++ b/src/chrome/internal/sources/sourcesLogic.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { SourceTextLogic } from './sourcesTextLogic'; import { SourcesTreeNodeLogic } from './sourcesTreeNodeLogic'; import { SourceResolver } from './sourceResolver'; diff --git a/src/chrome/internal/sources/sourcesTextLogic.ts b/src/chrome/internal/sources/sourcesTextLogic.ts index 166046060..0b2873ede 100644 --- a/src/chrome/internal/sources/sourcesTextLogic.ts +++ b/src/chrome/internal/sources/sourcesTextLogic.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ILoadedSource } from './loadedSource'; import { ValidatedMap } from '../../collections/validatedMap'; import { printIterable } from '../../collections/printting'; diff --git a/src/chrome/internal/sources/sourcesTreeNodeLogic.ts b/src/chrome/internal/sources/sourcesTreeNodeLogic.ts index 5eaf8a150..98c65d9bd 100644 --- a/src/chrome/internal/sources/sourcesTreeNodeLogic.ts +++ b/src/chrome/internal/sources/sourcesTreeNodeLogic.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ILoadedSource, ILoadedSourceTreeNode, determineOrderingOfLoadedSources } from './loadedSource'; import { IScript } from '../scripts/script'; import { IComponent } from '../features/feature'; diff --git a/src/chrome/internal/sources/unresolvedSource.ts b/src/chrome/internal/sources/unresolvedSource.ts index 982be4112..8d90e3b42 100644 --- a/src/chrome/internal/sources/unresolvedSource.ts +++ b/src/chrome/internal/sources/unresolvedSource.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IResourceIdentifier } from './resourceIdentifier'; import { ILoadedSource } from './loadedSource'; import { SourceResolver } from './sourceResolver'; diff --git a/src/chrome/internal/stackTraces/formatCallFrameDescription.ts b/src/chrome/internal/stackTraces/formatCallFrameDescription.ts index ae7a4ae75..ac310e447 100644 --- a/src/chrome/internal/stackTraces/formatCallFrameDescription.ts +++ b/src/chrome/internal/stackTraces/formatCallFrameDescription.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import * as path from 'path'; import { DebugProtocol } from 'vscode-debugprotocol'; import { LoadedSourceCallFrame } from './callFrame'; diff --git a/src/chrome/internal/stackTraces/stackTracesLogic.ts b/src/chrome/internal/stackTraces/stackTracesLogic.ts index 92f211f23..fbfc7189e 100644 --- a/src/chrome/internal/stackTraces/stackTracesLogic.ts +++ b/src/chrome/internal/stackTraces/stackTracesLogic.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { DebugProtocol } from 'vscode-debugprotocol'; import { injectable, inject } from 'inversify'; diff --git a/src/chrome/internal/stepping/features/asyncStepping.ts b/src/chrome/internal/stepping/features/asyncStepping.ts index df0fca2a4..5e352906c 100644 --- a/src/chrome/internal/stepping/features/asyncStepping.ts +++ b/src/chrome/internal/stepping/features/asyncStepping.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IComponent } from '../../features/feature'; import { InformationAboutPausedProvider, ResumeCommonLogic } from '../../features/takeProperActionOnPausedEvent'; import { VoteRelevance, Vote, Abstained } from '../../../communication/collaborativeDecision'; diff --git a/src/chrome/internal/stepping/features/syncStepping.ts b/src/chrome/internal/stepping/features/syncStepping.ts index dcb1e7205..51230a5f3 100644 --- a/src/chrome/internal/stepping/features/syncStepping.ts +++ b/src/chrome/internal/stepping/features/syncStepping.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ScriptCallFrame } from '../../stackTraces/callFrame'; import { InformationAboutPausedProvider, } from '../../features/takeProperActionOnPausedEvent'; import { IComponent } from '../../features/feature'; diff --git a/src/chrome/internal/stepping/stepping.ts b/src/chrome/internal/stepping/stepping.ts index 8d48b61bc..ebce9cfb0 100644 --- a/src/chrome/internal/stepping/stepping.ts +++ b/src/chrome/internal/stepping/stepping.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { IComponent } from '../features/feature'; import { AsyncStepping } from './features/asyncStepping'; import { SyncStepping } from './features/syncStepping'; diff --git a/src/chrome/logging/executionLogger.ts b/src/chrome/logging/executionLogger.ts index fe638a56d..0f06c747b 100644 --- a/src/chrome/logging/executionLogger.ts +++ b/src/chrome/logging/executionLogger.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { PromiseOrNot } from '../utils/promises'; import { Logging } from '../internal/services/logging'; diff --git a/src/chrome/logging/methodsCalledLogger.ts b/src/chrome/logging/methodsCalledLogger.ts index 00cafb2d6..a7e4c80f2 100644 --- a/src/chrome/logging/methodsCalledLogger.ts +++ b/src/chrome/logging/methodsCalledLogger.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + enum Synchronicity { Sync, Async diff --git a/src/chrome/utils/combine.ts b/src/chrome/utils/combine.ts index 215fc502b..5fe77bdca 100644 --- a/src/chrome/utils/combine.ts +++ b/src/chrome/utils/combine.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import { ValidatedMap } from '../collections/validatedMap'; export function combine(object1: T1, object2: T2): T1 & T2; diff --git a/src/chrome/utils/equivalence.ts b/src/chrome/utils/equivalence.ts index 087c58423..17eea8ec0 100644 --- a/src/chrome/utils/equivalence.ts +++ b/src/chrome/utils/equivalence.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export interface IEquivalenceComparable { isEquivalentTo(right: this): boolean; } \ No newline at end of file diff --git a/src/chrome/utils/failures.ts b/src/chrome/utils/failures.ts index 7da836dcf..81dd004a7 100644 --- a/src/chrome/utils/failures.ts +++ b/src/chrome/utils/failures.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export function undefinedOnFailure(operation: () => R): R | undefined { try { return operation(); diff --git a/src/chrome/utils/lazy.ts b/src/chrome/utils/lazy.ts index 3ce3aed8b..9fc1a7d9a 100644 --- a/src/chrome/utils/lazy.ts +++ b/src/chrome/utils/lazy.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + const empty = Symbol(); export class Lazy1 { diff --git a/src/chrome/utils/localization.ts b/src/chrome/utils/localization.ts index 5c3aab1b4..b089c3950 100644 --- a/src/chrome/utils/localization.ts +++ b/src/chrome/utils/localization.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + // import { LocalizeInfo, loadMessageBundle, config } from 'vscode-nls'; // let _localize = loadMessageBundle(); // Initialize to an unlocalized version until we know which locale to use diff --git a/src/chrome/utils/namespaceReverseLookupCreator.ts b/src/chrome/utils/namespaceReverseLookupCreator.ts index f1023338c..734a0d092 100644 --- a/src/chrome/utils/namespaceReverseLookupCreator.ts +++ b/src/chrome/utils/namespaceReverseLookupCreator.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export type NamespaceTree = { [name: string]: NamespaceTree | T }; export class NamespaceReverseLookupCreator { diff --git a/src/chrome/utils/promises.ts b/src/chrome/utils/promises.ts index 8af59dca9..4f1f2aa16 100644 --- a/src/chrome/utils/promises.ts +++ b/src/chrome/utils/promises.ts @@ -1 +1,5 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export type PromiseOrNot = Promise | T; \ No newline at end of file diff --git a/src/chrome/utils/version.ts b/src/chrome/utils/version.ts index ffc404e74..d9af8587c 100644 --- a/src/chrome/utils/version.ts +++ b/src/chrome/utils/version.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + import * as semver from 'semver'; export class Version { diff --git a/src/typeUtils.ts b/src/typeUtils.ts index f7bec1363..ef5a3cc14 100644 --- a/src/typeUtils.ts +++ b/src/typeUtils.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export type MakePropertyRequired = T & { [P in K]-?: T[K] }; export type RemoveProperty = Pick>; export type AllRequired = { [P in keyof T]-?: T[P] }; diff --git a/src/validation.ts b/src/validation.ts index 0d2ee692a..e11896802 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + export function zeroOrPositive(name: string, value: number) { if (value < 0) { breakWhileDebugging(); From a3aa8d48808200f00fe58b4aca5ffd05229c5c85 Mon Sep 17 00:00:00 2001 From: digeff Date: Thu, 17 Jan 2019 17:02:53 -0800 Subject: [PATCH 13/23] Added I prefix to all interfaces --- src/chrome/breakOnLoadHelper.ts | 8 ++--- src/chrome/cdtpDebuggee/cdtpPrimitives.ts | 4 +-- .../cdtpConsoleEventsProvider.ts | 4 +-- .../cdtpExceptionThrownEventsProvider.ts | 10 +++---- .../eventsProviders/cdtpLogEventsProvider.ts | 6 ++-- .../cdtpOnScriptParsedEventProvider.ts | 8 ++--- .../features/cdtpDebuggeeBreakpoints.ts | 6 ++-- .../features/cdtpInspectDebugeeState.ts | 6 ++-- .../cdtpPauseOnExceptionsConfigurer.ts | 6 ++-- .../features/cdtpUpdateDebugeeState.ts | 6 ++-- .../infrastructure/cdtpDomainsEnabler.ts | 2 +- .../protocolParsers/cdtpLocationParser.ts | 10 +++---- .../protocolParsers/cdtpStackTraceParser.ts | 4 +-- src/chrome/chromeDebugAdapter.ts | 30 +++++++++---------- .../chromeDebugAdapter/cdaConfiguration.ts | 6 ++-- .../chromeDebugAdapter/connectedCDAEvents.ts | 26 ++++++++-------- .../chromeDebugAdapter/unconnectedCDA.ts | 4 +-- src/chrome/client/clientToInternal.ts | 6 ++-- src/chrome/client/eventSender.ts | 30 +++++++++---------- src/chrome/client/internalToClient.ts | 4 +-- src/chrome/communication/channel.ts | 10 +++---- src/chrome/communication/channelIdentifier.ts | 2 +- .../communication/collaborativeDecision.ts | 12 ++++---- src/chrome/communication/internalChannels.ts | 4 +-- .../notificationsCommunicator.ts | 4 +-- .../communication/requestsCommunicator.ts | 12 ++++---- src/chrome/communication/targetChannels.ts | 4 +-- src/chrome/consoleHelper.ts | 4 +-- src/chrome/internal/breakpoints/bpRecipie.ts | 4 +-- .../bpRecipieAtLoadedSourceLogic.ts | 8 ++--- src/chrome/internal/breakpoints/breakpoint.ts | 4 +-- .../internal/breakpoints/breakpointsLogic.ts | 8 ++--- .../features/hitCountBreakpoints.ts | 8 ++--- .../features/pauseScriptLoadsToSetBPs.ts | 8 ++--- .../features/reAddBPsWhenSourceIsLoaded.ts | 10 +++---- .../internal/domains/supportedDomains.ts | 4 +-- .../internal/exceptions/pauseOnException.ts | 16 +++++----- src/chrome/internal/exceptions/strategies.ts | 14 ++++----- src/chrome/internal/features/skipFiles.ts | 10 +++---- src/chrome/internal/features/smartStep.ts | 14 ++++----- .../features/takeProperActionOnPausedEvent.ts | 14 ++++----- src/chrome/internal/locations/location.ts | 8 ++--- src/chrome/internal/requests.ts | 4 +-- src/chrome/internal/services/logging.ts | 6 ++-- .../features/notifyClientOfLoadedSources.ts | 12 ++++---- .../internal/sources/resourceIdentifier.ts | 8 ++--- .../sources/resourceIdentifierSubtypes.ts | 4 +-- src/chrome/internal/sources/sourceResolver.ts | 8 ++--- .../internal/stackTraces/stackTracesLogic.ts | 8 ++--- .../stepping/features/asyncStepping.ts | 8 ++--- .../stepping/features/syncStepping.ts | 8 ++--- src/debugAdapterInterfaces.d.ts | 6 ++-- src/executionTimingsReporter.ts | 6 ++-- src/utils.ts | 4 +-- 54 files changed, 225 insertions(+), 225 deletions(-) diff --git a/src/chrome/breakOnLoadHelper.ts b/src/chrome/breakOnLoadHelper.ts index 64a41bdaa..bdf73a2f8 100644 --- a/src/chrome/breakOnLoadHelper.ts +++ b/src/chrome/breakOnLoadHelper.ts @@ -17,7 +17,7 @@ import { IResourceIdentifier, newResourceIdentifierMap } from './internal/source import { PausedEvent } from './cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { IDOMInstrumentationBreakpoints } from './cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints'; -export interface UrlRegexAndFileSet { +export interface IUrlRegexAndFileSet { urlRegex: string; fileSet: Set; } @@ -28,7 +28,7 @@ export class BreakOnLoadHelper { private _instrumentationBreakpointSet = false; // Break on load: Store some mapping between the requested file names, the regex for the file, and the chrome breakpoint id to perform lookup operations efficiently - private _stopOnEntryBreakpointIdToRequestedFileName = new Map(); + private _stopOnEntryBreakpointIdToRequestedFileName = new Map(); private _stopOnEntryRequestedFileNameToBreakpointId = newResourceIdentifierMap(); private _stopOnEntryRegexToBreakpointId = new Map(); @@ -53,7 +53,7 @@ export class BreakOnLoadHelper { return this._stopOnEntryRequestedFileNameToBreakpointId; } - public get stopOnEntryBreakpointIdToRequestedFileName(): Map { + public get stopOnEntryBreakpointIdToRequestedFileName(): Map { return this._stopOnEntryBreakpointIdToRequestedFileName; } @@ -144,7 +144,7 @@ export class BreakOnLoadHelper { // If there is a breakpoint which is not a stopOnEntry breakpoint, we appear as if we hit that one // This is particularly done for cases when we end up with a user breakpoint and a stopOnEntry breakpoint on the same line for (let bp of hitBreakpoints) { - let regexAndFileNames = {} as UrlRegexAndFileSet; // this._stopOnEntryBreakpointIdToRequestedFileName.get(bp); + let regexAndFileNames = {} as IUrlRegexAndFileSet; // this._stopOnEntryBreakpointIdToRequestedFileName.get(bp); if (!regexAndFileNames) { // notification.hitBreakpoints = [bp]; allStopOnEntryBreakpoints = false; diff --git a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts index d2e9c4f61..b9add62b4 100644 --- a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts +++ b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts @@ -6,12 +6,12 @@ import { IScript } from '../internal/scripts/script'; import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; import { URLRegexp } from '../internal/locations/subtypes'; import { AlwaysBreak, ConditionalBreak } from '../internal/breakpoints/bpActionWhenHit'; -import { URL } from '../internal/sources/resourceIdentifier'; +import { IURL } from '../internal/sources/resourceIdentifier'; import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; import { IBreakpoint } from '../internal/breakpoints/breakpoint'; export type integer = number; -export type CDTPSupportedResources = IScript | URL | URLRegexp; +export type CDTPSupportedResources = IScript | IURL | URLRegexp; export type CDTPSupportedHitActions = AlwaysBreak | ConditionalBreak; export type CDTPBPRecipie = IBPRecipie; export type CDTPBreakpoint = IBreakpoint; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts index 7e3cd07d1..55310baed 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider.ts @@ -13,7 +13,7 @@ import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; export type ConsoleAPIEventType = 'log' | 'debug' | 'info' | 'error' | 'warning' | 'dir' | 'dirxml' | 'table' | 'trace' | 'clear' | 'startGroup' | 'startGroupCollapsed' | 'endGroup' | 'assert' | 'profile' | 'profileEnd' | 'count' | 'timeEnd'; -export interface ConsoleAPICalledEvent { +export interface IConsoleAPICalledEvent { readonly type: ConsoleAPIEventType; readonly args: CDTP.Runtime.RemoteObject[]; readonly executionContextId: CDTP.Runtime.ExecutionContextId; @@ -23,7 +23,7 @@ export interface ConsoleAPICalledEvent { } export type onMessageAddedListener = (message: CDTP.Console.MessageAddedEvent) => void; -export type onConsoleAPICalled = (message: ConsoleAPICalledEvent) => void; +export type onConsoleAPICalled = (message: IConsoleAPICalledEvent) => void; export interface IConsoleEventsProvider { onMessageAdded(listener: onMessageAddedListener): void; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts index bfc983d1b..c0107b40e 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider.ts @@ -14,12 +14,12 @@ import { IScript } from '../../internal/scripts/script'; import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; -export interface ExceptionThrownEvent { +export interface IExceptionThrownEvent { readonly timestamp: CDTP.Runtime.Timestamp; - readonly exceptionDetails: ExceptionDetails; + readonly exceptionDetails: IExceptionDetails; } -export interface ExceptionDetails { +export interface IExceptionDetails { readonly exceptionId: integer; readonly text: string; readonly lineNumber: integer; @@ -32,7 +32,7 @@ export interface ExceptionDetails { } export interface IExceptionThrownEventProvider { - onExceptionThrown(listener: (event: ExceptionThrownEvent) => void): void; + onExceptionThrown(listener: (event: IExceptionThrownEvent) => void): void; } @injectable() @@ -55,7 +55,7 @@ export class CDTPExceptionThrownEventsProvider extends CDTPEventsEmitterDiagnost super(domainsEnabler); } - private async toExceptionDetails(exceptionDetails: CDTP.Runtime.ExceptionDetails): Promise { + private async toExceptionDetails(exceptionDetails: CDTP.Runtime.ExceptionDetails): Promise { return { exceptionId: exceptionDetails.exceptionId, text: exceptionDetails.text, diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts index d89bb5809..fd2053610 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpLogEventsProvider.ts @@ -16,7 +16,7 @@ import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; export type LogEntrySource = 'xml' | 'javascript' | 'network' | 'storage' | 'appcache' | 'rendering' | 'security' | 'deprecation' | 'worker' | 'violation' | 'intervention' | 'recommendation' | 'other'; export type LogLevel = 'verbose' | 'info' | 'warning' | 'error'; -export interface LogEntry { +export interface ILogEntry { readonly source: LogEntrySource; readonly level: LogLevel; readonly text: string; @@ -30,7 +30,7 @@ export interface LogEntry { } export interface ILogEventsProvider { - onEntryAdded(listener: (entry: LogEntry) => void): void; + onEntryAdded(listener: (entry: ILogEntry) => void): void; } export class CDTPLogEventsProvider extends CDTPEventsEmitterDiagnosticsModule implements ILogEventsProvider { @@ -48,7 +48,7 @@ export class CDTPLogEventsProvider extends CDTPEventsEmitterDiagnosticsModule { + private async toLogEntry(entry: CDTP.Log.LogEntry): Promise { return { source: entry.source, level: entry.level, diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts index 781e7896d..1b367b5a7 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider.ts @@ -20,7 +20,7 @@ import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; /** * A new JavaScript Script has been parsed by the debugee and it's about to be executed */ -export interface ScriptParsedEvent { +export interface IScriptParsedEvent { readonly script: IScript; readonly url: string; readonly startLine: integer; @@ -38,10 +38,10 @@ export interface ScriptParsedEvent { readonly stackTrace?: CodeFlowStackTrace; } -export type ScriptParsedListener = (params: ScriptParsedEvent) => void; +export type ScriptParsedListener = (params: IScriptParsedEvent) => void; export interface IScriptParsedProvider { - onScriptParsed(listener: (event: ScriptParsedEvent) => void): void; + onScriptParsed(listener: (event: IScriptParsedEvent) => void): void; } export class CDTPOnScriptParsedEventProvider extends CDTPEventsEmitterDiagnosticsModule implements IScriptParsedProvider { @@ -96,7 +96,7 @@ export class CDTPOnScriptParsedEventProvider extends CDTPEventsEmitterDiagnostic return script; } - private async toScriptParsedEvent(params: CDTP.Debugger.ScriptParsedEvent): Promise { + private async toScriptParsedEvent(params: CDTP.Debugger.ScriptParsedEvent): Promise { const executionContext = this._scriptsRegistry.getExecutionContextById(params.executionContextId); return { diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts index 205c3fa68..1e1fbf57f 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts @@ -34,7 +34,7 @@ export interface IDebuggeeBreakpoints { onBreakpointResolvedSyncOrAsync(listener: OnBreakpointResolvedListener): void; } -interface BreakpointClass { +interface IBreakpointClass { new(recipie: IBPRecipie, actualLocation: LocationInScript): Breakpoint; } @@ -93,7 +93,7 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< } private async setBreakpointHelper - (classToUse: BreakpointClass, bpRecipie: IBPRecipie, + (classToUse: IBreakpointClass, bpRecipie: IBPRecipie, setBPInCDTPCall: SetBPInCDTPCall): Promise[]> { const cdtpConditionField = this.getCDTPConditionField(bpRecipie); const resource = bpRecipie.location.resource; // TODO: Figure out why the is needed and remove it @@ -133,7 +133,7 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< }); } - private async toBreakpoinInResource(classToUse: BreakpointClass, + private async toBreakpoinInResource(classToUse: IBreakpointClass, bpRecipie: IBPRecipie, actualLocation: CDTP.Debugger.Location): Promise> { const breakpoint = new classToUse(bpRecipie, await this.toLocationInScript(actualLocation)); return breakpoint; diff --git a/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts b/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts index dc1bf1770..82664d9d0 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpInspectDebugeeState.ts @@ -9,7 +9,7 @@ import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { ScriptCallFrame } from '../../internal/stackTraces/callFrame'; -export interface EvaluateOnCallFrameRequest { +export interface IEvaluateOnCallFrameRequest { readonly frame: ScriptCallFrame; readonly expression: string; readonly objectGroup?: string; @@ -25,7 +25,7 @@ export interface IInspectDebugeeState { callFunctionOn(params: CDTP.Runtime.CallFunctionOnRequest): Promise; getProperties(params: CDTP.Runtime.GetPropertiesRequest): Promise; evaluate(params: CDTP.Runtime.EvaluateRequest): Promise; - evaluateOnCallFrame(params: EvaluateOnCallFrameRequest): Promise; + evaluateOnCallFrame(params: IEvaluateOnCallFrameRequest): Promise; } export class AddSourceUriToExpession { @@ -66,7 +66,7 @@ export class CDTPInspectDebugeeState implements IInspectDebugeeState { return this.api.Runtime.evaluate(params); } - public evaluateOnCallFrame(params: EvaluateOnCallFrameRequest): Promise { + public evaluateOnCallFrame(params: IEvaluateOnCallFrameRequest): Promise { return this.api.Debugger.evaluateOnCallFrame({ callFrameId: this._callFrameRegistry.getFrameId(params.frame), expression: this.addSourceUriToEvaluates.addURLIfMissing(params.expression), diff --git a/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts b/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts index 9dba4b272..fbdc45075 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer.ts @@ -3,12 +3,12 @@ *--------------------------------------------------------*/ import { Protocol as CDTP } from 'devtools-protocol'; -import { PauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions } from '../../internal/exceptions/strategies'; +import { IPauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions } from '../../internal/exceptions/strategies'; import { inject, injectable } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; export interface IPauseOnExceptionsConfigurer { - setPauseOnExceptions(strategy: PauseOnExceptionsStrategy): Promise; + setPauseOnExceptions(strategy: IPauseOnExceptionsStrategy): Promise; } export type ExceptionCategories = 'none' | 'uncaught' | 'all'; @@ -22,7 +22,7 @@ export class CDTPPauseOnExceptionsConfigurer implements IPauseOnExceptionsConfig private readonly _protocolApi: CDTP.ProtocolApi) { } - public setPauseOnExceptions(strategy: PauseOnExceptionsStrategy): Promise { + public setPauseOnExceptions(strategy: IPauseOnExceptionsStrategy): Promise { let state: ExceptionCategories; if (strategy instanceof PauseOnAllExceptions) { diff --git a/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts b/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts index 2a931fe1a..f95802242 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpUpdateDebugeeState.ts @@ -9,7 +9,7 @@ import { injectable, inject } from 'inversify'; import { ScriptCallFrame } from '../../internal/stackTraces/callFrame'; import { integer } from '../cdtpPrimitives'; -export interface SetVariableValueRequest { +export interface ISetVariableValueRequest { readonly scopeNumber: integer; readonly variableName: string; readonly newValue: CDTP.Runtime.CallArgument; @@ -17,7 +17,7 @@ export interface SetVariableValueRequest { } export interface IUpdateDebugeeState { - setVariableValue(params: SetVariableValueRequest): Promise; + setVariableValue(params: ISetVariableValueRequest): Promise; } @injectable() @@ -27,7 +27,7 @@ export class CDTPUpdateDebugeeState implements IUpdateDebugeeState { private readonly _callFrameRegistry: CDTPCallFrameRegistry) { } - public setVariableValue(params: SetVariableValueRequest): Promise { + public setVariableValue(params: ISetVariableValueRequest): Promise { return this.api.Debugger.setVariableValue({ callFrameId: this._callFrameRegistry.getFrameId(params.frame), scopeNumber: params.scopeNumber, diff --git a/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts b/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts index 498de5cfb..97ed15551 100644 --- a/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts +++ b/src/chrome/cdtpDebuggee/infrastructure/cdtpDomainsEnabler.ts @@ -28,7 +28,7 @@ class EnableDomainFunctionAndResultPromise { constructor( public readonly enableDomain: () => Promise, public readonly parameters: unknown, - public readonly defer: utils.PromiseDefer, + public readonly defer: utils.IPromiseDefer, ) { } } diff --git a/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts b/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts index b999bee0f..ec845dfa7 100644 --- a/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts +++ b/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts @@ -7,24 +7,24 @@ import { createColumnNumber, createLineNumber } from '../../internal/locations/s import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { Protocol as CDTP } from 'devtools-protocol'; -interface HasCoordinates { +interface IHasCoordinates { lineNumber: number; columnNumber?: number; } -interface HasScript { +interface IHasScript { scriptId: CDTP.Runtime.ScriptId; } -export interface HasScriptLocation extends HasCoordinates, HasScript { } +export interface IHasScriptLocation extends IHasCoordinates, IHasScript { } export class CDTPLocationParser { - public async getLocationInScript(crdpObjectWithScriptLocation: HasScriptLocation): Promise { + public async getLocationInScript(crdpObjectWithScriptLocation: IHasScriptLocation): Promise { return new LocationInScript(await this._scriptsRegistry.getScriptByCdtpId(crdpObjectWithScriptLocation.scriptId), this.getCoordinates(crdpObjectWithScriptLocation)); } - private getCoordinates(crdpObjectWithCoordinates: HasCoordinates): Position { + private getCoordinates(crdpObjectWithCoordinates: IHasCoordinates): Position { return new Position(createLineNumber(crdpObjectWithCoordinates.lineNumber), createColumnNumber(crdpObjectWithCoordinates.columnNumber)); } diff --git a/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts index f0377396c..7e838ad8b 100644 --- a/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts +++ b/src/chrome/cdtpDebuggee/protocolParsers/cdtpStackTraceParser.ts @@ -7,7 +7,7 @@ import { IScript, } from '../../internal/scripts/script'; import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrace'; import { CodeFlowFrame } from '../../internal/stackTraces/callFrame'; -import { CDTPLocationParser, HasScriptLocation } from './cdtpLocationParser'; +import { CDTPLocationParser, IHasScriptLocation } from './cdtpLocationParser'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { asyncMap } from '../../collections/async'; @@ -26,7 +26,7 @@ export class CDTPStackTraceParser { return this.toCodeFlowFrame(index, callFrame, callFrame); } - public async toCodeFlowFrame(index: number, callFrame: CDTP.Runtime.CallFrame | CDTP.Debugger.CallFrame, location: HasScriptLocation): Promise> { + public async toCodeFlowFrame(index: number, callFrame: CDTP.Runtime.CallFrame | CDTP.Debugger.CallFrame, location: IHasScriptLocation): Promise> { const scriptLocation = await this._cdtpLocationParser.getLocationInScript(location); return new CodeFlowFrame(index, callFrame.functionName, scriptLocation); } diff --git a/src/chrome/chromeDebugAdapter.ts b/src/chrome/chromeDebugAdapter.ts index da17b0de6..9a3615a42 100644 --- a/src/chrome/chromeDebugAdapter.ts +++ b/src/chrome/chromeDebugAdapter.ts @@ -8,7 +8,7 @@ import { TerminatedEvent, ContinuedEvent, logger, } from 'vscode-debugadapter'; import { ICommonRequestArgs, ILaunchRequestArgs, IScopesResponseBody, IVariablesResponseBody, IThreadsResponseBody, IEvaluateResponseBody, ISetVariableResponseBody, - ICompletionsResponseBody, IRestartRequestArgs, TimeTravelRuntime + ICompletionsResponseBody, IRestartRequestArgs, ITimeTravelRuntime } from '../debugAdapterInterfaces'; import { ChromeConnection } from './chromeConnection'; @@ -36,7 +36,7 @@ import { ISession } from './client/session'; import { IScript } from './internal/scripts/script'; import { LocationInLoadedSource } from './internal/locations/location'; -import { EvaluateArguments, CompletionsArguments } from './internal/requests'; +import { IEvaluateArguments, ICompletionsArguments } from './internal/requests'; import { EventSender } from './client/eventSender'; import { parseResourceIdentifier, ConnectedCDAConfiguration } from '..'; import { LoadedSourceCallFrame } from './internal/stackTraces/callFrame'; @@ -44,15 +44,15 @@ import { CodeFlowStackTrace } from './internal/stackTraces/codeFlowStackTrace'; import { IResourceIdentifier } from './internal/sources/resourceIdentifier'; import { FormattedExceptionParser } from './internal/formattedExceptionParser'; import { DeleteMeScriptsRegistry } from './internal/scripts/scriptsRegistry'; -import { CDTPExceptionThrownEventsProvider, ExceptionThrownEvent } from './cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider'; +import { CDTPExceptionThrownEventsProvider, IExceptionThrownEvent } from './cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider'; import { CDTPExecutionContextEventsProvider } from './cdtpDebuggee/eventsProviders/cdtpExecutionContextEventsProvider'; -import { IInspectDebugeeState, EvaluateOnCallFrameRequest } from './cdtpDebuggee/features/cdtpInspectDebugeeState'; +import { IInspectDebugeeState, IEvaluateOnCallFrameRequest } from './cdtpDebuggee/features/cdtpInspectDebugeeState'; import { IUpdateDebugeeState } from './cdtpDebuggee/features/cdtpUpdateDebugeeState'; import { injectable, inject } from 'inversify'; import { TYPES } from './dependencyInjection.ts/types'; import { ICDTDebuggeeExecutionEventsProvider, PausedEvent } from './cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; -import { LogEntry, CDTPLogEventsProvider } from './cdtpDebuggee/eventsProviders/cdtpLogEventsProvider'; -import { IConsoleEventsProvider, ConsoleAPICalledEvent } from './cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider'; +import { ILogEntry, CDTPLogEventsProvider } from './cdtpDebuggee/eventsProviders/cdtpLogEventsProvider'; +import { IConsoleEventsProvider, IConsoleAPICalledEvent } from './cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider'; import { IPauseOnExceptionsConfigurer } from './cdtpDebuggee/features/CDTPPauseOnExceptionsConfigurer'; // export class ChromeDebugAdapter extends ChromeDebugAdapterClass { @@ -345,7 +345,7 @@ export class ChromeDebugLogic { } } - public onConsoleAPICalled(event: ConsoleAPICalledEvent): void { + public onConsoleAPICalled(event: IConsoleAPICalledEvent): void { if (this._launchAttachArgs._suppressConsoleOutput) { return; } @@ -357,7 +357,7 @@ export class ChromeDebugLogic { } } - private onLogEntryAdded(entry: LogEntry): void { + private onLogEntryAdded(entry: ILogEntry): void { // The Debug Console doesn't give the user a way to filter by level, just ignore 'verbose' logs if (entry.level === 'verbose') { return; @@ -424,7 +424,7 @@ export class ChromeDebugLogic { .catch(err => logger.error(err.toString())); } - protected async onExceptionThrown(params: ExceptionThrownEvent): Promise { + protected async onExceptionThrown(params: IExceptionThrownEvent): Promise { if (this._launchAttachArgs._suppressConsoleOutput) { return; } @@ -450,7 +450,7 @@ export class ChromeDebugLogic { protected onMessageAdded(params: any): void { // message.type is undefined when Runtime.consoleAPICalled is being sent if (params && params.message && params.message.type) { - const onConsoleAPICalledParams: ConsoleAPICalledEvent = { + const onConsoleAPICalledParams: IConsoleAPICalledEvent = { type: params.message.type, timestamp: params.message.timestamp, args: params.message.parameters || [{ type: 'string', value: params.message.text }], @@ -504,7 +504,7 @@ export class ChromeDebugLogic { } public stepBack(): Promise { - return (this._chromeConnection.api).TimeTravel.stepBack() + return (this._chromeConnection.api).TimeTravel.stepBack() .then(() => { /* make void */ }, () => { }); } @@ -518,7 +518,7 @@ export class ChromeDebugLogic { } */ public reverseContinue(): Promise { - return (this._chromeConnection.api).TimeTravel.reverse() + return (this._chromeConnection.api).TimeTravel.reverse() .then(() => { /* make void */ }, () => { }); } @@ -786,7 +786,7 @@ export class ChromeDebugLogic { ] } */ - public async evaluate(args: EvaluateArguments): Promise { + public async evaluate(args: IEvaluateArguments): Promise { const expression = args.expression.startsWith('{') && args.expression.endsWith('}') ? `(${args.expression})` : args.expression; @@ -851,7 +851,7 @@ export class ChromeDebugLogic { } public async evaluateOnCallFrame(expression: string, frame: LoadedSourceCallFrame, extraArgs?: Partial): Promise { - let args: EvaluateOnCallFrameRequest = { + let args: IEvaluateOnCallFrameRequest = { frame: frame.unmappedCallFrame, expression, // silent because of an issue where node will sometimes hang when breaking on exceptions in console messages. Fixed somewhere between 8 and 8.4 @@ -1029,7 +1029,7 @@ export class ChromeDebugLogic { ] } */ - public async completions(args: CompletionsArguments): Promise { + public async completions(args: ICompletionsArguments): Promise { const text = args.text; const column = args.column; diff --git a/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts b/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts index 7a82a9ea9..20f079881 100644 --- a/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts +++ b/src/chrome/client/chromeDebugAdapter/cdaConfiguration.ts @@ -5,7 +5,7 @@ import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; import { IClientCapabilities, ILaunchRequestArgs, IAttachRequestArgs } from '../../../debugAdapterInterfaces'; import { ChromeConnection } from '../../chromeConnection'; -import { LoggingConfiguration } from '../../internal/services/logging'; +import { ILoggingConfiguration } from '../../internal/services/logging'; import { ScenarioType } from './unconnectedCDA'; import { injectable } from 'inversify'; import { ISession } from '../session'; @@ -15,7 +15,7 @@ export interface IConnectedCDAConfiguration { args: ILaunchRequestArgs | IAttachRequestArgs; isVSClient: boolean; _extensibilityPoints: IExtensibilityPoints; - loggingConfiguration: LoggingConfiguration; + loggingConfiguration: ILoggingConfiguration; _session: ISession; _clientCapabilities: IClientCapabilities; _chromeConnectionClass: typeof ChromeConnection; @@ -29,7 +29,7 @@ export class ConnectedCDAConfiguration implements IConnectedCDAConfiguration { public readonly isVSClient = this._clientCapabilities.clientID === 'visualstudio'; constructor(public readonly _extensibilityPoints: IExtensibilityPoints, - public readonly loggingConfiguration: LoggingConfiguration, + public readonly loggingConfiguration: ILoggingConfiguration, public readonly _session: ISession, public readonly _clientCapabilities: IClientCapabilities, public readonly _chromeConnectionClass: typeof ChromeConnection, diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts b/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts index 831a6e916..cf54db318 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts @@ -2,31 +2,31 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ - import { EventsConsumedByStackTrace } from '../../internal/stackTraces/stackTracesLogic'; -import { EventsConsumedBySkipFilesLogic } from '../../internal/features/skipFiles'; + import { IEventsConsumedByStackTrace } from '../../internal/stackTraces/stackTracesLogic'; +import { IEventsConsumedBySkipFilesLogic } from '../../internal/features/skipFiles'; import { EventsConsumedByBreakpointsLogic } from '../../internal/breakpoints/breakpointsLogic'; import { ICommunicator } from '../../communication/communicator'; import { Internal } from '../../communication/internalChannels'; import { Target } from '../../communication/targetChannels'; import { ILoadedSource } from '../../internal/sources/loadedSource'; import { asyncMap } from '../../collections/async'; -import { EventsConsumedByPauseOnException } from '../../internal/exceptions/pauseOnException'; -import { EventsConsumedByTakeProperActionOnPausedEvent } from '../../internal/features/takeProperActionOnPausedEvent'; -import { EventsConsumedBySourceResolver } from '../../internal/sources/sourceResolver'; -import { EventsConsumedBySmartStepLogic } from '../../internal/features/smartStep'; -import { EventsConsumedByReAddBPsWhenSourceIsLoaded } from '../../internal/breakpoints/features/reAddBPsWhenSourceIsLoaded'; -import { EventsConsumedByAsyncStepping } from '../../internal/stepping/features/asyncStepping'; +import { IEventsConsumedByPauseOnException } from '../../internal/exceptions/pauseOnException'; +import { IEventsConsumedByTakeProperActionOnPausedEvent } from '../../internal/features/takeProperActionOnPausedEvent'; +import { IEventsConsumedBySourceResolver } from '../../internal/sources/sourceResolver'; +import { IEventsConsumedBySmartStepLogic } from '../../internal/features/smartStep'; +import { IEventsConsumedByReAddBPsWhenSourceIsLoaded } from '../../internal/breakpoints/features/reAddBPsWhenSourceIsLoaded'; +import { IEventsConsumedByAsyncStepping } from '../../internal/stepping/features/asyncStepping'; // import { EventsConsumedBySyncStepping } from '../../internal/stepping/features/syncStepping'; -export interface EventsConsumedByConnectedCDA extends EventsConsumedByBreakpointsLogic, EventsConsumedByPauseOnException, - EventsConsumedByStackTrace, EventsConsumedByTakeProperActionOnPausedEvent, EventsConsumedBySkipFilesLogic, - EventsConsumedBySourceResolver, EventsConsumedBySmartStepLogic, - EventsConsumedByReAddBPsWhenSourceIsLoaded, EventsConsumedByAsyncStepping { } +export interface IEventsConsumedByConnectedCDA extends EventsConsumedByBreakpointsLogic, IEventsConsumedByPauseOnException, + IEventsConsumedByStackTrace, IEventsConsumedByTakeProperActionOnPausedEvent, IEventsConsumedBySkipFilesLogic, + IEventsConsumedBySourceResolver, IEventsConsumedBySmartStepLogic, + IEventsConsumedByReAddBPsWhenSourceIsLoaded, IEventsConsumedByAsyncStepping { } export class ConnectedCDAEventsCreator { constructor(private readonly communicator: ICommunicator) { } - public create(): EventsConsumedByConnectedCDA { + public create(): IEventsConsumedByConnectedCDA { const onLoadedSourceIsAvailable = (listener: (source: ILoadedSource) => void) => { this.communicator.subscribe(Target.Debugger.OnScriptParsed, async scriptParsed => { await asyncMap(scriptParsed.script.allSources, listener); diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts index 734d37103..ffc0bdd39 100644 --- a/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts @@ -14,7 +14,7 @@ import { Communicator, LoggingCommunicator } from '../../communication/communica import { DependencyInjection } from '../../dependencyInjection.ts/di'; import { TYPES } from '../../dependencyInjection.ts/types'; import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; -import { Logging, LoggingConfiguration } from '../../internal/services/logging'; +import { Logging, ILoggingConfiguration } from '../../internal/services/logging'; import { ExecutionLogger } from '../../logging/executionLogger'; import { DelayMessagesUntilInitializedSession } from '../delayMessagesUntilInitializedSession'; import { DoNotPauseWhileSteppingSession } from '../doNotPauseWhileSteppingSession'; @@ -48,7 +48,7 @@ export class UnconnectedCDA extends UnconnectedCDACommonLogic implements IDebugA return this.createConnection(ScenarioType.Attach, updatedArgs, telemetryPropertyCollector); } - private parseLoggingConfiguration(args: ILaunchRequestArgs | IAttachRequestArgs): LoggingConfiguration { + private parseLoggingConfiguration(args: ILaunchRequestArgs | IAttachRequestArgs): ILoggingConfiguration { const traceMapping: { [key: string]: Logger.LogLevel | undefined } = { true: Logger.LogLevel.Warn, verbose: Logger.LogLevel.Verbose }; const traceValue = args.trace && traceMapping[args.trace.toString().toLowerCase()]; return { logLevel: traceValue, logFilePath: args.logFilePath, shouldLogTimestamps: args.logTimestamps }; diff --git a/src/chrome/client/clientToInternal.ts b/src/chrome/client/clientToInternal.ts index ea16f326c..5e7e2c532 100644 --- a/src/chrome/client/clientToInternal.ts +++ b/src/chrome/client/clientToInternal.ts @@ -13,7 +13,7 @@ import { IBPActionWhenHit, AlwaysBreak, ConditionalBreak } from '../internal/bre import { HandlesRegistry } from './handlesRegistry'; import { createLineNumber, createColumnNumber } from '../internal/locations/subtypes'; import { parseResourceIdentifier } from '../internal/sources/resourceIdentifier'; -import { PauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions, PauseOnAllRejections, DoNotPauseOnAnyRejections, PauseOnPromiseRejectionsStrategy } from '../internal/exceptions/strategies'; +import { IPauseOnExceptionsStrategy, PauseOnAllExceptions, PauseOnUnhandledExceptions, DoNotPauseOnAnyExceptions, PauseOnAllRejections, DoNotPauseOnAnyRejections, IPauseOnPromiseRejectionsStrategy } from '../internal/exceptions/strategies'; import { injectable, inject } from 'inversify'; import { TYPES } from '../dependencyInjection.ts/types'; import { ISource, SourceAlreadyResolvedToLoadedSource } from '../internal/sources/source'; @@ -21,7 +21,7 @@ import { IStackTracePresentationRow } from '../internal/stackTraces/stackTracePr @injectable() export class ClientToInternal { - public toPauseOnExceptionsStrategy(exceptionFilters: string[]): PauseOnExceptionsStrategy { + public toPauseOnExceptionsStrategy(exceptionFilters: string[]): IPauseOnExceptionsStrategy { if (exceptionFilters.indexOf('all') >= 0) { return new PauseOnAllExceptions(); } else if (exceptionFilters.indexOf('uncaught') >= 0) { @@ -31,7 +31,7 @@ export class ClientToInternal { } } - public toPauseOnPromiseRejectionsStrategy(exceptionFilters: string[]): PauseOnPromiseRejectionsStrategy { + public toPauseOnPromiseRejectionsStrategy(exceptionFilters: string[]): IPauseOnPromiseRejectionsStrategy { if (exceptionFilters.indexOf('promise_reject') >= 0) { return new PauseOnAllRejections(); } else { diff --git a/src/chrome/client/eventSender.ts b/src/chrome/client/eventSender.ts index 1f2809291..e18522892 100644 --- a/src/chrome/client/eventSender.ts +++ b/src/chrome/client/eventSender.ts @@ -16,45 +16,45 @@ import { TYPES } from '../dependencyInjection.ts/types'; import { Protocol as CDTP } from 'devtools-protocol'; import { ChromeDebugLogic } from '../chromeDebugAdapter'; -export interface OutputParameters { +export interface IOutputParameters { readonly output: string; readonly category: string; readonly variablesReference?: number; readonly location?: LocationInLoadedSource; } -export interface SourceWasLoadedParameters { +export interface ISourceWasLoadedParameters { readonly reason: 'new' | 'changed' | 'removed'; readonly source: ILoadedSource; } -export interface BPStatusChangedParameters { +export interface IBPStatusChangedParameters { readonly reason: string; readonly bpRecipieStatus: IBPRecipieStatus; } -export interface ExceptionThrownParameters { +export interface IExceptionThrownParameters { readonly exceptionStackTrace: IFormattedExceptionLineDescription[]; readonly category: string; readonly location?: LocationInLoadedSource; } -export interface DebugeeIsStoppedParameters { +export interface IDebugeeIsStoppedParameters { reason: ReasonType; exception?: CDTP.Runtime.RemoteObject; } export interface IEventsToClientReporter { - sendOutput(params: OutputParameters): void; - sendSourceWasLoaded(params: SourceWasLoadedParameters): Promise; - sendBPStatusChanged(params: BPStatusChangedParameters): Promise; - sendExceptionThrown(params: ExceptionThrownParameters): Promise; - sendDebugeeIsStopped(params: DebugeeIsStoppedParameters): Promise; + sendOutput(params: IOutputParameters): void; + sendSourceWasLoaded(params: ISourceWasLoadedParameters): Promise; + sendBPStatusChanged(params: IBPStatusChangedParameters): Promise; + sendExceptionThrown(params: IExceptionThrownParameters): Promise; + sendDebugeeIsStopped(params: IDebugeeIsStoppedParameters): Promise; } @injectable() export class EventSender implements IEventsToClientReporter { - public sendOutput(params: OutputParameters): void { + public sendOutput(params: IOutputParameters): void { const event = new OutputEvent(params.output, params.category) as DebugProtocol.OutputEvent; if (params.variablesReference) { @@ -68,21 +68,21 @@ export class EventSender implements IEventsToClientReporter { this._session.sendEvent(event); } - public async sendSourceWasLoaded(params: SourceWasLoadedParameters): Promise { + public async sendSourceWasLoaded(params: ISourceWasLoadedParameters): Promise { const clientSource = await this._internalToClient.toSource(params.source); const event = new LoadedSourceEvent(params.reason, clientSource); this._session.sendEvent(event); } - public async sendBPStatusChanged(params: BPStatusChangedParameters): Promise { + public async sendBPStatusChanged(params: IBPStatusChangedParameters): Promise { const breakpointStatus = await this._internalToClient.toBPRecipieStatus(params.bpRecipieStatus); const event = new BreakpointEvent(params.reason, breakpointStatus); this._session.sendEvent(event); } - public async sendExceptionThrown(params: ExceptionThrownParameters): Promise { + public async sendExceptionThrown(params: IExceptionThrownParameters): Promise { return this.sendOutput({ output: this._internalToClient.toExceptionStackTracePrintted(params.exceptionStackTrace), category: params.category, @@ -90,7 +90,7 @@ export class EventSender implements IEventsToClientReporter { }); } - public async sendDebugeeIsStopped(params: DebugeeIsStoppedParameters): Promise { + public async sendDebugeeIsStopped(params: IDebugeeIsStoppedParameters): Promise { return this._session.sendEvent(new StoppedEvent2(params.reason, /*threadId=*/ChromeDebugLogic.THREAD_ID, params.exception)); } diff --git a/src/chrome/client/internalToClient.ts b/src/chrome/client/internalToClient.ts index 7e4de67d7..cae3d57df 100644 --- a/src/chrome/client/internalToClient.ts +++ b/src/chrome/client/internalToClient.ts @@ -20,7 +20,7 @@ import { Source } from 'vscode-debugadapter'; import { IStackTracePresentationRow, StackTraceLabel } from '../internal/stackTraces/stackTracePresentationRow'; import { CallFramePresentation } from '../internal/stackTraces/callFramePresentation'; -interface ClientLocationInSource { +interface IClientLocationInSource { source: DebugProtocol.Source; line: number; column: number; @@ -81,7 +81,7 @@ export class InternalToClient { return source; } - public async toLocationInSource(locationInSource: LocationInLoadedSource, objectToUpdate: T): Promise { + public async toLocationInSource(locationInSource: LocationInLoadedSource, objectToUpdate: T): Promise { const source = await this.toSource(locationInSource.source); const clientLocationInSource = { source, line: locationInSource.position.lineNumber, column: locationInSource.position.columnNumber }; this._lineColTransformer.convertDebuggerLocationToClient(clientLocationInSource); diff --git a/src/chrome/communication/channel.ts b/src/chrome/communication/channel.ts index 67c5e11a9..505932e65 100644 --- a/src/chrome/communication/channel.ts +++ b/src/chrome/communication/channel.ts @@ -5,22 +5,22 @@ import { RequestChannelIdentifier } from './requestsCommunicator'; import { NamespaceReverseLookupCreator, NamespaceTree } from '../utils/namespaceReverseLookupCreator'; import { NotificationChannelIdentifier } from './notificationsCommunicator'; -import { ChannelIdentifier } from './channelIdentifier'; +import { IChannelIdentifier } from './channelIdentifier'; -type ChannelIdentifierNamespace = NamespaceTree; +type ChannelIdentifierNamespace = NamespaceTree; const registeredChannels: ChannelIdentifierNamespace = {}; export function registerChannels(channel: ChannelIdentifierNamespace, name: string): void { registeredChannels[name] = channel; } -let channelToNameMapping: Map | null = null; +let channelToNameMapping: Map | null = null; -function isChannelIdentifier(obj: any): obj is ChannelIdentifier { +function isChannelIdentifier(obj: any): obj is IChannelIdentifier { return obj instanceof NotificationChannelIdentifier || obj instanceof RequestChannelIdentifier; } -export function getChannelName(channel: ChannelIdentifier): string { +export function getChannelName(channel: IChannelIdentifier): string { if (channelToNameMapping === null) { channelToNameMapping = new NamespaceReverseLookupCreator(registeredChannels, isChannelIdentifier, '').create(); } diff --git a/src/chrome/communication/channelIdentifier.ts b/src/chrome/communication/channelIdentifier.ts index c4a8b2a9b..14dd7cf86 100644 --- a/src/chrome/communication/channelIdentifier.ts +++ b/src/chrome/communication/channelIdentifier.ts @@ -2,6 +2,6 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -export interface ChannelIdentifier { +export interface IChannelIdentifier { } \ No newline at end of file diff --git a/src/chrome/communication/collaborativeDecision.ts b/src/chrome/communication/collaborativeDecision.ts index 73269b755..af7ab73da 100644 --- a/src/chrome/communication/collaborativeDecision.ts +++ b/src/chrome/communication/collaborativeDecision.ts @@ -13,14 +13,14 @@ export enum VoteRelevance { Abstained, } -export interface Vote { +export interface IVote { relevance: VoteRelevance; isRelevant(): boolean; - execute(remainingRelevantVotes: Vote[]): Promise; + execute(remainingRelevantVotes: IVote[]): Promise; } -export abstract class VoteCommonLogic implements Vote { +export abstract class VoteCommonLogic implements IVote { public abstract execute(): Promise; public abstract get relevance(): VoteRelevance; @@ -54,7 +54,7 @@ export class Abstained extends VoteCommonLogic { } export class ExecuteDecisionBasedOnVotes { - private readonly _votesByRelevance: ValidatedMultiMap>; + private readonly _votesByRelevance: ValidatedMultiMap>; public async execute(): Promise { const overrideVotes = this.getVotesWithCertainRelevance(VoteRelevance.OverrideOtherVotes); @@ -77,11 +77,11 @@ export class ExecuteDecisionBasedOnVotes { return this.getVotesWithCertainRelevance(relevance).length; } - private getVotesWithCertainRelevance(relevance: VoteRelevance): Vote[] { + private getVotesWithCertainRelevance(relevance: VoteRelevance): IVote[] { return Array.from(this._votesByRelevance.tryGetting(relevance) || []); } - constructor(private readonly _actionIfNoOneVoted: () => PromiseOrNot, votes: Vote[]) { + constructor(private readonly _actionIfNoOneVoted: () => PromiseOrNot, votes: IVote[]) { this._votesByRelevance = groupByKey(votes, vote => vote.relevance); } } \ No newline at end of file diff --git a/src/chrome/communication/internalChannels.ts b/src/chrome/communication/internalChannels.ts index 1355fb940..aa68d573c 100644 --- a/src/chrome/communication/internalChannels.ts +++ b/src/chrome/communication/internalChannels.ts @@ -6,13 +6,13 @@ import { NotificationChannelIdentifier } from './notificationsCommunicator'; import { BPRecipie } from '../internal/breakpoints/bpRecipie'; import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; import { registerChannels } from './channel'; -import { Vote } from './collaborativeDecision'; +import { IVote } from './collaborativeDecision'; import { PausedEvent } from '../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; const _breakpoints = { // Notifications OnUnbounBPRecipieIsNowBound: new NotificationChannelIdentifier>(), - OnPausedOnBreakpoint: new NotificationChannelIdentifier>(), + OnPausedOnBreakpoint: new NotificationChannelIdentifier>(), OnNoPendingBreakpoints: new NotificationChannelIdentifier(), OnGoingToPauseClient: new NotificationChannelIdentifier(), }; diff --git a/src/chrome/communication/notificationsCommunicator.ts b/src/chrome/communication/notificationsCommunicator.ts index aa278b574..10bbbb249 100644 --- a/src/chrome/communication/notificationsCommunicator.ts +++ b/src/chrome/communication/notificationsCommunicator.ts @@ -3,7 +3,7 @@ *--------------------------------------------------------*/ import { ValidatedMap } from '../collections/validatedMap'; -import { ChannelIdentifier } from './channelIdentifier'; +import { IChannelIdentifier } from './channelIdentifier'; import { getChannelName } from './channel'; import { Listeners } from './listeners'; import { PromiseOrNot } from '../utils/promises'; @@ -20,7 +20,7 @@ export type PublisherFunction = Notification extends voi export type SubscriberFunction = (listener: NotificationListener) => void; // We need the template parameter to force the Communicator to be "strongly typed" from the client perspective -export class NotificationChannelIdentifier<_Notification, _Response = void> implements ChannelIdentifier { +export class NotificationChannelIdentifier<_Notification, _Response = void> implements IChannelIdentifier { [Symbol.toStringTag]: 'NotificationChannelIdentifier' = 'NotificationChannelIdentifier'; constructor(public readonly identifierSymbol: Symbol = Symbol()) { } diff --git a/src/chrome/communication/requestsCommunicator.ts b/src/chrome/communication/requestsCommunicator.ts index 4329990e8..9475cd01b 100644 --- a/src/chrome/communication/requestsCommunicator.ts +++ b/src/chrome/communication/requestsCommunicator.ts @@ -3,7 +3,7 @@ *--------------------------------------------------------*/ import { ValidatedMap } from '../collections/validatedMap'; -import { ChannelIdentifier } from './channelIdentifier'; +import { IChannelIdentifier } from './channelIdentifier'; import { getChannelName } from './channel'; import { PromiseOrNot } from '../utils/promises'; @@ -15,7 +15,7 @@ export type RequestHandlerCallback = export type NonVoidRequestHandler = (request: Request) => Promise; // We need the template parameter to force the Communicator to be "strongly typed" from the client perspective -export class RequestChannelIdentifier<_Request, _Response> implements ChannelIdentifier { +export class RequestChannelIdentifier<_Request, _Response> implements IChannelIdentifier { [Symbol.toStringTag]: 'RequestChannelIdentifier' = 'RequestChannelIdentifier'; constructor(public readonly identifierSymbol: Symbol = Symbol()) { } @@ -25,12 +25,12 @@ export class RequestChannelIdentifier<_Request, _Response> implements ChannelIde } } -interface RequestHandler { +interface IRequestHandler { isRegistered(): boolean; call(request: Request): Promise; } -class NoRegisteredRequestHandler implements RequestHandler { +class NoRegisteredRequestHandler implements IRequestHandler { public isRegistered(): boolean { return false; } @@ -42,7 +42,7 @@ class NoRegisteredRequestHandler implements RequestHandler) { } } -class RegisteredRequestHandler implements RequestHandler { +class RegisteredRequestHandler implements IRequestHandler { public isRegistered(): boolean { return true; } @@ -56,7 +56,7 @@ class RegisteredRequestHandler implements RequestHandler { public readonly requester: Requester = new Requester(this); - public handler: RequestHandler = new NoRegisteredRequestHandler(this); + public handler: IRequestHandler = new NoRegisteredRequestHandler(this); public toString(): string { return `#${this._identifier}`; diff --git a/src/chrome/communication/targetChannels.ts b/src/chrome/communication/targetChannels.ts index a472f2057..2f3dc74f3 100644 --- a/src/chrome/communication/targetChannels.ts +++ b/src/chrome/communication/targetChannels.ts @@ -6,13 +6,13 @@ import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; import { NotificationChannelIdentifier } from './notificationsCommunicator'; import { Breakpoint } from '../internal/breakpoints/breakpoint'; import { registerChannels } from './channel'; -import { ScriptParsedEvent } from '../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; +import { IScriptParsedEvent } from '../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; import { PausedEvent } from '../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; const _debugger = { // Notifications OnAsyncBreakpointResolved: new NotificationChannelIdentifier>(), - OnScriptParsed: new NotificationChannelIdentifier(), + OnScriptParsed: new NotificationChannelIdentifier(), OnPaused: new NotificationChannelIdentifier(), OnResumed: new NotificationChannelIdentifier(), }; diff --git a/src/chrome/consoleHelper.ts b/src/chrome/consoleHelper.ts index 11f26041f..2624461bf 100644 --- a/src/chrome/consoleHelper.ts +++ b/src/chrome/consoleHelper.ts @@ -6,10 +6,10 @@ import { Protocol as CDTP } from 'devtools-protocol'; import * as Color from 'color'; import * as variables from './variables'; import { CodeFlowStackTrace } from './internal/stackTraces/codeFlowStackTrace'; -import { ExceptionDetails } from './cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider'; +import { IExceptionDetails } from './cdtpDebuggee/eventsProviders/cdtpExceptionThrownEventsProvider'; import { functionDescription } from './internal/stackTraces/callFramePresentation'; -export function formatExceptionDetails(e: ExceptionDetails): string { +export function formatExceptionDetails(e: IExceptionDetails): string { if (!e.exception) { return `${e.text || 'Uncaught Error'}\n${stackTraceToString(e.stackTrace)}`; } diff --git a/src/chrome/internal/breakpoints/bpRecipie.ts b/src/chrome/internal/breakpoints/bpRecipie.ts index 5fe348875..4a8c4cb2f 100644 --- a/src/chrome/internal/breakpoints/bpRecipie.ts +++ b/src/chrome/internal/breakpoints/bpRecipie.ts @@ -9,7 +9,7 @@ import { IScript } from '../scripts/script'; import { IBPActionWhenHit, AlwaysBreak } from './bpActionWhenHit'; import { utils } from '../../..'; import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; -import { IResourceIdentifier, URL } from '../sources/resourceIdentifier'; +import { IResourceIdentifier, IURL } from '../sources/resourceIdentifier'; import { URLRegexp, createURLRegexp } from '../locations/subtypes'; import { IEquivalenceComparable } from '../../utils/equivalence'; @@ -137,7 +137,7 @@ export class BPRecipieInScript - extends MappedBPRecipieCommonLogic, TBPActionWhenHit> implements IBPRecipie, TBPActionWhenHit> { + extends MappedBPRecipieCommonLogic, TBPActionWhenHit> implements IBPRecipie, TBPActionWhenHit> { } export class BPRecipieInUrlRegexp diff --git a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts index a849ea88f..2c2be2cf4 100644 --- a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts +++ b/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts @@ -12,7 +12,7 @@ import { createColumnNumber, createLineNumber } from '../locations/subtypes'; import { RangeInScript } from '../locations/rangeInScript'; import { BreakpointsRegistry } from './breakpointsRegistry'; import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; -import { VoteRelevance, Vote, Abstained } from '../../communication/collaborativeDecision'; +import { VoteRelevance, IVote, Abstained } from '../../communication/collaborativeDecision'; import { inject, injectable } from 'inversify'; import { IDebuggeeBreakpoints } from '../../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; import { IBreakpointFeaturesSupport } from '../../cdtpDebuggee/features/cdtpBreakpointFeaturesSupport'; @@ -39,7 +39,7 @@ export interface IBreakpointsInLoadedSource { addBreakpointAtLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise[]>; } -export interface BPRecipieAtLoadedSourceLogicDependencies { +export interface IBPRecipieAtLoadedSourceLogicDependencies { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; publishGoingToPauseClient(): void; } @@ -48,7 +48,7 @@ export interface BPRecipieAtLoadedSourceLogicDependencies { export class BPRecipieAtLoadedSourceLogic implements IBreakpointsInLoadedSource { private readonly doesTargetSupportColumnBreakpointsCached: Promise; - public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { if (paused.hitBreakpoints && paused.hitBreakpoints.length > 0) { // TODO DIEGO: Improve this to consider breakpoints where we shouldn't pause return new HitBreakpoint(this._eventsToClientReporter, @@ -118,7 +118,7 @@ export class BPRecipieAtLoadedSourceLogic implements IBreakpointsInLoadedSource } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: BPRecipieAtLoadedSourceLogicDependencies, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IBPRecipieAtLoadedSourceLogicDependencies, @inject(TYPES.IBreakpointFeaturesSupport) private readonly _breakpointFeaturesSupport: IBreakpointFeaturesSupport, private readonly _breakpointRegistry: BreakpointsRegistry, private readonly _bpRecipiesRegistry: CDTPBPRecipiesRegistry, diff --git a/src/chrome/internal/breakpoints/breakpoint.ts b/src/chrome/internal/breakpoints/breakpoint.ts index 29c93a5af..7a63c0791 100644 --- a/src/chrome/internal/breakpoints/breakpoint.ts +++ b/src/chrome/internal/breakpoints/breakpoint.ts @@ -6,7 +6,7 @@ import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../locations/l import { IBPRecipie } from './bpRecipie'; import { ILoadedSource } from '../sources/loadedSource'; import { IScript } from '../scripts/script'; -import { URL } from '../sources/resourceIdentifier'; +import { IURL } from '../sources/resourceIdentifier'; import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; import { URLRegexp } from '../locations/subtypes'; @@ -28,7 +28,7 @@ export class BreakpointInLoadedSource extends Breakpoint { } export class BreakpointInScript extends Breakpoint { } -export class BreakpointInUrl extends Breakpoint> { } +export class BreakpointInUrl extends Breakpoint> { } export class BreakpointInUrlRegexp extends Breakpoint { } diff --git a/src/chrome/internal/breakpoints/breakpointsLogic.ts b/src/chrome/internal/breakpoints/breakpointsLogic.ts index 3731fd63f..5039737cc 100644 --- a/src/chrome/internal/breakpoints/breakpointsLogic.ts +++ b/src/chrome/internal/breakpoints/breakpointsLogic.ts @@ -7,7 +7,7 @@ import { ITelemetryPropertyCollector, IComponent, ConnectedCDAConfiguration } fr import { ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; import { BPRecipiesInUnresolvedSource, BPRecipiesInLoadedSource } from './bpRecipies'; import { Breakpoint } from './breakpoint'; -import { ReAddBPsWhenSourceIsLoaded, EventsConsumedByReAddBPsWhenSourceIsLoaded } from './features/reAddBPsWhenSourceIsLoaded'; +import { ReAddBPsWhenSourceIsLoaded, IEventsConsumedByReAddBPsWhenSourceIsLoaded } from './features/reAddBPsWhenSourceIsLoaded'; import { asyncMap } from '../../collections/async'; import { IBPRecipieStatus } from './bpRecipieStatus'; import { ClientCurrentBPRecipiesRegistry } from './clientCurrentBPRecipiesRegistry'; @@ -15,7 +15,7 @@ import { BreakpointsRegistry } from './breakpointsRegistry'; import { BPRecipieAtLoadedSourceLogic } from './bpRecipieAtLoadedSourceLogic'; import { RemoveProperty } from '../../../typeUtils'; import { IEventsToClientReporter } from '../../client/eventSender'; -import { PauseScriptLoadsToSetBPs, PauseScriptLoadsToSetBPsDependencies } from './features/pauseScriptLoadsToSetBPs'; +import { PauseScriptLoadsToSetBPs, IPauseScriptLoadsToSetBPsDependencies } from './features/pauseScriptLoadsToSetBPs'; import { inject, injectable } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { IDebuggeeBreakpoints } from '../../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; @@ -24,8 +24,8 @@ import { CDTPBreakpoint } from '../../cdtpDebuggee/cdtpPrimitives'; import { ISource } from '../sources/source'; export interface InternalDependencies extends - EventsConsumedByReAddBPsWhenSourceIsLoaded, - PauseScriptLoadsToSetBPsDependencies { + IEventsConsumedByReAddBPsWhenSourceIsLoaded, + IPauseScriptLoadsToSetBPsDependencies { onAsyncBreakpointResolved(listener: (params: Breakpoint) => void): void; } diff --git a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts index 83ca1ead9..b4bdd1369 100644 --- a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts +++ b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts @@ -9,13 +9,13 @@ import { ValidatedMap } from '../../../collections/validatedMap'; import { HitCountConditionParser, HitCountConditionFunction } from '../hitCountConditionParser'; import { NotifyStoppedCommonLogic, InformationAboutPausedProvider } from '../../features/takeProperActionOnPausedEvent'; import { ReasonType } from '../../../stoppedEvent'; -import { Vote, Abstained, VoteRelevance } from '../../../communication/collaborativeDecision'; +import { IVote, Abstained, VoteRelevance } from '../../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; import { IEventsToClientReporter } from '../../../client/eventSender'; import { TYPES } from '../../../dependencyInjection.ts/types'; import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; -export interface HitCountBreakpointsDependencies { +export interface IHitCountBreakpointsDependencies { registerAddBPRecipieHandler(handlerRequirements: (bpRecipie: BPRecipieInSource) => boolean, handler: (bpRecipie: BPRecipieInSource) => Promise): void; @@ -69,7 +69,7 @@ export class HitCountBreakpoints implements IComponent { this.underlyingToBPRecipie.set(underlyingBPRecipie, new HitCountBPData(bpRecipie, shouldPauseCondition)); } - public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { const hitCountBPData = paused.hitBreakpoints.map(hitBPRecipie => this.underlyingToBPRecipie.tryGetting(hitBPRecipie.unmappedBPRecipie)).filter(bpRecipie => bpRecipie !== undefined); @@ -79,6 +79,6 @@ export class HitCountBreakpoints implements IComponent { : new Abstained(this); } - constructor(private readonly _dependencies: HitCountBreakpointsDependencies, + constructor(private readonly _dependencies: IHitCountBreakpointsDependencies, @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { } } \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts index 1cac3e4e2..b1320571b 100644 --- a/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts +++ b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts @@ -9,7 +9,7 @@ import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../../location import { IBreakpoint } from '../breakpoint'; import { NotifyStoppedCommonLogic, ResumeCommonLogic, InformationAboutPausedProvider } from '../../features/takeProperActionOnPausedEvent'; import { ReasonType } from '../../../stoppedEvent'; -import { VoteRelevance, Vote, Abstained } from '../../../communication/collaborativeDecision'; +import { VoteRelevance, IVote, Abstained } from '../../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../../dependencyInjection.ts/types'; import { IEventsToClientReporter } from '../../../client/eventSender'; @@ -21,7 +21,7 @@ import { IDebugeeRuntimeVersionProvider } from '../../../cdtpDebuggee/features/c import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; export type Dummy = VoteRelevance; // If we don't do this the .d.ts doesn't include VoteRelevance and the compilation fails. Remove this when the issue disappears... -export interface PauseScriptLoadsToSetBPsDependencies { +export interface IPauseScriptLoadsToSetBPsDependencies { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; waitUntilUnbindedBPsAreSet(loadedSource: ILoadedSource): Promise; @@ -66,7 +66,7 @@ export class PauseScriptLoadsToSetBPs implements IComponent { } } - private async askForInformationAboutPaused(paused: PausedEvent): Promise> { + private async askForInformationAboutPaused(paused: PausedEvent): Promise> { if (this.isInstrumentationPause(paused)) { await asyncMap(paused.callFrames[0].location.script.allSources, async source => { await this._reAddBPsWhenSourceIsLoaded.waitUntilBPsAreSet(source); @@ -120,7 +120,7 @@ export class PauseScriptLoadsToSetBPs implements IComponent { } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: PauseScriptLoadsToSetBPsDependencies, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IPauseScriptLoadsToSetBPsDependencies, @inject(TYPES.IDOMInstrumentationBreakpoints) private readonly _domInstrumentationBreakpoints: IDOMInstrumentationBreakpoints, @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionController, @inject(TYPES.IEventsToClientReporter) protected readonly _eventsToClientReporter: IEventsToClientReporter, diff --git a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts index 431e5e16f..b0083b0ed 100644 --- a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts +++ b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts @@ -8,13 +8,13 @@ import { asyncMap } from '../../../collections/async'; import { BPRecipieIsUnbinded, BPRecipieIsBinded } from '../bpRecipieStatus'; import { newResourceIdentifierMap, IResourceIdentifier } from '../../sources/resourceIdentifier'; import { IEventsToClientReporter } from '../../../client/eventSender'; -import { PromiseDefer, promiseDefer } from '../../../../utils'; +import { IPromiseDefer, promiseDefer } from '../../../../utils'; import { IComponent } from '../../features/feature'; import { injectable, inject } from 'inversify'; import { IBreakpointsInLoadedSource } from '../bpRecipieAtLoadedSourceLogic'; import { TYPES } from '../../../dependencyInjection.ts/types'; -export interface EventsConsumedByReAddBPsWhenSourceIsLoaded { +export interface IEventsConsumedByReAddBPsWhenSourceIsLoaded { onLoadedSourceIsAvailable(listener: (source: ILoadedSource) => Promise): void; notifyNoPendingBPs(): void; } @@ -22,7 +22,7 @@ export interface EventsConsumedByReAddBPsWhenSourceIsLoaded { @injectable() export class ReAddBPsWhenSourceIsLoaded implements IComponent { private readonly _sourcePathToBPRecipies = newResourceIdentifierMap(); - private readonly _sourcePathToBPsAreSetDefer = newResourceIdentifierMap>(); + private readonly _sourcePathToBPsAreSetDefer = newResourceIdentifierMap>(); public install(): void { this._dependencies.onLoadedSourceIsAvailable(source => this.onLoadedSourceIsAvailable(source)); @@ -42,7 +42,7 @@ export class ReAddBPsWhenSourceIsLoaded implements IComponent { } } - private getBPsAreSetDefer(identifier: IResourceIdentifier): PromiseDefer { + private getBPsAreSetDefer(identifier: IResourceIdentifier): IPromiseDefer { return this._sourcePathToBPsAreSetDefer.getOrAdd(identifier, () => promiseDefer()); } @@ -91,7 +91,7 @@ export class ReAddBPsWhenSourceIsLoaded implements IComponent { } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByReAddBPsWhenSourceIsLoaded, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedByReAddBPsWhenSourceIsLoaded, @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter, @inject(TYPES.BPRecipieInLoadedSourceLogic) private readonly _breakpointsInLoadedSource: IBreakpointsInLoadedSource) { } } \ No newline at end of file diff --git a/src/chrome/internal/domains/supportedDomains.ts b/src/chrome/internal/domains/supportedDomains.ts index 7835828bb..3c8e2a0e0 100644 --- a/src/chrome/internal/domains/supportedDomains.ts +++ b/src/chrome/internal/domains/supportedDomains.ts @@ -7,7 +7,7 @@ import { Protocol as CDTP } from 'devtools-protocol'; import { injectable } from 'inversify'; -export interface SupportedDomainsDependencies { +export interface ISupportedDomainsDependencies { getTargetDebuggerDomainsSchemas(): Promise; } @@ -37,5 +37,5 @@ export class SupportedDomains implements IComponent, ISupportedDomains { } } - constructor(private readonly _dependencies: SupportedDomainsDependencies) { } + constructor(private readonly _dependencies: ISupportedDomainsDependencies) { } } \ No newline at end of file diff --git a/src/chrome/internal/exceptions/pauseOnException.ts b/src/chrome/internal/exceptions/pauseOnException.ts index d3a763d8b..5b8e63c80 100644 --- a/src/chrome/internal/exceptions/pauseOnException.ts +++ b/src/chrome/internal/exceptions/pauseOnException.ts @@ -7,8 +7,8 @@ import { IComponent } from '../features/feature'; import * as errors from '../../../errors'; import { utils } from '../../..'; import { FormattedExceptionParser, IFormattedExceptionLineDescription } from '../formattedExceptionParser'; -import { PauseOnPromiseRejectionsStrategy, PauseOnExceptionsStrategy } from './strategies'; -import { VoteRelevance, Vote, Abstained } from '../../communication/collaborativeDecision'; +import { IPauseOnPromiseRejectionsStrategy, IPauseOnExceptionsStrategy } from './strategies'; +import { VoteRelevance, IVote, Abstained } from '../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { IEventsToClientReporter } from '../../client/eventSender'; @@ -34,7 +34,7 @@ export interface IExceptionInformation { readonly details?: IExceptionInformationDetails; } -export interface EventsConsumedByPauseOnException { +export interface IEventsConsumedByPauseOnException { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; publishGoingToPauseClient(): void; } @@ -61,19 +61,19 @@ export class PromiseWasRejected extends NotifyStoppedCommonLogic { @injectable() export class PauseOnExceptionOrRejection implements IComponent { - private _promiseRejectionsStrategy: PauseOnPromiseRejectionsStrategy; + private _promiseRejectionsStrategy: IPauseOnPromiseRejectionsStrategy; private _lastException: any; - public setExceptionsStrategy(strategy: PauseOnExceptionsStrategy): Promise { + public setExceptionsStrategy(strategy: IPauseOnExceptionsStrategy): Promise { return this._pauseOnExceptions.setPauseOnExceptions(strategy); } - public setPromiseRejectionStrategy(promiseRejectionsStrategy: PauseOnPromiseRejectionsStrategy): void { + public setPromiseRejectionStrategy(promiseRejectionsStrategy: IPauseOnPromiseRejectionsStrategy): void { this._promiseRejectionsStrategy = promiseRejectionsStrategy; } - public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { if (paused.reason === 'exception') { // If we are here is because we either configured the debugee to pauser on unhandled or handled exceptions this._lastException = paused.data; @@ -115,7 +115,7 @@ export class PauseOnExceptionOrRejection implements IComponent { return this; } - constructor(@inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByPauseOnException, + constructor(@inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedByPauseOnException, @inject(TYPES.DeleteMeScriptsRegistry) private readonly _scriptsLogic: DeleteMeScriptsRegistry, @inject(TYPES.IPauseOnExceptions) private readonly _pauseOnExceptions: IPauseOnExceptionsConfigurer, @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { } diff --git a/src/chrome/internal/exceptions/strategies.ts b/src/chrome/internal/exceptions/strategies.ts index aec0619bd..a66eea670 100644 --- a/src/chrome/internal/exceptions/strategies.ts +++ b/src/chrome/internal/exceptions/strategies.ts @@ -2,25 +2,25 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -export interface PauseOnExceptionsStrategy { +export interface IPauseOnExceptionsStrategy { } -export class PauseOnUnhandledExceptions implements PauseOnExceptionsStrategy { } -export class PauseOnAllExceptions implements PauseOnExceptionsStrategy { } -export class DoNotPauseOnAnyExceptions implements PauseOnExceptionsStrategy { } +export class PauseOnUnhandledExceptions implements IPauseOnExceptionsStrategy { } +export class PauseOnAllExceptions implements IPauseOnExceptionsStrategy { } +export class DoNotPauseOnAnyExceptions implements IPauseOnExceptionsStrategy { } -export interface PauseOnPromiseRejectionsStrategy { +export interface IPauseOnPromiseRejectionsStrategy { shouldPauseOnRejections(): boolean; } -export class PauseOnAllRejections implements PauseOnPromiseRejectionsStrategy { +export class PauseOnAllRejections implements IPauseOnPromiseRejectionsStrategy { public shouldPauseOnRejections(): boolean { return true; } } -export class DoNotPauseOnAnyRejections implements PauseOnPromiseRejectionsStrategy { +export class DoNotPauseOnAnyRejections implements IPauseOnPromiseRejectionsStrategy { public shouldPauseOnRejections(): boolean { return false; } diff --git a/src/chrome/internal/features/skipFiles.ts b/src/chrome/internal/features/skipFiles.ts index e7425d0a1..c373cdbfa 100644 --- a/src/chrome/internal/features/skipFiles.ts +++ b/src/chrome/internal/features/skipFiles.ts @@ -14,7 +14,7 @@ import * as nls from 'vscode-nls'; import { injectable, inject, LazyServiceIdentifer } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { ClientToInternal } from '../../client/clientToInternal'; -import { ScriptParsedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; +import { IScriptParsedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; import { IBlackboxPatternsConfigurer } from '../../cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer'; import { IToggleSkipFileStatusArgs } from '../../../debugAdapterInterfaces'; import * as utils from '../../../utils'; @@ -22,8 +22,8 @@ import { BaseSourceMapTransformer } from '../../../transformers/baseSourceMapTra import { ConnectedCDAConfiguration } from '../../client/chromeDebugAdapter/cdaConfiguration'; const localize = nls.loadMessageBundle(); -export interface EventsConsumedBySkipFilesLogic { - onScriptParsed(listener: (scriptEvent: ScriptParsedEvent) => Promise): void; +export interface IEventsConsumedBySkipFilesLogic { + onScriptParsed(listener: (scriptEvent: IScriptParsedEvent) => Promise): void; } export interface ISkipFilesConfiguration { @@ -241,7 +241,7 @@ export class SkipFilesLogic implements IComponent, ISta logger.log('Warning: this runtime does not support skipFiles'); } - private async onScriptParsed(scriptEvent: ScriptParsedEvent): Promise { + private async onScriptParsed(scriptEvent: IScriptParsedEvent): Promise { const script = scriptEvent.script; const sources = script.mappedSources; await this.resolveSkipFiles(script, script.developmentSource.identifier, sources.map(source => source.identifier)); @@ -283,7 +283,7 @@ export class SkipFilesLogic implements IComponent, ISta } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedBySkipFilesLogic, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedBySkipFilesLogic, @inject(new LazyServiceIdentifer(() => TYPES.StackTracesLogic)) private readonly stackTracesLogic: StackTracesLogic, @inject(TYPES.BaseSourceMapTransformer) private readonly sourceMapTransformer: BaseSourceMapTransformer, @inject(TYPES.ClientToInternal) private readonly _clientToInternal: ClientToInternal, diff --git a/src/chrome/internal/features/smartStep.ts b/src/chrome/internal/features/smartStep.ts index 1d350e458..f9474f596 100644 --- a/src/chrome/internal/features/smartStep.ts +++ b/src/chrome/internal/features/smartStep.ts @@ -11,7 +11,7 @@ import { logger } from 'vscode-debugadapter'; import { IComponent } from './feature'; import { LocationInLoadedSource } from '../locations/location'; import { ICallFramePresentationDetails } from '../stackTraces/callFramePresentation'; -import { Abstained, VoteRelevance, VoteCommonLogic, Vote } from '../../communication/collaborativeDecision'; +import { Abstained, VoteRelevance, VoteCommonLogic, IVote } from '../../communication/collaborativeDecision'; import * as nls from 'vscode-nls'; import { injectable, inject } from 'inversify'; import { IStackTracePresentationLogicProvider } from '../stackTraces/stackTracesLogic'; @@ -19,21 +19,21 @@ import { TYPES } from '../../dependencyInjection.ts/types'; import { utils, ConnectedCDAConfiguration } from '../../..'; const localize = nls.loadMessageBundle(); -export interface EventsConsumedBySmartStepLogic { +export interface IEventsConsumedBySmartStepLogic { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; } -export interface SmartStepLogicConfiguration { +export interface ISmartStepLogicConfiguration { isEnabled: boolean; } -export interface ShouldStepInToAvoidSkippedSourceDependencies { +export interface IShouldStepInToAvoidSkippedSourceDependencies { stepIntoDebugee(): Promise; } export class ShouldStepInToAvoidSkippedSource extends VoteCommonLogic { public readonly relevance = VoteRelevance.OverrideOtherVotes; - private readonly _dependencies: ShouldStepInToAvoidSkippedSourceDependencies; + private readonly _dependencies: IShouldStepInToAvoidSkippedSourceDependencies; public async execute(): Promise { return this._dependencies.stepIntoDebugee(); @@ -62,7 +62,7 @@ export class SmartStepLogic implements IComponent, IStackTracePresentationLogicP this.stepInIfOnSkippedSource(); } - public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { if (this.isEnabled() && await this.shouldSkip(paused.callFrames[0])) { this._smartStepCount++; return new ShouldStepInToAvoidSkippedSource(); @@ -116,7 +116,7 @@ export class SmartStepLogic implements IComponent, IStackTracePresentationLogicP } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedBySmartStepLogic, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedBySmartStepLogic, @inject(TYPES.BasePathTransformer) private readonly _pathTransformer: BasePathTransformer, @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration diff --git a/src/chrome/internal/features/takeProperActionOnPausedEvent.ts b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts index 04216bd6b..a79cac863 100644 --- a/src/chrome/internal/features/takeProperActionOnPausedEvent.ts +++ b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts @@ -7,7 +7,7 @@ import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExec import { IEventsToClientReporter } from '../../client/eventSender'; import { ReasonType } from '../../stoppedEvent'; import { PromiseOrNot } from '../../utils/promises'; -import { Vote, VoteCommonLogic, VoteRelevance, ExecuteDecisionBasedOnVotes } from '../../communication/collaborativeDecision'; +import { IVote, VoteCommonLogic, VoteRelevance, ExecuteDecisionBasedOnVotes } from '../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; import { IDebugeeExecutionController } from '../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; @@ -33,9 +33,9 @@ export abstract class NotifyStoppedCommonLogic extends VoteCommonLogic { } } -export type InformationAboutPausedProvider = (paused: PausedEvent) => Promise>; +export type InformationAboutPausedProvider = (paused: PausedEvent) => Promise>; -export interface EventsConsumedByTakeProperActionOnPausedEvent extends TakeActionBasedOnInformationDependencies { +export interface IEventsConsumedByTakeProperActionOnPausedEvent extends ITakeActionBasedOnInformationDependencies { // onPaused(listener: (paused: PausedEvent) => Promise | void): void; } @@ -57,13 +57,13 @@ export class TakeProperActionOnPausedEvent implements IComponent { } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: TakeActionBasedOnInformationDependencies, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: ITakeActionBasedOnInformationDependencies, @inject(TYPES.ICDTPDebuggerEventsProvider) private readonly _cdtpDebuggerEventsProvider: ICDTDebuggeeExecutionEventsProvider, @inject(TYPES.IEventsToClientReporter) private readonly _eventsToClientReporter: IEventsToClientReporter) { } } -export interface TakeActionBasedOnInformationDependencies { - askForInformationAboutPause(paused: PausedEvent): PromiseOrNot[]>; +export interface ITakeActionBasedOnInformationDependencies { + askForInformationAboutPause(paused: PausedEvent): PromiseOrNot[]>; } export class TakeActionBasedOnInformation { @@ -85,7 +85,7 @@ export class TakeActionBasedOnInformation { } } - constructor(piecesOfInformation: Vote[], + constructor(piecesOfInformation: IVote[], private readonly _eventsToClientReporter: IEventsToClientReporter) { this._takeActionBasedOnVotes = new ExecuteDecisionBasedOnVotes(async () => { // If we don't have any information whatsoever, then we assume that we stopped due to a debugger statement diff --git a/src/chrome/internal/locations/location.ts b/src/chrome/internal/locations/location.ts index 3b8ec8d4e..9445e08cc 100644 --- a/src/chrome/internal/locations/location.ts +++ b/src/chrome/internal/locations/location.ts @@ -9,7 +9,7 @@ import { ILoadedSource } from '../sources/loadedSource'; import { logger } from 'vscode-debugadapter'; import { ColumnNumber, LineNumber, URLRegexp } from './subtypes'; import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; -import { IResourceIdentifier, parseResourceIdentifier, URL } from '../sources/resourceIdentifier'; +import { IResourceIdentifier, parseResourceIdentifier, IURL } from '../sources/resourceIdentifier'; import { IEquivalenceComparable } from '../../utils/equivalence'; export type integer = number; @@ -41,14 +41,14 @@ export interface ILocation extends IEq readonly resource: T; } -export type ScriptOrSourceOrURLOrURLRegexp = IScript | ILoadedSource | ISource | URLRegexp | URL; +export type ScriptOrSourceOrURLOrURLRegexp = IScript | ILoadedSource | ISource | URLRegexp | IURL; export type Location = T extends ISource ? LocationInSource : // Used when receiving locations from the client T extends ILoadedSource ? LocationInLoadedSource : // Used to translate between locations on the client and the debugee T extends IScript ? LocationInScript : // Used when receiving locations from the debugee T extends URLRegexp ? LocationInUrlRegexp : // Used when setting a breakpoint by URL in a local file path in windows, to make it case insensitive - T extends URL ? LocationInUrl : // Used when setting a breakpoint by URL for case-insensitive URLs + T extends IURL ? LocationInUrl : // Used when setting a breakpoint by URL for case-insensitive URLs ILocation; // TODO: Figure out how to replace this by never (We run into some issues with the isEquivalentTo call if we do) abstract class LocationCommonLogic implements ILocation { @@ -152,7 +152,7 @@ export class LocationInLoadedSource extends LocationCommonLogic { } export class LocationInUrl extends LocationCommonLogic> { - public get url(): URL { + public get url(): IURL { return this.resource; } } diff --git a/src/chrome/internal/requests.ts b/src/chrome/internal/requests.ts index 2bed390fc..277106d50 100644 --- a/src/chrome/internal/requests.ts +++ b/src/chrome/internal/requests.ts @@ -4,7 +4,7 @@ import { LoadedSourceCallFrame } from './stackTraces/callFrame'; -export interface EvaluateArguments { +export interface IEvaluateArguments { readonly expression: string; readonly frame?: LoadedSourceCallFrame; readonly context?: string; @@ -14,7 +14,7 @@ export interface EvaluateArguments { }; } -export interface CompletionsArguments { +export interface ICompletionsArguments { readonly frame?: LoadedSourceCallFrame; readonly text: string; readonly column: number; diff --git a/src/chrome/internal/services/logging.ts b/src/chrome/internal/services/logging.ts index ddf5025ea..a8717ce3f 100644 --- a/src/chrome/internal/services/logging.ts +++ b/src/chrome/internal/services/logging.ts @@ -5,7 +5,7 @@ import { Logger, logger } from 'vscode-debugadapter'; import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; -export interface LoggingConfiguration { +export interface ILoggingConfiguration { logLevel?: Logger.LogLevel; shouldLogTimestamps: boolean; logFilePath: string; @@ -16,12 +16,12 @@ export class Logging { logger.verbose(entry); } - public install(extensibilityPoints: IExtensibilityPoints, configuration: LoggingConfiguration): this { + public install(extensibilityPoints: IExtensibilityPoints, configuration: ILoggingConfiguration): this { this.configure(extensibilityPoints, configuration); return this; } - public configure(extensibilityPoints: IExtensibilityPoints, configuration: LoggingConfiguration): void { + public configure(extensibilityPoints: IExtensibilityPoints, configuration: ILoggingConfiguration): void { const logToFile = !!configuration.logLevel; // The debug configuration provider should have set logFilePath on the launch config. If not, default to 'true' to use the diff --git a/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts index 5ae86a649..ef7b415fb 100644 --- a/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts +++ b/src/chrome/internal/sources/features/notifyClientOfLoadedSources.ts @@ -5,17 +5,17 @@ import { IComponent } from '../../features/feature'; import { IScript } from '../../scripts/script'; import { telemetry } from '../../../../telemetry'; -import { SourceWasLoadedParameters, IEventsToClientReporter } from '../../../client/eventSender'; +import { ISourceWasLoadedParameters, IEventsToClientReporter } from '../../../client/eventSender'; import { ValidatedMap } from '../../../collections/validatedMap'; import { CDTPScriptUrl } from '../resourceIdentifierSubtypes'; import { LoadedSourceEventReason, utils } from '../../../..'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../../dependencyInjection.ts/types'; -import { ScriptParsedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; +import { IScriptParsedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; -export interface NotifyClientOfLoadedSourcesDependencies { - sendSourceWasLoaded(params: SourceWasLoadedParameters): Promise; - onScriptParsed(listener: (scriptEvent: ScriptParsedEvent) => Promise): void; +export interface INotifyClientOfLoadedSourcesDependencies { + sendSourceWasLoaded(params: ISourceWasLoadedParameters): Promise; + onScriptParsed(listener: (scriptEvent: IScriptParsedEvent) => Promise): void; } @injectable() @@ -72,6 +72,6 @@ export class NotifyClientOfLoadedSources implements IComponent { } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: NotifyClientOfLoadedSourcesDependencies, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: INotifyClientOfLoadedSourcesDependencies, @inject(TYPES.EventSender) private readonly _eventsToClientReporter: IEventsToClientReporter) { } } \ No newline at end of file diff --git a/src/chrome/internal/sources/resourceIdentifier.ts b/src/chrome/internal/sources/resourceIdentifier.ts index e6ec25225..8d9ba864d 100644 --- a/src/chrome/internal/sources/resourceIdentifier.ts +++ b/src/chrome/internal/sources/resourceIdentifier.ts @@ -66,10 +66,10 @@ export class ResourceName extends IsEquivalentA export interface IResourceLocation extends IResourceIdentifier { } // A standard URL -export interface URL extends IResourceLocation { } +export interface IURL extends IResourceLocation { } // A local file URL is a 'file:///' url -export class LocalFileURL extends IsEquivalentCommonLogic implements URL { +export class LocalFileURL extends IsEquivalentCommonLogic implements IURL { private _localResourcePath: ILocalFilePath; public static isValid(path: string) { @@ -100,7 +100,7 @@ export class LocalFileURL extends IsEquivalentC } // Any URL that is not a 'file:///' url -export class NonLocalFileURL extends IsEquivalentAndConstructorCommonLogic implements URL { +export class NonLocalFileURL extends IsEquivalentAndConstructorCommonLogic implements IURL { public toString(): string { return path.basename(this.textRepresentation); } @@ -186,7 +186,7 @@ function parseLocalResourcePath(path: TString): } } -function parseURL(textRepresentation: TString): URL { +function parseURL(textRepresentation: TString): IURL { if (LocalFileURL.isValid(textRepresentation)) { return new LocalFileURL(textRepresentation); } else { diff --git a/src/chrome/internal/sources/resourceIdentifierSubtypes.ts b/src/chrome/internal/sources/resourceIdentifierSubtypes.ts index 910a8d6d5..d8d81e07a 100644 --- a/src/chrome/internal/sources/resourceIdentifierSubtypes.ts +++ b/src/chrome/internal/sources/resourceIdentifierSubtypes.ts @@ -12,11 +12,11 @@ export function createCDTPScriptUrl(textRepresentation: string): CDTPScriptUrl { } const ScriptDevelopmentLocationSymbol = Symbol(); -export interface ScriptDevelopmentLocation extends IResourceIdentifier { +export interface IScriptDevelopmentLocation extends IResourceIdentifier { readonly [ScriptDevelopmentLocationSymbol]: true; } const MappedSourceLocationSymbol = Symbol(); -export interface MappedSourceLocation extends IResourceIdentifier { +export interface IMappedSourceLocation extends IResourceIdentifier { readonly [MappedSourceLocationSymbol]: true; } diff --git a/src/chrome/internal/sources/sourceResolver.ts b/src/chrome/internal/sources/sourceResolver.ts index 1c45c4641..a6c5c531a 100644 --- a/src/chrome/internal/sources/sourceResolver.ts +++ b/src/chrome/internal/sources/sourceResolver.ts @@ -8,10 +8,10 @@ import { newResourceIdentifierMap, IResourceIdentifier } from './resourceIdentif import { IComponent } from '../features/feature'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; -import { ScriptParsedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; +import { IScriptParsedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; -export interface EventsConsumedBySourceResolver { - onScriptParsed(listener: (scriptEvent: ScriptParsedEvent) => Promise): void; +export interface IEventsConsumedBySourceResolver { + onScriptParsed(listener: (scriptEvent: IScriptParsedEvent) => Promise): void; } /** @@ -53,5 +53,5 @@ export class SourceResolver implements IComponent { } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedBySourceResolver) { } + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedBySourceResolver) { } } diff --git a/src/chrome/internal/stackTraces/stackTracesLogic.ts b/src/chrome/internal/stackTraces/stackTracesLogic.ts index fbfc7189e..b2fab175d 100644 --- a/src/chrome/internal/stackTraces/stackTracesLogic.ts +++ b/src/chrome/internal/stackTraces/stackTracesLogic.ts @@ -20,12 +20,12 @@ import { InformationAboutPausedProvider } from '../features/takeProperActionOnPa import { asyncMap } from '../../collections/async'; import { TYPES } from '../../dependencyInjection.ts/types'; import { ConnectedCDAConfiguration } from '../../..'; -import { Vote, Abstained } from '../../communication/collaborativeDecision'; +import { IVote, Abstained } from '../../communication/collaborativeDecision'; import { IAsyncDebuggingConfigurer } from '../../cdtpDebuggee/features/CDTPAsyncDebuggingConfigurer'; import { IStackTracePresentationRow, StackTraceLabel, CallFramePresentationHint } from './stackTracePresentationRow'; import { IStackTracePresentation } from './stackTracePresentation'; -export interface EventsConsumedByStackTrace { +export interface IEventsConsumedByStackTrace { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; onResumed(listener: () => void): void; } @@ -48,7 +48,7 @@ export class StackTracesLogic implements IComponent { this._currentPauseEvent = null; } - public async onPaused(pausedEvent: PausedEvent): Promise> { + public async onPaused(pausedEvent: PausedEvent): Promise> { this._currentPauseEvent = pausedEvent; return new Abstained(this); } @@ -138,7 +138,7 @@ export class StackTracesLogic implements IComponent { } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByStackTrace, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedByStackTrace, // TODO DIEGO: @multiInject(new LazyServiceIdentifer(() => TYPES.IStackTracePresentationLogicProvider)) private readonly _stackTracePresentationLogicProviders: IStackTracePresentationLogicProvider[], @inject(TYPES.IStackTracePresentationLogicProvider) private readonly _stackTracePresentationLogicProviders: IStackTracePresentationLogicProvider, @inject(TYPES.IAsyncDebuggingConfiguration) private readonly _breakpointFeaturesSupport: IAsyncDebuggingConfigurer, diff --git a/src/chrome/internal/stepping/features/asyncStepping.ts b/src/chrome/internal/stepping/features/asyncStepping.ts index 5e352906c..51fcfef3e 100644 --- a/src/chrome/internal/stepping/features/asyncStepping.ts +++ b/src/chrome/internal/stepping/features/asyncStepping.ts @@ -4,14 +4,14 @@ import { IComponent } from '../../features/feature'; import { InformationAboutPausedProvider, ResumeCommonLogic } from '../../features/takeProperActionOnPausedEvent'; -import { VoteRelevance, Vote, Abstained } from '../../../communication/collaborativeDecision'; +import { VoteRelevance, IVote, Abstained } from '../../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../../dependencyInjection.ts/types'; import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { IDebugeeExecutionController } from '../../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; import { IDebugeeSteppingController } from '../../../cdtpDebuggee/features/CDTPDebugeeSteppingController'; -export interface EventsConsumedByAsyncStepping { +export interface IEventsConsumedByAsyncStepping { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; } @@ -25,7 +25,7 @@ export class PausedBecauseAsyncCallWasScheduled extends ResumeCommonLogic { @injectable() export class AsyncStepping implements IComponent { - public async askForInformationAboutPaused(paused: PausedEvent): Promise> { + public async askForInformationAboutPaused(paused: PausedEvent): Promise> { if (paused.asyncCallStackTraceId) { await this._debugeeStepping.pauseOnAsyncCall({ parentStackTraceId: paused.asyncCallStackTraceId }); return new PausedBecauseAsyncCallWasScheduled(this._debugeeExecutionControl); @@ -39,7 +39,7 @@ export class AsyncStepping implements IComponent { } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: EventsConsumedByAsyncStepping, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedByAsyncStepping, @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionController, @inject(TYPES.IDebugeeSteppingController) private readonly _debugeeStepping: IDebugeeSteppingController) { } } \ No newline at end of file diff --git a/src/chrome/internal/stepping/features/syncStepping.ts b/src/chrome/internal/stepping/features/syncStepping.ts index 51230a5f3..3cb3bbdde 100644 --- a/src/chrome/internal/stepping/features/syncStepping.ts +++ b/src/chrome/internal/stepping/features/syncStepping.ts @@ -5,7 +5,7 @@ import { ScriptCallFrame } from '../../stackTraces/callFrame'; import { InformationAboutPausedProvider, } from '../../features/takeProperActionOnPausedEvent'; import { IComponent } from '../../features/feature'; -import { Abstained, Vote } from '../../../communication/collaborativeDecision'; +import { Abstained, IVote } from '../../../communication/collaborativeDecision'; import { injectable, inject } from 'inversify'; import { IDebugeeExecutionController } from '../../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; import { TYPES } from '../../../dependencyInjection.ts/types'; @@ -31,7 +31,7 @@ class CurrentlyIdle implements SyncSteppingStatus { } } -export interface SyncSteppingDependencies { +export interface ISyncSteppingDependencies { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; } @@ -51,7 +51,7 @@ export class SyncStepping implements IComponent { return this._debugeeExecutionControl.pause(); } - private async askForInformationAboutPaused(_paused: PausedEvent): Promise> { + private async askForInformationAboutPaused(_paused: PausedEvent): Promise> { return new Abstained(this); } @@ -74,7 +74,7 @@ export class SyncStepping implements IComponent { } constructor( - @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: SyncSteppingDependencies, + @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: ISyncSteppingDependencies, @inject(TYPES.IDebugeeSteppingController) private readonly _debugeeStepping: IDebugeeSteppingController, @inject(TYPES.IDebugeeExecutionControl) private readonly _debugeeExecutionControl: IDebugeeExecutionController) { } } \ No newline at end of file diff --git a/src/debugAdapterInterfaces.d.ts b/src/debugAdapterInterfaces.d.ts index d13fba622..3550e9246 100644 --- a/src/debugAdapterInterfaces.d.ts +++ b/src/debugAdapterInterfaces.d.ts @@ -134,13 +134,13 @@ export interface IExceptionInfoResponseBody extends DAPExceptionInfoResponseBody export declare type PromiseOrNot = T | Promise; -export interface TimeTravelClient { +export interface ITimeTravelClient { stepBack(): Promise; reverse(): Promise; } -export interface TimeTravelRuntime extends CDTP.ProtocolApi { - TimeTravel: TimeTravelClient; +export interface ITimeTravelRuntime extends CDTP.ProtocolApi { + TimeTravel: ITimeTravelClient; } export interface IUninitializedDebugAdapter { diff --git a/src/executionTimingsReporter.ts b/src/executionTimingsReporter.ts index 649939ec1..1e4385b82 100644 --- a/src/executionTimingsReporter.ts +++ b/src/executionTimingsReporter.ts @@ -41,14 +41,14 @@ export interface IStepStartedEventsEmitter { removeListener(event: 'milestoneReached', listener: (args: IMilestoneReachedEventArguments) => void): this; } -export interface FinishedStartingUpEventArguments { +export interface IFinishedStartingUpEventArguments { requestedContentWasDetected: boolean; reasonForNotDetected: string; } export interface IFinishedStartingUpEventsEmitter { - on(event: 'finishedStartingUp', listener: (args: FinishedStartingUpEventArguments) => void): this; - once(event: 'finishedStartingUp', listener: (args: FinishedStartingUpEventArguments) => void): this; + on(event: 'finishedStartingUp', listener: (args: IFinishedStartingUpEventArguments) => void): this; + once(event: 'finishedStartingUp', listener: (args: IFinishedStartingUpEventArguments) => void): this; removeListener(event: 'finishedStartingUp', listener: () => void): this; removeListener(event: 'finishedStartingUp', listener: () => void): this; } diff --git a/src/utils.ts b/src/utils.ts index 2e8bb8987..28bd7aee1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -607,13 +607,13 @@ export function toVoidP(p: Promise): Promise { return p.then(() => { }); } -export interface PromiseDefer { +export interface IPromiseDefer { readonly promise: Promise; resolve: (value?: T | PromiseLike) => void; reject: (reason?: any) => void; } -export function promiseDefer(): PromiseDefer { +export function promiseDefer(): IPromiseDefer { let resolveCallback; let rejectCallback; const promise = new Promise((resolve, reject) => { From e3442d68e2e1a45a161c2faf1085058c8cb5b42e Mon Sep 17 00:00:00 2001 From: digeff Date: Thu, 17 Jan 2019 17:06:08 -0800 Subject: [PATCH 14/23] Fix multiline /** comments --- src/chrome/internal/scripts/executionContext.ts | 3 ++- src/chrome/internal/scripts/script.ts | 3 ++- src/chrome/internal/sources/loadedSource.ts | 3 ++- src/chrome/internal/sources/resourceIdentifier.ts | 3 ++- src/chrome/internal/stackTraces/callFrame.ts | 9 ++++++--- .../internal/stackTraces/formatCallFrameDescription.ts | 3 ++- .../internal/stackTraces/stackTracePresentation.ts | 3 ++- 7 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/chrome/internal/scripts/executionContext.ts b/src/chrome/internal/scripts/executionContext.ts index 512272cf6..ec2e0cef8 100644 --- a/src/chrome/internal/scripts/executionContext.ts +++ b/src/chrome/internal/scripts/executionContext.ts @@ -2,7 +2,8 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -/** This interface represents the execution context in CDTP where a script is executed. A new context is created when a page is refreshed, etc... +/** + * This interface represents the execution context in CDTP where a script is executed. A new context is created when a page is refreshed, etc... * We keep track of this because only scripts of non destroyed execution contexts should be displayed to the user */ export interface IExecutionContext { diff --git a/src/chrome/internal/scripts/script.ts b/src/chrome/internal/scripts/script.ts index 2c183f23b..be9fa8581 100644 --- a/src/chrome/internal/scripts/script.ts +++ b/src/chrome/internal/scripts/script.ts @@ -16,7 +16,8 @@ import { IExecutionContext } from './executionContext'; import { Lazy1 } from '../../utils/lazy'; import { IEquivalenceComparable } from '../../utils/equivalence'; -/** This interface represents a piece of code that is being executed in the debugee. Usually a script matches to a file or a url, but that is not always the case. +/** + * This interface represents a piece of code that is being executed in the debugee. Usually a script matches to a file or a url, but that is not always the case. * This interface solves the problem of finding the different loaded sources associated with a script, and being able to identify and compare both scripts and sources easily. */ export interface IScript extends IEquivalenceComparable { diff --git a/src/chrome/internal/sources/loadedSource.ts b/src/chrome/internal/sources/loadedSource.ts index 2f520ff2e..95271b715 100644 --- a/src/chrome/internal/sources/loadedSource.ts +++ b/src/chrome/internal/sources/loadedSource.ts @@ -8,7 +8,8 @@ import { IResourceIdentifier, parseResourceIdentifier, ResourceName } from './re import { determineOrderingOfStrings } from '../../collections/utilities'; import { IEquivalenceComparable } from '../../utils/equivalence'; -/** This interface represents a source or text that is related to a script that the debugee is executing. The text can be the contents of the script itself, +/** + * This interface represents a source or text that is related to a script that the debugee is executing. The text can be the contents of the script itself, * or a file from which the script was loaded, or a file that was compiled to generate the contents of the script */ export interface ILoadedSource extends IEquivalenceComparable { diff --git a/src/chrome/internal/sources/resourceIdentifier.ts b/src/chrome/internal/sources/resourceIdentifier.ts index 8d9ba864d..21ddaf375 100644 --- a/src/chrome/internal/sources/resourceIdentifier.ts +++ b/src/chrome/internal/sources/resourceIdentifier.ts @@ -8,7 +8,8 @@ import { IValidatedMap } from '../../collections/validatedMap'; import { MapUsingProjection } from '../../collections/mapUsingProjection'; import { IEquivalenceComparable } from '../../utils/equivalence'; -/** Hierarchy: +/** + * Hierarchy: * IResourceIdentifier: Identifies a resource * IResourceLocation: Identifies and tells us how to get the resource * URL: Url diff --git a/src/chrome/internal/stackTraces/callFrame.ts b/src/chrome/internal/stackTraces/callFrame.ts index 9c0b7bdeb..ef113084e 100644 --- a/src/chrome/internal/stackTraces/callFrame.ts +++ b/src/chrome/internal/stackTraces/callFrame.ts @@ -8,7 +8,8 @@ import { IScript } from '../scripts/script'; import { Protocol as CDTP } from 'devtools-protocol'; import { Scope } from './scopes'; -/** CDTP has two types of stack traces: +/** + * CDTP has two types of stack traces: * 1. CDTP.Runtime stack traces have only information about which code was executed, but not the state associated with it * 2. CDTP.Debugger stack traces which have all the information that CDTP.Runtime has, and it also includes state information * @@ -18,7 +19,8 @@ import { Scope } from './scopes'; export type ScriptOrLoadedSource = IScript | ILoadedSource; -/** This class represents the code flow (which code was executed) of a call frame. +/** + * This class represents the code flow (which code was executed) of a call frame. * (This has similar properties as the stack traces from the CDTP.Runtime domain) */ export class CodeFlowFrame { @@ -44,7 +46,8 @@ export class CodeFlowFrame { } } -/** This interface represents both the code flow and the state of a call frame. +/** + * This interface represents both the code flow and the state of a call frame. * (This has similar properties as the stack traces from the CDTP.Debugger domain) */ export interface ICallFrame { diff --git a/src/chrome/internal/stackTraces/formatCallFrameDescription.ts b/src/chrome/internal/stackTraces/formatCallFrameDescription.ts index ac310e447..903679f31 100644 --- a/src/chrome/internal/stackTraces/formatCallFrameDescription.ts +++ b/src/chrome/internal/stackTraces/formatCallFrameDescription.ts @@ -7,7 +7,8 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { LoadedSourceCallFrame } from './callFrame'; import { functionDescription } from './callFramePresentation'; -/** The clients can requests the stack traces frames descriptions in different formats. +/** + * The clients can requests the stack traces frames descriptions in different formats. * We use this function to create the description for the call frame according to the parameters supplied by the client. */ export function formatCallFrameDescription(callFrame: LoadedSourceCallFrame, formatArgs?: DebugProtocol.StackFrameFormat): string { diff --git a/src/chrome/internal/stackTraces/stackTracePresentation.ts b/src/chrome/internal/stackTraces/stackTracePresentation.ts index 9dbb7221b..c89bd7e1f 100644 --- a/src/chrome/internal/stackTraces/stackTracePresentation.ts +++ b/src/chrome/internal/stackTraces/stackTracePresentation.ts @@ -4,7 +4,8 @@ import { IStackTracePresentationRow } from './stackTracePresentationRow'; -/** The stack traces we sent to the client will be represented by this classes and it is a combination of: +/** + * The stack traces we sent to the client will be represented by this classes and it is a combination of: * 1. CallFrames with state information from the sync frames. * 2. CodeFlowFrames without state information from async frames. * 3. Labels that we use to separate and show the description of the async frames From f0c3a968d3b70c855f9f1342876a0539517ad914 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 18 Jan 2019 17:08:05 +0000 Subject: [PATCH 15/23] Fix import casing --- .../features/cdtpDebugeeRuntimeVersionProvider.ts | 2 +- src/chrome/chromeDebugAdapter.ts | 2 +- src/chrome/dependencyInjection.ts/bind.ts | 8 ++++---- src/chrome/internal/exceptions/pauseOnException.ts | 2 +- src/chrome/internal/sources/features/dotScriptsCommand.ts | 2 +- src/chrome/internal/sources/sourcesTextLogic.ts | 2 +- src/chrome/internal/stackTraces/stackTracesLogic.ts | 2 +- src/chrome/internal/stepping/features/asyncStepping.ts | 2 +- src/chrome/internal/stepping/features/syncStepping.ts | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts b/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts index 164f1d8a7..5ba86e53a 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider.ts @@ -6,7 +6,7 @@ import { Protocol as CDTP } from 'devtools-protocol'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; -import { Version } from '../../utils/Version'; +import { Version } from '../../utils/version'; export interface IDebugeeRuntimeVersionProvider { version(): Promise; diff --git a/src/chrome/chromeDebugAdapter.ts b/src/chrome/chromeDebugAdapter.ts index 9a3615a42..10abdf778 100644 --- a/src/chrome/chromeDebugAdapter.ts +++ b/src/chrome/chromeDebugAdapter.ts @@ -53,7 +53,7 @@ import { TYPES } from './dependencyInjection.ts/types'; import { ICDTDebuggeeExecutionEventsProvider, PausedEvent } from './cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { ILogEntry, CDTPLogEventsProvider } from './cdtpDebuggee/eventsProviders/cdtpLogEventsProvider'; import { IConsoleEventsProvider, IConsoleAPICalledEvent } from './cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider'; -import { IPauseOnExceptionsConfigurer } from './cdtpDebuggee/features/CDTPPauseOnExceptionsConfigurer'; +import { IPauseOnExceptionsConfigurer } from './cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer'; // export class ChromeDebugAdapter extends ChromeDebugAdapterClass { // /** These methods are called by the ChromeDebugAdapter subclass in chrome-debug. We need to redirect them like this diff --git a/src/chrome/dependencyInjection.ts/bind.ts b/src/chrome/dependencyInjection.ts/bind.ts index 07eb32ec7..3bf1b6aaa 100644 --- a/src/chrome/dependencyInjection.ts/bind.ts +++ b/src/chrome/dependencyInjection.ts/bind.ts @@ -36,11 +36,11 @@ import { IDOMInstrumentationBreakpoints, CDTPDOMDebugger } from '../cdtpDebuggee import { CDTPBrowserNavigator } from '../cdtpDebuggee/features/cdtpBrowserNavigator'; import { CDTPLogEventsProvider } from '../cdtpDebuggee/eventsProviders/cdtpLogEventsProvider'; import { CDTPConsoleEventsProvider } from '../cdtpDebuggee/eventsProviders/cdtpConsoleEventsProvider'; -import { IAsyncDebuggingConfigurer, CDTPAsyncDebuggingConfigurer } from '../cdtpDebuggee/features/CDTPAsyncDebuggingConfigurer'; -import { IScriptSourcesRetriever, CDTPScriptSourcesRetriever } from '../cdtpDebuggee/features/CDTPScriptSourcesRetriever'; +import { IAsyncDebuggingConfigurer, CDTPAsyncDebuggingConfigurer } from '../cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer'; +import { IScriptSourcesRetriever, CDTPScriptSourcesRetriever } from '../cdtpDebuggee/features/cdtpScriptSourcesRetriever'; import { CDTPDebugeeExecutionController } from '../cdtpDebuggee/features/cdtpDebugeeExecutionController'; -import { CDTPPauseOnExceptionsConfigurer } from '../cdtpDebuggee/features/CDTPPauseOnExceptionsConfigurer'; -import { CDTPDebugeeSteppingController } from '../cdtpDebuggee/features/CDTPDebugeeSteppingController'; +import { CDTPPauseOnExceptionsConfigurer } from '../cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer'; +import { CDTPDebugeeSteppingController } from '../cdtpDebuggee/features/cdtpDebugeeSteppingController'; import { CDTPDebugeeRuntimeVersionProvider } from '../cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider'; import { CDTPBlackboxPatternsConfigurer } from '../cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer'; import { CDTPDomainsEnabler } from '../cdtpDebuggee/infrastructure/cdtpDomainsEnabler'; diff --git a/src/chrome/internal/exceptions/pauseOnException.ts b/src/chrome/internal/exceptions/pauseOnException.ts index 5b8e63c80..84cd549d6 100644 --- a/src/chrome/internal/exceptions/pauseOnException.ts +++ b/src/chrome/internal/exceptions/pauseOnException.ts @@ -14,7 +14,7 @@ import { TYPES } from '../../dependencyInjection.ts/types'; import { IEventsToClientReporter } from '../../client/eventSender'; import { DeleteMeScriptsRegistry } from '../scripts/scriptsRegistry'; import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; -import { IPauseOnExceptionsConfigurer } from '../../cdtpDebuggee/features/CDTPPauseOnExceptionsConfigurer'; +import { IPauseOnExceptionsConfigurer } from '../../cdtpDebuggee/features/cdtpPauseOnExceptionsConfigurer'; type ExceptionBreakMode = 'never' | 'always' | 'unhandled' | 'userUnhandled'; diff --git a/src/chrome/internal/sources/features/dotScriptsCommand.ts b/src/chrome/internal/sources/features/dotScriptsCommand.ts index 245d222b0..65dff7338 100644 --- a/src/chrome/internal/sources/features/dotScriptsCommand.ts +++ b/src/chrome/internal/sources/features/dotScriptsCommand.ts @@ -9,7 +9,7 @@ import { IEventsToClientReporter } from '../../../client/eventSender'; import { determineOrderingOfStrings } from '../../../collections/utilities'; import { TYPES } from '../../../dependencyInjection.ts/types'; import { IScript } from '../../scripts/script'; -import { IScriptSourcesRetriever } from '../../../cdtpDebuggee/features/CDTPScriptSourcesRetriever'; +import { IScriptSourcesRetriever } from '../../../cdtpDebuggee/features/cdtpScriptSourcesRetriever'; import { CDTPScriptsRegistry } from '../../../cdtpDebuggee/registries/cdtpScriptsRegistry'; @injectable() diff --git a/src/chrome/internal/sources/sourcesTextLogic.ts b/src/chrome/internal/sources/sourcesTextLogic.ts index 0b2873ede..b9e6de765 100644 --- a/src/chrome/internal/sources/sourcesTextLogic.ts +++ b/src/chrome/internal/sources/sourcesTextLogic.ts @@ -8,7 +8,7 @@ import { printIterable } from '../../collections/printting'; import { IComponent } from '../features/feature'; import { injectable, inject } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; -import { IScriptSourcesRetriever } from '../../cdtpDebuggee/features/CDTPScriptSourcesRetriever'; +import { IScriptSourcesRetriever } from '../../cdtpDebuggee/features/cdtpScriptSourcesRetriever'; @injectable() export class SourceTextLogic implements IComponent { diff --git a/src/chrome/internal/stackTraces/stackTracesLogic.ts b/src/chrome/internal/stackTraces/stackTracesLogic.ts index b2fab175d..5e19feb32 100644 --- a/src/chrome/internal/stackTraces/stackTracesLogic.ts +++ b/src/chrome/internal/stackTraces/stackTracesLogic.ts @@ -21,7 +21,7 @@ import { asyncMap } from '../../collections/async'; import { TYPES } from '../../dependencyInjection.ts/types'; import { ConnectedCDAConfiguration } from '../../..'; import { IVote, Abstained } from '../../communication/collaborativeDecision'; -import { IAsyncDebuggingConfigurer } from '../../cdtpDebuggee/features/CDTPAsyncDebuggingConfigurer'; +import { IAsyncDebuggingConfigurer } from '../../cdtpDebuggee/features/cdtpAsyncDebuggingConfigurer'; import { IStackTracePresentationRow, StackTraceLabel, CallFramePresentationHint } from './stackTracePresentationRow'; import { IStackTracePresentation } from './stackTracePresentation'; diff --git a/src/chrome/internal/stepping/features/asyncStepping.ts b/src/chrome/internal/stepping/features/asyncStepping.ts index 51fcfef3e..2ca7be129 100644 --- a/src/chrome/internal/stepping/features/asyncStepping.ts +++ b/src/chrome/internal/stepping/features/asyncStepping.ts @@ -9,7 +9,7 @@ import { injectable, inject } from 'inversify'; import { TYPES } from '../../../dependencyInjection.ts/types'; import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { IDebugeeExecutionController } from '../../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; -import { IDebugeeSteppingController } from '../../../cdtpDebuggee/features/CDTPDebugeeSteppingController'; +import { IDebugeeSteppingController } from '../../../cdtpDebuggee/features/cdtpDebugeeSteppingController'; export interface IEventsConsumedByAsyncStepping { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; diff --git a/src/chrome/internal/stepping/features/syncStepping.ts b/src/chrome/internal/stepping/features/syncStepping.ts index 3cb3bbdde..f3f900e9d 100644 --- a/src/chrome/internal/stepping/features/syncStepping.ts +++ b/src/chrome/internal/stepping/features/syncStepping.ts @@ -10,7 +10,7 @@ import { injectable, inject } from 'inversify'; import { IDebugeeExecutionController } from '../../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; import { TYPES } from '../../../dependencyInjection.ts/types'; import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; -import { IDebugeeSteppingController } from '../../../cdtpDebuggee/features/CDTPDebugeeSteppingController'; +import { IDebugeeSteppingController } from '../../../cdtpDebuggee/features/cdtpDebugeeSteppingController'; type SteppingAction = () => Promise; From 67ab0300d4eb46bff4680c12189393c5219e7f6a Mon Sep 17 00:00:00 2001 From: digeff Date: Fri, 18 Jan 2019 09:37:49 -0800 Subject: [PATCH 16/23] Reorganize BPs files --- src/chrome/breakOnLoadHelper.ts | 2 +- src/chrome/cdtpDebuggee/cdtpPrimitives.ts | 14 +- .../cdtpDebuggeeExecutionEventsProvider.ts | 6 +- .../features/cdtpDebuggeeBreakpoints.ts | 63 ++++---- .../protocolParsers/cdtpLocationParser.ts | 2 +- .../client/chromeDebugAdapter/cdaState.ts | 2 +- .../client/chromeDebugAdapter/connectedCDA.ts | 2 +- .../chromeDebugAdapter/connectedCDAEvents.ts | 2 +- .../chromeDebugAdapter/unconnectedCDA.ts | 4 +- .../unconnectedCDACommonLogic.ts | 2 +- .../chromeDebugAdapter/uninitializedCDA.ts | 4 +- src/chrome/client/clientToInternal.ts | 18 +-- .../delayMessagesUntilInitializedSession.ts | 4 +- .../client/doNotPauseWhileSteppingSession.ts | 4 +- src/chrome/client/handlesRegistry.ts | 3 +- src/chrome/client/internalToClient.ts | 15 +- src/chrome/client/session.ts | 2 +- src/chrome/communication/targetChannels.ts | 6 +- src/chrome/dependencyInjection.ts/bind.ts | 6 +- .../breakpoints/baseMappedBPRecipie.ts | 57 ++++++++ .../internal/breakpoints/bpActionWhenHit.ts | 126 +++++++--------- src/chrome/internal/breakpoints/bpRecipie.ts | 134 +++--------------- .../internal/breakpoints/bpRecipieInSource.ts | 41 ++++++ .../internal/breakpoints/bpRecipieStatus.ts | 28 ++-- src/chrome/internal/breakpoints/bpRecipies.ts | 33 +++-- src/chrome/internal/breakpoints/breakpoint.ts | 48 ++++--- .../bpRecipieAtLoadedSourceLogic.ts | 42 +++--- .../{ => features}/bpsDeltaCalculator.ts | 15 +- .../{ => features}/breakpointsLogic.ts | 44 +++--- .../features/hitCountBreakpoints.ts | 18 +-- .../{ => features}/hitCountConditionParser.ts | 0 .../features/pauseScriptLoadsToSetBPs.ts | 7 +- .../features/reAddBPsWhenSourceIsLoaded.ts | 16 ++- .../targetDuplicatedBPsLogic.ts | 0 .../{ => registries}/breakpointsRegistry.ts | 20 +-- .../clientCurrentBPRecipiesRegistry.ts | 16 +-- src/chrome/internal/locations/location.ts | 46 ++++-- src/chrome/internal/sources/loadedSource.ts | 25 +++- .../internal/sources/resourceIdentifier.ts | 13 +- src/chrome/internal/sources/source.ts | 17 ++- .../internal/sources/unresolvedSource.ts | 6 +- 41 files changed, 472 insertions(+), 441 deletions(-) create mode 100644 src/chrome/internal/breakpoints/baseMappedBPRecipie.ts create mode 100644 src/chrome/internal/breakpoints/bpRecipieInSource.ts rename src/chrome/internal/breakpoints/{ => features}/bpRecipieAtLoadedSourceLogic.ts (79%) rename src/chrome/internal/breakpoints/{ => features}/bpsDeltaCalculator.ts (92%) rename src/chrome/internal/breakpoints/{ => features}/breakpointsLogic.ts (77%) rename src/chrome/internal/breakpoints/{ => features}/hitCountConditionParser.ts (100%) rename src/chrome/internal/breakpoints/{ => features}/targetDuplicatedBPsLogic.ts (100%) rename src/chrome/internal/breakpoints/{ => registries}/breakpointsRegistry.ts (70%) rename src/chrome/internal/breakpoints/{ => registries}/clientCurrentBPRecipiesRegistry.ts (70%) diff --git a/src/chrome/breakOnLoadHelper.ts b/src/chrome/breakOnLoadHelper.ts index bdf73a2f8..ec2907e5e 100644 --- a/src/chrome/breakOnLoadHelper.ts +++ b/src/chrome/breakOnLoadHelper.ts @@ -12,7 +12,7 @@ import * as assert from 'assert'; import { InternalSourceBreakpoint } from './internalSourceBreakpoint'; import { Version, parseResourceIdentifier } from '..'; import { LocationInScript } from './internal/locations/location'; -import { BreakpointsLogic } from './internal/breakpoints/breakpointsLogic'; +import { BreakpointsLogic } from './internal/breakpoints/features/breakpointsLogic'; import { IResourceIdentifier, newResourceIdentifierMap } from './internal/sources/resourceIdentifier'; import { PausedEvent } from './cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { IDOMInstrumentationBreakpoints } from './cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints'; diff --git a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts index b9add62b4..9d7b621ed 100644 --- a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts +++ b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts @@ -5,13 +5,15 @@ import { IScript } from '../internal/scripts/script'; import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; import { URLRegexp } from '../internal/locations/subtypes'; -import { AlwaysBreak, ConditionalBreak } from '../internal/breakpoints/bpActionWhenHit'; -import { IURL } from '../internal/sources/resourceIdentifier'; +import { AlwaysPause, ConditionalPause } from '../internal/breakpoints/bpActionWhenHit'; +import { IResourceIdentifier } from '../internal/sources/resourceIdentifier'; import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; -import { IBreakpoint } from '../internal/breakpoints/breakpoint'; +import { MappableBreakpoint } from '../internal/breakpoints/breakpoint'; export type integer = number; -export type CDTPSupportedResources = IScript | IURL | URLRegexp; -export type CDTPSupportedHitActions = AlwaysBreak | ConditionalBreak; +// The IResourceIdentifier is used with the URL that is associated with each Script in CDTP. This should be a URL, but it could also be a string that is not a valid URL +// For that reason we use IResourceIdentifier for this type, instead of IURL +export type CDTPSupportedResources = IScript | IResourceIdentifier | URLRegexp; +export type CDTPSupportedHitActions = AlwaysPause | ConditionalPause; export type CDTPBPRecipie = IBPRecipie; -export type CDTPBreakpoint = IBreakpoint; +export type CDTPBreakpoint = MappableBreakpoint; diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts index 4877f886c..5c2b455be 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts @@ -6,7 +6,6 @@ import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagno import { asyncMap } from '../../collections/async'; import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; import { adaptToSinglIntoToMulti } from '../../../utils'; -import { AnyBPRecipie } from '../../internal/breakpoints/bpRecipie'; import { CDTPBreakpointIdsRegistry } from '../registries/cdtpBreakpointIdsRegistry'; import { ScriptCallFrame, CodeFlowFrame } from '../../internal/stackTraces/callFrame'; import { asyncUndefinedOnFailure } from '../../utils/failures'; @@ -20,6 +19,7 @@ import { CodeFlowStackTrace } from '../../internal/stackTraces/codeFlowStackTrac import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { CDTPCallFrameRegistry } from '../registries/cdtpCallFrameRegistry'; import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; +import { CDTPBPRecipie } from '../cdtpPrimitives'; export type PauseEventReason = 'XHR' | 'DOM' | 'EventListener' | 'exception' | 'assert' | 'debugCommand' | 'promiseRejection' | 'OOM' | 'other' | 'ambiguous'; @@ -28,7 +28,7 @@ export class PausedEvent { public readonly callFrames: ScriptCallFrame[], public readonly reason: PauseEventReason, public readonly data: any, - public readonly hitBreakpoints: AnyBPRecipie[], + public readonly hitBreakpoints: CDTPBPRecipie[], public readonly asyncStackTrace: CodeFlowStackTrace | undefined, public readonly asyncStackTraceId: CDTP.Runtime.StackTraceId | undefined, public readonly asyncCallStackTraceId: CDTP.Runtime.StackTraceId | undefined) { } @@ -74,7 +74,7 @@ export class CDTDebuggeeExecutionEventsProvider extends CDTPEventsEmitterDiagnos super(domainsEnabler); } - private getBPFromID(hitBreakpoint: CDTP.Debugger.BreakpointId): AnyBPRecipie { + private getBPFromID(hitBreakpoint: CDTP.Debugger.BreakpointId): CDTPBPRecipie { return this._breakpointIdRegistry.getRecipieByBreakpointId(hitBreakpoint); } diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts index 1e1fbf57f..ee1be98be 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts @@ -2,11 +2,9 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp, BPRecipie, IBPRecipie } from '../../internal/breakpoints/bpRecipie'; -import { AlwaysBreak, ConditionalBreak } from '../../internal/breakpoints/bpActionWhenHit'; -import { BreakpointInScript, BreakpointInUrl, BreakpointInUrlRegexp, Breakpoint } from '../../internal/breakpoints/breakpoint'; +import { BPRecipie, IBPRecipie } from '../../internal/breakpoints/bpRecipie'; import { RangeInScript } from '../../internal/locations/rangeInScript'; -import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../../internal/locations/location'; +import { LocationInScript } from '../../internal/locations/location'; import { Protocol as CDTP } from 'devtools-protocol'; import { TYPES } from '../../dependencyInjection.ts/types'; import { inject, injectable } from 'inversify'; @@ -20,24 +18,27 @@ import { Position } from '../../internal/locations/location'; import { singleOne } from '../../collections/utilities'; import { CDTPSupportedResources, CDTPSupportedHitActions, CDTPBreakpoint } from '../cdtpPrimitives'; import { Listeners } from '../../communication/listeners'; +import { IScript } from '../../internal/scripts/script'; +import { IURL, IResourceIdentifier } from '../../internal/sources/resourceIdentifier'; +import { CDTPScriptUrl } from '../../internal/sources/resourceIdentifierSubtypes'; +import { URLRegexp } from '../../internal/locations/subtypes'; +import { MappableBreakpoint, ActualLocation } from '../../internal/breakpoints/breakpoint'; +import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp } from '../../internal/breakpoints/BaseMappedBPRecipie'; +import { ConditionalPause } from '../../internal/breakpoints/bpActionWhenHit'; type SetBPInCDTPCall = (resource: TResource, position: Position, cdtpConditionField: string) => Promise; export type OnBreakpointResolvedListener = (breakpoint: CDTPBreakpoint) => void; export interface IDebuggeeBreakpoints { - setBreakpoint(bpRecipie: BPRecipieInScript): Promise; - setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise; - setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise; + setBreakpoint(bpRecipie: BPRecipieInScript): Promise>; + setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise>[]>; + setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise[]>; getPossibleBreakpoints(rangeInScript: RangeInScript): Promise; removeBreakpoint(bpRecipie: IBPRecipie): Promise; onBreakpointResolvedAsync(listener: OnBreakpointResolvedListener): void; onBreakpointResolvedSyncOrAsync(listener: OnBreakpointResolvedListener): void; } -interface IBreakpointClass { - new(recipie: IBPRecipie, actualLocation: LocationInScript): Breakpoint; -} - @injectable() export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule implements IDebuggeeBreakpoints { protected readonly api = this.protocolApi.Debugger; @@ -48,7 +49,7 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< public readonly onBreakpointResolvedAsync = this.addApiListener('breakpointResolved', async (params: CDTP.Debugger.BreakpointResolvedEvent) => { const bpRecipie = this._breakpointIdRegistry.getRecipieByBreakpointId(params.breakpointId); - const breakpoint = new Breakpoint(bpRecipie, + const breakpoint = new MappableBreakpoint(bpRecipie, await this.toLocationInScript(params.location)); return breakpoint; }); @@ -63,12 +64,12 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< this.onBreakpointResolvedAsync(bp => this.onBreakpointResolvedSyncOrAsyncListeners.call(bp)); } - public onBreakpointResolvedSyncOrAsync(listener: (breakpoint: Breakpoint) => void): void { + public onBreakpointResolvedSyncOrAsync(listener: (breakpoint: MappableBreakpoint) => void): void { this.onBreakpointResolvedSyncOrAsyncListeners.add(listener); } - public async setBreakpoint(bpRecipie: BPRecipieInScript): Promise { - const breakpoints = await this.setBreakpointHelper(BreakpointInScript, bpRecipie, async (_resource, _position, cdtpConditionField) => { + public async setBreakpoint(bpRecipie: BPRecipieInScript): Promise> { + const breakpoints = await this.setBreakpointHelper(bpRecipie, async (_resource, _position, cdtpConditionField) => { const response = await this.api.setBreakpoint({ location: this.toCrdpLocation(bpRecipie.location), condition: cdtpConditionField }); return { breakpointId: response.breakpointId, locations: [response.actualLocation] }; }); @@ -76,27 +77,27 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< return singleOne(breakpoints); } - public async setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise { - return this.setBreakpointHelper(BreakpointInUrl, bpRecipie, (resource, position, cdtpConditionField) => + public async setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise>[]> { + return this.setBreakpointHelper(bpRecipie, (resource, position, cdtpConditionField) => this.api.setBreakpointByUrl({ url: resource.textRepresentation, lineNumber: position.lineNumber, columnNumber: position.columnNumber, condition: cdtpConditionField })); } - public async setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise { - return this.setBreakpointHelper(BreakpointInUrlRegexp, bpRecipie, (resource, position, cdtpConditionField) => + public async setBreakpointByUrlRegexp(bpRecipie: BPRecipieInUrlRegexp): Promise[]> { + return this.setBreakpointHelper(bpRecipie, (resource, position, cdtpConditionField) => this.api.setBreakpointByUrl({ urlRegex: resource, lineNumber: position.lineNumber, columnNumber: position.columnNumber, condition: cdtpConditionField })); } - private async setBreakpointHelper - (classToUse: IBreakpointClass, bpRecipie: IBPRecipie, - setBPInCDTPCall: SetBPInCDTPCall): Promise[]> { + private async setBreakpointHelper | URLRegexp, TBPActionWhenHit extends CDTPSupportedHitActions> + (bpRecipie: IBPRecipie, + setBPInCDTPCall: SetBPInCDTPCall): Promise[]> { const cdtpConditionField = this.getCDTPConditionField(bpRecipie); - const resource = bpRecipie.location.resource; // TODO: Figure out why the is needed and remove it + const resource: TResource = bpRecipie.location.resource; // TODO: Figure out why the is needed and remove it const position = bpRecipie.location.position; const response = await setBPInCDTPCall(resource, position, cdtpConditionField); @@ -107,7 +108,7 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< */ this._breakpointIdRegistry.registerRecipie(response.breakpointId, bpRecipie); - const breakpoints = await Promise.all(response.locations.map(cdtpLocation => this.toBreakpoinInResource(classToUse, bpRecipie, cdtpLocation))); + const breakpoints = await Promise.all(response.locations.map(cdtpLocation => this.toBreakpoinInResource(bpRecipie, cdtpLocation))); breakpoints.forEach(bp => this.onBreakpointResolvedSyncOrAsyncListeners.call(bp)); return breakpoints; } @@ -126,16 +127,14 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< this._breakpointIdRegistry.unregisterRecipie(bpRecipie); } - private getCDTPConditionField(bpRecipie: IBPRecipie): string | undefined { - return bpRecipie.bpActionWhenHit.basedOnTypeDo({ - alwaysBreak: () => undefined, - conditionalBreak: conditionalBreak => conditionalBreak.expressionOfWhenToBreak - }); + private getCDTPConditionField(bpRecipie: IBPRecipie): string | undefined { + return bpRecipie.bpActionWhenHit instanceof ConditionalPause + ? bpRecipie.bpActionWhenHit.expressionOfWhenToPause + : undefined; } - private async toBreakpoinInResource(classToUse: IBreakpointClass, - bpRecipie: IBPRecipie, actualLocation: CDTP.Debugger.Location): Promise> { - const breakpoint = new classToUse(bpRecipie, await this.toLocationInScript(actualLocation)); + private async toBreakpoinInResource(bpRecipie: IBPRecipie, actualLocation: CDTP.Debugger.Location): Promise> { + const breakpoint = new MappableBreakpoint(bpRecipie, >await this.toLocationInScript(actualLocation)); return breakpoint; } diff --git a/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts b/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts index ec845dfa7..ad73137e8 100644 --- a/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts +++ b/src/chrome/cdtpDebuggee/protocolParsers/cdtpLocationParser.ts @@ -2,7 +2,7 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ - import { Position, LocationInScript } from '../../internal/locations/location'; +import { Position, LocationInScript } from '../../internal/locations/location'; import { createColumnNumber, createLineNumber } from '../../internal/locations/subtypes'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { Protocol as CDTP } from 'devtools-protocol'; diff --git a/src/chrome/client/chromeDebugAdapter/cdaState.ts b/src/chrome/client/chromeDebugAdapter/cdaState.ts index 3219c4655..83962e1e4 100644 --- a/src/chrome/client/chromeDebugAdapter/cdaState.ts +++ b/src/chrome/client/chromeDebugAdapter/cdaState.ts @@ -7,7 +7,7 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { PromiseOrNot } from '../../utils/promises'; import { ChromeDebugLogic } from '../../chromeDebugAdapter'; -export abstract class UnconnectedCDACommonLogic implements IDebugAdapterState { +export abstract class BaseUnconnectedCDA implements IDebugAdapterState { public abstract chromeDebugAdapter(): ChromeDebugLogic; public initialize(_args: DebugProtocol.InitializeRequestArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise<{capabilities: DebugProtocol.Capabilities, newState: IDebugAdapterState}> { diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts index 99b080de0..af5e051a7 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts @@ -10,7 +10,7 @@ import { InternalToClient } from '../internalToClient'; import { IGetLoadedSourcesResponseBody, IDebugAdapterState, PromiseOrNot, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IThreadsResponseBody, IEvaluateResponseBody, IExceptionInfoResponseBody, ILaunchRequestArgs, IAttachRequestArgs } from '../../../debugAdapterInterfaces'; import { StackTracesLogic } from '../../internal/stackTraces/stackTracesLogic'; import { SourcesLogic } from '../../internal/sources/sourcesLogic'; -import { BreakpointsLogic } from '../../internal/breakpoints/breakpointsLogic'; +import { BreakpointsLogic } from '../../internal/breakpoints/features/breakpointsLogic'; import { CDTPScriptsRegistry } from '../../cdtpDebuggee/registries/cdtpScriptsRegistry'; import { PauseOnExceptionOrRejection } from '../../internal/exceptions/pauseOnException'; import { Stepping } from '../../internal/stepping/stepping'; diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts b/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts index cf54db318..688f0838f 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDAEvents.ts @@ -4,7 +4,7 @@ import { IEventsConsumedByStackTrace } from '../../internal/stackTraces/stackTracesLogic'; import { IEventsConsumedBySkipFilesLogic } from '../../internal/features/skipFiles'; -import { EventsConsumedByBreakpointsLogic } from '../../internal/breakpoints/breakpointsLogic'; +import { EventsConsumedByBreakpointsLogic } from '../../internal/breakpoints/features/breakpointsLogic'; import { ICommunicator } from '../../communication/communicator'; import { Internal } from '../../communication/internalChannels'; import { Target } from '../../communication/targetChannels'; diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts index ffc0bdd39..0d2137aa2 100644 --- a/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDA.ts @@ -21,7 +21,7 @@ import { DoNotPauseWhileSteppingSession } from '../doNotPauseWhileSteppingSessio import { ConnectedCDAConfiguration } from './cdaConfiguration'; import { ConnectedCDA } from './connectedCDA'; import { ConnectedCDAEventsCreator } from './connectedCDAEvents'; -import { UnconnectedCDACommonLogic } from './unconnectedCDACommonLogic'; +import { BaseUnconnectedCDA } from './unconnectedCDACommonLogic'; import { IDebuggeeLauncher } from '../../debugeeStartup/debugeeLauncher'; import { IDomainsEnabler } from '../../cdtpDebuggee/infrastructure/cdtpDomainsEnabler'; @@ -30,7 +30,7 @@ export enum ScenarioType { Attach } -export class UnconnectedCDA extends UnconnectedCDACommonLogic implements IDebugAdapterState { +export class UnconnectedCDA extends BaseUnconnectedCDA implements IDebugAdapterState { private readonly _session = new DelayMessagesUntilInitializedSession(new DoNotPauseWhileSteppingSession(this._basicSession)); private configuration: ConnectedCDAConfiguration; diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts index 2565b3e6a..184f279d6 100644 --- a/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts @@ -7,7 +7,7 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { ChromeDebugLogic, ILaunchRequestArgs, IAttachRequestArgs, IExceptionInfoResponseBody, IDebugAdapterState } from '../../..'; import { PromiseOrNot } from '../../utils/promises'; -export abstract class UnconnectedCDACommonLogic implements IDebugAdapterState { +export abstract class BaseUnconnectedCDA implements IDebugAdapterState { public abstract chromeDebugAdapter(): ChromeDebugLogic; public initialize(_args: DebugProtocol.InitializeRequestArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise<{capabilities: DebugProtocol.Capabilities, newState: IDebugAdapterState}> { diff --git a/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts b/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts index 2a34225b7..36659a8e1 100644 --- a/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/uninitializedCDA.ts @@ -2,7 +2,7 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { UnconnectedCDACommonLogic } from './unconnectedCDACommonLogic'; +import { BaseUnconnectedCDA } from './unconnectedCDACommonLogic'; import { ChromeConnection } from '../../chromeConnection'; import { IDebugAdapterState, ChromeDebugLogic, ITelemetryPropertyCollector, IInitializeRequestArgs, ChromeDebugSession } from '../../..'; import { DebugProtocol } from 'vscode-debugprotocol'; @@ -11,7 +11,7 @@ import { IExtensibilityPoints } from '../../extensibility/extensibilityPoints'; import * as nls from 'vscode-nls'; let localize = nls.loadMessageBundle(); // Initialize to an unlocalized version until we know which locale to use -export class UninitializedCDA extends UnconnectedCDACommonLogic implements IDebugAdapterState { +export class UninitializedCDA extends BaseUnconnectedCDA implements IDebugAdapterState { public chromeDebugAdapter(): ChromeDebugLogic { throw new Error('Method not implemented.'); } diff --git a/src/chrome/client/clientToInternal.ts b/src/chrome/client/clientToInternal.ts index 5e7e2c532..08408ff8f 100644 --- a/src/chrome/client/clientToInternal.ts +++ b/src/chrome/client/clientToInternal.ts @@ -3,13 +3,13 @@ *--------------------------------------------------------*/ import { ILoadedSource } from '../internal/sources/loadedSource'; -import { BPRecipieInSource } from '../internal/breakpoints/bpRecipie'; +import { BPRecipieInSource } from '../internal/breakpoints/bpRecipieInSource'; import { DebugProtocol } from 'vscode-debugprotocol'; import { SourcesLogic } from '../internal/sources/sourcesLogic'; import { Position, LocationInSource } from '../internal/locations/location'; import { LineColTransformer } from '../../transformers/lineNumberTransformer'; -import { BPRecipiesInUnresolvedSource } from '../internal/breakpoints/bpRecipies'; -import { IBPActionWhenHit, AlwaysBreak, ConditionalBreak } from '../internal/breakpoints/bpActionWhenHit'; +import { BPRecipiesInSource } from '../internal/breakpoints/bpRecipies'; +import { IBPActionWhenHit, AlwaysPause, ConditionalPause } from '../internal/breakpoints/bpActionWhenHit'; import { HandlesRegistry } from './handlesRegistry'; import { createLineNumber, createColumnNumber } from '../internal/locations/subtypes'; import { parseResourceIdentifier } from '../internal/sources/resourceIdentifier'; @@ -60,10 +60,10 @@ export class ClientToInternal { } } - public toBPRecipies(args: DebugProtocol.SetBreakpointsArguments): BPRecipiesInUnresolvedSource { + public toBPRecipies(args: DebugProtocol.SetBreakpointsArguments): BPRecipiesInSource { const source = this.toSource(args.source); const breakpoints = args.breakpoints.map(breakpoint => this.toBPRecipie(source, breakpoint)); - return new BPRecipiesInUnresolvedSource(source, breakpoints); + return new BPRecipiesInSource(source, breakpoints); } public toBPRecipie(source: ISource, clientBreakpoint: DebugProtocol.SourceBreakpoint): BPRecipieInSource { @@ -84,14 +84,14 @@ export class ClientToInternal { howManyDefined += actionWhenHit.hitCondition ? 1 : 0; howManyDefined += actionWhenHit.logMessage ? 1 : 0; if (howManyDefined === 0) { - return new AlwaysBreak(); + return new AlwaysPause(); } else if (howManyDefined === 1) { if (actionWhenHit.condition) { - return new ConditionalBreak(actionWhenHit.condition); + return new ConditionalPause(actionWhenHit.condition); } else if (actionWhenHit.hitCondition) { - return new ConditionalBreak(actionWhenHit.hitCondition); + return new ConditionalPause(actionWhenHit.hitCondition); } else if (actionWhenHit.logMessage) { - return new ConditionalBreak(actionWhenHit.logMessage); + return new ConditionalPause(actionWhenHit.logMessage); } else { throw new Error(`Couldn't parse the desired action when hit for the breakpoint: 'condition' (${actionWhenHit.condition}), 'hitCondition' (${actionWhenHit.hitCondition}) or 'logMessage' (${actionWhenHit.logMessage})`); } diff --git a/src/chrome/client/delayMessagesUntilInitializedSession.ts b/src/chrome/client/delayMessagesUntilInitializedSession.ts index 24f8f1a35..e30bf0879 100644 --- a/src/chrome/client/delayMessagesUntilInitializedSession.ts +++ b/src/chrome/client/delayMessagesUntilInitializedSession.ts @@ -4,9 +4,9 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { InitializedEvent } from 'vscode-debugadapter'; -import { WrappedSessionCommonLogic } from './session'; +import { BaseWrappedSession } from './session'; -export class DelayMessagesUntilInitializedSession extends WrappedSessionCommonLogic { +export class DelayMessagesUntilInitializedSession extends BaseWrappedSession { private _hasSentInitializedMessage = false; private _eventsWaitingInitialization: DebugProtocol.Event[] = []; diff --git a/src/chrome/client/doNotPauseWhileSteppingSession.ts b/src/chrome/client/doNotPauseWhileSteppingSession.ts index 7b0b7aa64..a2e36180f 100644 --- a/src/chrome/client/doNotPauseWhileSteppingSession.ts +++ b/src/chrome/client/doNotPauseWhileSteppingSession.ts @@ -2,7 +2,7 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { WrappedSessionCommonLogic } from './session'; +import { BaseWrappedSession } from './session'; import { DebugProtocol } from 'vscode-debugprotocol'; import { utils } from '../..'; @@ -15,7 +15,7 @@ const steppingRequests = { restartFrame: true, }; -export class DoNotPauseWhileSteppingSession extends WrappedSessionCommonLogic { +export class DoNotPauseWhileSteppingSession extends BaseWrappedSession { private readonly _onFlightSteppingRequests = new Set>(); public async dispatchRequest(request: DebugProtocol.Request): Promise { diff --git a/src/chrome/client/handlesRegistry.ts b/src/chrome/client/handlesRegistry.ts index 62c902d68..5fb7da71e 100644 --- a/src/chrome/client/handlesRegistry.ts +++ b/src/chrome/client/handlesRegistry.ts @@ -7,6 +7,7 @@ import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; import { BidirectionalMap } from '../collections/bidirectionalMap'; import { injectable } from 'inversify'; import { IStackTracePresentationRow } from '../internal/stackTraces/stackTracePresentationRow'; +import { ISource } from '../internal/sources/source'; export class BidirectionalHandles { private readonly _idToObject = new BidirectionalMap(); @@ -39,7 +40,7 @@ const prefixMultiplier = 1000000; export class HandlesRegistry { // TODO DIEGO: V1 reseted the frames on an onPaused event. Figure out if that is the right thing to do // We use different prefixes so it's easier to identify the IDs in the logs... - public readonly breakpoints = new BidirectionalHandles>>(888 * prefixMultiplier); + public readonly breakpoints = new BidirectionalHandles>(888 * prefixMultiplier); public readonly frames = new BidirectionalHandles(123 * prefixMultiplier); public readonly sources = new BidirectionalHandles(555 * prefixMultiplier); diff --git a/src/chrome/client/internalToClient.ts b/src/chrome/client/internalToClient.ts index cae3d57df..12ca73444 100644 --- a/src/chrome/client/internalToClient.ts +++ b/src/chrome/client/internalToClient.ts @@ -9,7 +9,7 @@ import { asyncAdaptToSinglIntoToMulti } from '../../utils'; import { ILoadedSource, ILoadedSourceTreeNode } from '../internal/sources/loadedSource'; import { LocationInLoadedSource } from '../internal/locations/location'; import { RemoveProperty } from '../../typeUtils'; -import { IBPRecipieStatus } from '../internal/breakpoints/bpRecipieStatus'; +import { IBPRecipieStatus, BPRecipieIsBinded } from '../internal/breakpoints/bpRecipieStatus'; import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; import { HandlesRegistry } from './handlesRegistry'; import { IExceptionInformation } from '../internal/exceptions/pauseOnException'; @@ -19,6 +19,8 @@ import { TYPES } from '../dependencyInjection.ts/types'; import { Source } from 'vscode-debugadapter'; import { IStackTracePresentationRow, StackTraceLabel } from '../internal/stackTraces/stackTracePresentationRow'; import { CallFramePresentation } from '../internal/stackTraces/callFramePresentation'; +import { asyncMap } from '../collections/async'; +import { ISource } from '../internal/sources/source'; interface IClientLocationInSource { source: DebugProtocol.Source; @@ -28,10 +30,13 @@ interface IClientLocationInSource { @injectable() export class InternalToClient { - public readonly toStackFrames = asyncAdaptToSinglIntoToMulti(this, this.toStackFrame); public readonly toSourceTrees = asyncAdaptToSinglIntoToMulti(this, this.toSourceTree); public readonly toBPRecipiesStatus = asyncAdaptToSinglIntoToMulti(this, this.toBPRecipieStatus); + public toStackFrames(rows: IStackTracePresentationRow[]): Promise { + return asyncMap(rows, row => this.toStackFrame(row)); + } + public getFrameId(stackFrame: IStackTracePresentationRow): number { return this._handlesRegistry.frames.getIdByObject(stackFrame); } @@ -90,19 +95,19 @@ export class InternalToClient { public async toBPRecipieStatus(bpRecipieStatus: IBPRecipieStatus): Promise { const clientStatus = { - id: this.toBreakpointId(bpRecipieStatus.recipie), + id: this.toBreakpointId(bpRecipieStatus.recipie.unmappedBPRecipie), verified: bpRecipieStatus.isVerified(), message: bpRecipieStatus.statusDescription }; - if (bpRecipieStatus.isBinded()) { + if (bpRecipieStatus instanceof BPRecipieIsBinded) { await this.toLocationInSource(bpRecipieStatus.actualLocationInSource, clientStatus); } return clientStatus; } - public toBreakpointId(recipie: IBPRecipie>): number { + public toBreakpointId(recipie: IBPRecipie): number { return this._handlesRegistry.breakpoints.getIdByObject(recipie); } diff --git a/src/chrome/client/session.ts b/src/chrome/client/session.ts index 3ae68a919..6225d4ff5 100644 --- a/src/chrome/client/session.ts +++ b/src/chrome/client/session.ts @@ -15,7 +15,7 @@ export interface ISession { dispatchRequest(request: DebugProtocol.Request): Promise; } -export abstract class WrappedSessionCommonLogic implements ISession { +export abstract class BaseWrappedSession implements ISession { public dispatchRequest(request: DebugProtocol.Request): Promise { return this._wrappedSession.dispatchRequest(request); } diff --git a/src/chrome/communication/targetChannels.ts b/src/chrome/communication/targetChannels.ts index 2f3dc74f3..e6c31bdcb 100644 --- a/src/chrome/communication/targetChannels.ts +++ b/src/chrome/communication/targetChannels.ts @@ -2,16 +2,16 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { ScriptOrSourceOrURLOrURLRegexp } from '../internal/locations/location'; import { NotificationChannelIdentifier } from './notificationsCommunicator'; -import { Breakpoint } from '../internal/breakpoints/breakpoint'; +import { MappableBreakpoint } from '../internal/breakpoints/breakpoint'; import { registerChannels } from './channel'; import { IScriptParsedEvent } from '../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; import { PausedEvent } from '../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; +import { IScript } from '../internal/scripts/script'; const _debugger = { // Notifications - OnAsyncBreakpointResolved: new NotificationChannelIdentifier>(), + OnAsyncBreakpointResolved: new NotificationChannelIdentifier>(), OnScriptParsed: new NotificationChannelIdentifier(), OnPaused: new NotificationChannelIdentifier(), OnResumed: new NotificationChannelIdentifier(), diff --git a/src/chrome/dependencyInjection.ts/bind.ts b/src/chrome/dependencyInjection.ts/bind.ts index 3bf1b6aaa..40bcbfdd0 100644 --- a/src/chrome/dependencyInjection.ts/bind.ts +++ b/src/chrome/dependencyInjection.ts/bind.ts @@ -11,14 +11,14 @@ import { SourcesLogic } from '../internal/sources/sourcesLogic'; import { CDTPScriptsRegistry } from '../cdtpDebuggee/registries/cdtpScriptsRegistry'; import { ClientToInternal } from '../client/clientToInternal'; import { InternalToClient } from '../client/internalToClient'; -import { BreakpointsLogic } from '../internal/breakpoints/breakpointsLogic'; +import { BreakpointsLogic } from '../internal/breakpoints/features/breakpointsLogic'; import { PauseOnExceptionOrRejection } from '../internal/exceptions/pauseOnException'; import { Stepping } from '../internal/stepping/stepping'; import { DotScriptCommand } from '../internal/sources/features/dotScriptsCommand'; -import { BreakpointsRegistry } from '../internal/breakpoints/breakpointsRegistry'; +import { BreakpointsRegistry } from '../internal/breakpoints/registries/breakpointsRegistry'; import { ReAddBPsWhenSourceIsLoaded } from '../internal/breakpoints/features/reAddBPsWhenSourceIsLoaded'; import { PauseScriptLoadsToSetBPs } from '../internal/breakpoints/features/pauseScriptLoadsToSetBPs'; -import { BPRecipieAtLoadedSourceLogic } from '../internal/breakpoints/bpRecipieAtLoadedSourceLogic'; +import { BPRecipieAtLoadedSourceLogic } from '../internal/breakpoints/features/bpRecipieAtLoadedSourceLogic'; import { DeleteMeScriptsRegistry } from '../internal/scripts/scriptsRegistry'; import { SyncStepping } from '../internal/stepping/features/syncStepping'; import { AsyncStepping } from '../internal/stepping/features/asyncStepping'; diff --git a/src/chrome/internal/breakpoints/baseMappedBPRecipie.ts b/src/chrome/internal/breakpoints/baseMappedBPRecipie.ts new file mode 100644 index 000000000..46434829f --- /dev/null +++ b/src/chrome/internal/breakpoints/baseMappedBPRecipie.ts @@ -0,0 +1,57 @@ +import { Location, ScriptOrSourceOrURLOrURLRegexp, LocationInScript, LocationInUrlRegexp, LocationInUrl } from '../locations/location'; +import { IBPActionWhenHit } from './bpActionWhenHit'; +import { BaseBPRecipie, IBPRecipie } from './bpRecipie'; +import { BPRecipieInSource } from './bpRecipieInSource'; +import { ILoadedSource } from '../sources/loadedSource'; +import { IScript } from '../scripts/script'; +import { CDTPSupportedHitActions } from '../../cdtpDebuggee/cdtpPrimitives'; +import { createURLRegexp, URLRegexp } from '../locations/subtypes'; +import { utils } from '../../..'; +import { IURL } from '../sources/resourceIdentifier'; +import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; + +export abstract class BaseMappedBPRecipie extends BaseBPRecipie { + constructor(public readonly unmappedBPRecipie: BPRecipieInSource, public readonly location: Location) { + super(); + } + + public get bpActionWhenHit(): TBPActionWhenHit { + return this.unmappedBPRecipie.bpActionWhenHit; + } + + public isEquivalentTo(right: IBPRecipie): boolean { + return this.location.isEquivalentTo(right.location) + && right.unmappedBPRecipie.isEquivalentTo(this.unmappedBPRecipie); + } + + public toString(): string { + return `BP @ ${this.location} do: ${this.bpActionWhenHit}`; + } +} + +export class BPRecipieInLoadedSource extends BaseMappedBPRecipie { + public mappedToScript(): BPRecipieInScript { + return new BPRecipieInScript(this.unmappedBPRecipie, this.location.mappedToScript()); + } +} + +export class BPRecipieInScript extends BaseMappedBPRecipie { + private static nextBPGuid = 89000000; + + public withLocationReplaced(newLocation: LocationInScript): BPRecipieInScript { + return new BPRecipieInScript(this.unmappedBPRecipie, newLocation); + } + + public mappedToUrlRegexp(): BPRecipieInUrlRegexp { + const urlRegexp = createURLRegexp(utils.pathToRegex(this.location.script.url, `${BPRecipieInScript.nextBPGuid++}`)); + return new BPRecipieInUrlRegexp(this.unmappedBPRecipie, new LocationInUrlRegexp(urlRegexp, this.location.position)); + } + + public mappedToUrl(): BPRecipieInUrl { + const url = this.location.script.runtimeSource.identifier; + return new BPRecipieInUrl(this.unmappedBPRecipie, new LocationInUrl(url, this.location.position)); + } +} + +export class BPRecipieInUrl extends BaseMappedBPRecipie, CDTPSupportedHitActions> { } +export class BPRecipieInUrlRegexp extends BaseMappedBPRecipie { } \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/bpActionWhenHit.ts b/src/chrome/internal/breakpoints/bpActionWhenHit.ts index 560ee11f6..1f80138f6 100644 --- a/src/chrome/internal/breakpoints/bpActionWhenHit.ts +++ b/src/chrome/internal/breakpoints/bpActionWhenHit.ts @@ -4,106 +4,89 @@ import { IEquivalenceComparable } from '../../utils/equivalence'; +/** + * These classes represents the different actions that a pausepoint can take when hit + * Pausepoint: AlwaysPause + * Conditional Pausepoint: ConditionalPause + * Logpoint: LogMessage + * Hit Count Pausepoint: PauseOnHitCount + */ export interface IBPActionWhenHit extends IEquivalenceComparable { isEquivalentTo(bpActionWhenHit: IBPActionWhenHit): boolean; + accept(visitor: IBPActionWhenHitVisitor): T; +} - basedOnTypeDo(actionBasedOnClass: { - alwaysBreak?: (alwaysBreak: AlwaysBreak) => R, - conditionalBreak?: (conditionalBreak: ConditionalBreak) => R, - logMessage?: (logMessage: LogMessage) => R, - breakOnSpecificHitCounts?: (breakOnSpecificHitCounts: BreakOnHitCount) => R - }): R; - - isBreakOnHitCount(): this is BreakOnHitCount; - isAlwaysBreak(): this is AlwaysBreak; - isConditionalBreak(): this is ConditionalBreak; - isLogMessage(): this is LogMessage; +export interface IBPActionWhenHitVisitor { + alwaysPause(alwaysPause: AlwaysPause): T; + conditionalPause(conditionalPause: ConditionalPause): T; + pauseOnHitCount(pauseOnHitCount: PauseOnHitCount): T; + logMessage(logMessage: LogMessage): T; } -export abstract class BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public abstract isEquivalentTo(bpActionWhenHit: IBPActionWhenHit): boolean; +abstract class BaseBPActionWhenHit { + public abstract accept(visitor: IBPActionWhenHitVisitor): T; - basedOnTypeDo(actionBasedOnClass: { - alwaysBreak?: (alwaysBreak: AlwaysBreak) => R, - conditionalBreak?: (conditionalBreak: ConditionalBreak) => R, - logMessage?: (logMessage: LogMessage) => R, - breakOnSpecificHitCounts?: (breakOnSpecificHitCounts: BreakOnHitCount) => R; - }): R { - if (this.isAlwaysBreak() && actionBasedOnClass.alwaysBreak) { - return actionBasedOnClass.alwaysBreak(this); - } else if (this.isConditionalBreak() && actionBasedOnClass.conditionalBreak) { - return actionBasedOnClass.conditionalBreak(this); - } else if (this.isBreakOnHitCount() && actionBasedOnClass.breakOnSpecificHitCounts) { - return actionBasedOnClass.breakOnSpecificHitCounts(this); - } else if (this.isLogMessage() && actionBasedOnClass.logMessage) { - return actionBasedOnClass.logMessage(this); - } else { - throw new Error(`Unexpected case. The logic wasn't prepared to handle the specified breakpoint action when hit: ${this}`); - } + public isEquivalentTo(bpActionWhenHit: IBPActionWhenHit): boolean { + return bpActionWhenHit.accept(new BPActionWhenHitIsEquivalentVisitor(this)); } +} - public isAlwaysBreak(): this is AlwaysBreak { - return false; +class BPActionWhenHitIsEquivalentVisitor implements IBPActionWhenHitVisitor { + public alwaysPause(alwaysPause: AlwaysPause): boolean { + return this.areSameClass(this._left, alwaysPause); } - public isConditionalBreak(): this is ConditionalBreak { - return false; + public conditionalPause(conditionalPause: ConditionalPause): boolean { + return this.areSameClass(this._left, conditionalPause) + && this._left.expressionOfWhenToPause === conditionalPause.expressionOfWhenToPause; } - - public isBreakOnHitCount(): this is BreakOnHitCount { - return false; + public pauseOnHitCount(pauseOnHitCount: PauseOnHitCount): boolean { + return this.areSameClass(this._left, pauseOnHitCount) + && this._left.pauseOnHitCondition === pauseOnHitCount.pauseOnHitCondition; } - - public isLogMessage(): this is LogMessage { - return false; + public logMessage(logMessage: LogMessage): boolean { + return this.areSameClass(this._left, logMessage) + && this._left.expressionToLog === logMessage.expressionToLog; } -} -export class AlwaysBreak extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public isEquivalentTo(otherBPActionWhenHit: IBPActionWhenHit): boolean { - return otherBPActionWhenHit.isAlwaysBreak(); + private areSameClass(left: IBPActionWhenHit, right: T): left is T { + return left.constructor === right.constructor; } - public isAlwaysBreak(): this is AlwaysBreak { - return true; + constructor(private readonly _left: IBPActionWhenHit) { } +} + +export class AlwaysPause extends BaseBPActionWhenHit { + public accept(visitor: IBPActionWhenHitVisitor): T { + return visitor.alwaysPause(this); } public toString(): string { - return 'always break'; + return 'always pause'; } } -export class ConditionalBreak extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public isEquivalentTo(otherBPActionWhenHit: IBPActionWhenHit): boolean { - return otherBPActionWhenHit.isConditionalBreak() - && otherBPActionWhenHit.expressionOfWhenToBreak === this.expressionOfWhenToBreak; - } - - public isConditionalBreak(): this is ConditionalBreak { - return true; +export class ConditionalPause extends BaseBPActionWhenHit { + public accept(visitor: IBPActionWhenHitVisitor): T { + return visitor.conditionalPause(this); } public toString(): string { - return `break if: ${this.expressionOfWhenToBreak}`; + return `pause if: ${this.expressionOfWhenToPause}`; } - constructor(public readonly expressionOfWhenToBreak: string) { + constructor(public readonly expressionOfWhenToPause: string) { super(); } } -export class BreakOnHitCount extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public isEquivalentTo(otherBPActionWhenHit: IBPActionWhenHit): boolean { - return otherBPActionWhenHit.isBreakOnHitCount() - && otherBPActionWhenHit.pauseOnHitCondition === this.pauseOnHitCondition; - } - - public isBreakOnHitCount(): this is BreakOnHitCount { - return true; +export class PauseOnHitCount extends BaseBPActionWhenHit { + public accept(visitor: IBPActionWhenHitVisitor): T { + return visitor.pauseOnHitCount(this); } public toString(): string { - return `break when hits: ${this.pauseOnHitCondition}`; + return `pause when hits: ${this.pauseOnHitCondition}`; } constructor(public readonly pauseOnHitCondition: string) { @@ -111,14 +94,9 @@ export class BreakOnHitCount extends BasedOnTypeDoCommonLogic implements IBPActi } } -export class LogMessage extends BasedOnTypeDoCommonLogic implements IBPActionWhenHit { - public isEquivalentTo(otherBPActionWhenHit: IBPActionWhenHit): boolean { - return otherBPActionWhenHit.isLogMessage() - && otherBPActionWhenHit.expressionToLog === this.expressionToLog; - } - - public isLogMessage(): this is LogMessage { - return true; +export class LogMessage extends BaseBPActionWhenHit { + public accept(visitor: IBPActionWhenHitVisitor): T { + return visitor.logMessage(this); } public toString(): string { diff --git a/src/chrome/internal/breakpoints/bpRecipie.ts b/src/chrome/internal/breakpoints/bpRecipie.ts index 4a8c4cb2f..5dcf79396 100644 --- a/src/chrome/internal/breakpoints/bpRecipie.ts +++ b/src/chrome/internal/breakpoints/bpRecipie.ts @@ -3,143 +3,43 @@ *--------------------------------------------------------*/ import { ISource } from '../sources/source'; -import { Location, ScriptOrSourceOrURLOrURLRegexp, LocationInUrl, LocationInUrlRegexp, LocationInScript, ILocation } from '../locations/location'; +import { Location, ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; import { ILoadedSource } from '../sources/loadedSource'; import { IScript } from '../scripts/script'; -import { IBPActionWhenHit, AlwaysBreak } from './bpActionWhenHit'; -import { utils } from '../../..'; -import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; -import { IResourceIdentifier, IURL } from '../sources/resourceIdentifier'; -import { URLRegexp, createURLRegexp } from '../locations/subtypes'; +import { IBPActionWhenHit } from './bpActionWhenHit'; +import { IResourceIdentifier } from '../sources/resourceIdentifier'; +import { URLRegexp } from '../locations/subtypes'; import { IEquivalenceComparable } from '../../utils/equivalence'; +import { BPRecipieInLoadedSource, BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp } from './baseMappedBPRecipie'; +import { BPRecipieInSource } from './bpRecipieInSource'; +/** + * IBPRecipie represents the instruction to set a breakpoint with some particular properties. Assuming that IBPRecipie ends up creating an actual + * breakpoint in the debuggee, an instance of Breakpoint will be created to represent that actual breakpoint. + */ export interface IBPRecipie extends IEquivalenceComparable { readonly location: Location; readonly bpActionWhenHit: TBPActionWhenHit; - readonly unmappedBPRecipie: AnyBPRecipie; // Original bpRecipie before any mapping was done + readonly unmappedBPRecipie: BPRecipie; // We store the original bpRecipie before any mapping was done, to make it easier to send updates of the status to the client } -export type AnyBPRecipie = IBPRecipie; - -abstract class BPRecipieCommonLogic { +export abstract class BaseBPRecipie implements IBPRecipie { + public abstract get unmappedBPRecipie(): BPRecipieInSource; public abstract get bpActionWhenHit(): TBPActionWhenHit; - - constructor( - public readonly location: Location) { } + public abstract get location(): Location; + public abstract isEquivalentTo(right: this): boolean; public toString(): string { return `BP @ ${this.location} do: ${this.bpActionWhenHit}`; } } -abstract class UnmappedBPRecipieCommonLogic - extends BPRecipieCommonLogic { - - public get unmappedBPRecipie(): IBPRecipie { - return this; - } - - public isEquivalentTo(right: IBPRecipie): boolean { - // TODO: Figure out how to remove the > casts - return (>this.location).isEquivalentTo(>right.location) - && this.bpActionWhenHit.isEquivalentTo(right.bpActionWhenHit); - } - - constructor( - location: Location, - public readonly bpActionWhenHit: TBPActionWhenHit) { - super(location); - } -} - -abstract class MappedBPRecipieCommonLogic { - public get bpActionWhenHit(): TBPActionWhenHit { - return this.unmappedBPRecipie.bpActionWhenHit; - } - - public isEquivalentTo(right: IBPRecipie): boolean { - return (>this.location).isEquivalentTo(>right.location) - && right.unmappedBPRecipie.isEquivalentTo(this.unmappedBPRecipie); - } - - constructor(public readonly unmappedBPRecipie: IBPRecipie, - public readonly location: Location) { } - - public toString(): string { - return `BP @ ${this.location} do: ${this.bpActionWhenHit}`; - } -} - -export class BPRecipieInSource extends UnmappedBPRecipieCommonLogic implements IBPRecipie { - public withAlwaysBreakAction(): BPRecipieInSource { - return new BPRecipieInSource(this.location, new AlwaysBreak()); - } - - public tryResolvingSource( - succesfulAction: (breakpointInLoadedSource: BPRecipieInLoadedSource) => R, - failedAction: (breakpointInUnbindedSource: BPRecipieInSource) => R): R { - return this.location.tryResolvingSource( - locationInLoadedSource => succesfulAction(new BPRecipieInLoadedSource(this, locationInLoadedSource)), - () => failedAction(this)); - } - - public resolvedToLoadedSource(): BPRecipieInLoadedSource { - return this.tryResolvingSource( - breakpointInLoadedSource => breakpointInLoadedSource, - () => { throw new Error(`Failed to convert ${this} into a breakpoint in a loaded source`); }); - } - - public resolvedWithLoadedSource(source: ILoadedSource): BPRecipieInLoadedSource { - return new BPRecipieInLoadedSource(this, this.location.resolvedWith(source)); - } -} - -export class BPRecipieInLoadedSource - extends MappedBPRecipieCommonLogic implements IBPRecipie { - - public mappedToScript(): BPRecipieInScript { - return new BPRecipieInScript(this.unmappedBPRecipie, this.location.mappedToScript()); - } -} - -export type IBreakpointRecipieInLoadedSource = IBPRecipie; -export type IBreakpointRecipieInUnbindedSource = IBPRecipie; - -// TODO: Are we missing the IBPActionWhenHit parameter here? -export type BPRecipie = +export type BPRecipie = IBPRecipie & ( TResource extends ISource ? BPRecipieInSource : TResource extends ILoadedSource ? BPRecipieInLoadedSource : TResource extends IScript ? BPRecipieInScript : TResource extends IResourceIdentifier ? BPRecipieInUrl : TResource extends URLRegexp ? BPRecipieInUrlRegexp : - never; - -export class BPRecipieInScript - extends MappedBPRecipieCommonLogic implements IBPRecipie { - - public withLocationReplaced(newLocation: LocationInScript): BPRecipieInScript { - return new BPRecipieInScript(this.unmappedBPRecipie, newLocation); - } - - public mappedToUrlRegexp(): BPRecipieInUrlRegexp { - const urlRegexp = createURLRegexp(utils.pathToRegex(this.location.script.url, `${Math.random() * 100000000000000}`)); - return new BPRecipieInUrlRegexp(this.unmappedBPRecipie, - new LocationInUrlRegexp(urlRegexp, this.location.position)); - } - - public mappedToUrl(): BPRecipieInUrl { - const url = this.location.script.runtimeSource.identifier; - return new BPRecipieInUrl(this.unmappedBPRecipie, - new LocationInUrl(url, this.location.position)); - } -} - -export class BPRecipieInUrl - extends MappedBPRecipieCommonLogic, TBPActionWhenHit> implements IBPRecipie, TBPActionWhenHit> { -} - -export class BPRecipieInUrlRegexp - extends MappedBPRecipieCommonLogic implements IBPRecipie { -} + never); diff --git a/src/chrome/internal/breakpoints/bpRecipieInSource.ts b/src/chrome/internal/breakpoints/bpRecipieInSource.ts new file mode 100644 index 000000000..8145c189c --- /dev/null +++ b/src/chrome/internal/breakpoints/bpRecipieInSource.ts @@ -0,0 +1,41 @@ +import { ISource } from '../sources/source'; +import { Location } from '../locations/location'; +import { ILoadedSource } from '../sources/loadedSource'; +import { IBPActionWhenHit, AlwaysPause } from './bpActionWhenHit'; +import { BPRecipieInLoadedSource } from './baseMappedBPRecipie'; +import { BaseBPRecipie, IBPRecipie } from './bpRecipie'; + +export class BPRecipieInSource extends BaseBPRecipie { + constructor(public readonly location: Location, public readonly bpActionWhenHit: TBPActionWhenHit) { + super(); + } + + public isEquivalentTo(right: IBPRecipie): boolean { + return this.location.isEquivalentTo(right.location) && + this.bpActionWhenHit.isEquivalentTo(right.bpActionWhenHit); + } + + public get unmappedBPRecipie(): BPRecipieInSource { + return this; + } + + public withAlwaysBreakAction(): BPRecipieInSource { + return new BPRecipieInSource(this.location, new AlwaysPause()); + } + + public tryResolvingSource(succesfulAction: (breakpointInLoadedSource: BPRecipieInLoadedSource) => R, failedAction: (breakpointInUnbindedSource: BPRecipieInSource) => R): R { + return this.location.tryResolvingSource( + locationInLoadedSource => succesfulAction(new BPRecipieInLoadedSource(this, locationInLoadedSource)), + () => failedAction(this)); + } + + public resolvedToLoadedSource(): BPRecipieInLoadedSource { + return this.tryResolvingSource( + breakpointInLoadedSource => breakpointInLoadedSource, + () => { throw new Error(`Failed to convert ${this} into a breakpoint in a loaded source`); }); + } + + public resolvedWithLoadedSource(source: ILoadedSource): BPRecipieInLoadedSource { + return new BPRecipieInLoadedSource(this, this.location.resolvedWith(source)); + } +} diff --git a/src/chrome/internal/breakpoints/bpRecipieStatus.ts b/src/chrome/internal/breakpoints/bpRecipieStatus.ts index 6a123994a..650560424 100644 --- a/src/chrome/internal/breakpoints/bpRecipieStatus.ts +++ b/src/chrome/internal/breakpoints/bpRecipieStatus.ts @@ -2,28 +2,20 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { IBPRecipie, AnyBPRecipie } from './bpRecipie'; - -import { ILoadedSource } from '../sources/loadedSource'; - -import { ScriptOrSourceOrURLOrURLRegexp, LocationInLoadedSource } from '../locations/location'; - +import { IBPRecipie } from './bpRecipie'; +import { LocationInLoadedSource } from '../locations/location'; import { IBreakpoint } from './breakpoint'; import { printArray } from '../../collections/printting'; +import { ISource } from '../sources/source'; export interface IBPRecipieStatus { + readonly recipie: IBPRecipie; readonly statusDescription: string; - readonly recipie: IBPRecipie; isVerified(): boolean; - isBinded(): this is BPRecipieIsBinded; } export class BPRecipieIsUnbinded implements IBPRecipieStatus { - public isBinded(): this is BPRecipieIsBinded { - return false; - } - public isVerified(): boolean { return false; } @@ -33,19 +25,15 @@ export class BPRecipieIsUnbinded implements IBPRecipieStatus { } constructor( - public readonly recipie: AnyBPRecipie, + public readonly recipie: IBPRecipie, public readonly statusDescription: string) { } } export class BPRecipieIsBinded implements IBPRecipieStatus { - public isBinded(): this is BPRecipieIsBinded { - return true; - } - public get actualLocationInSource(): LocationInLoadedSource { // TODO: Figure out what is the right way to decide the actual location when we have multiple breakpoints - return this.breakpoints[0].actualLocation.mappedToSource(); + return this.breakpoints[0].actualLocation; } public isVerified(): boolean { @@ -57,8 +45,8 @@ export class BPRecipieIsBinded implements IBPRecipieStatus { } constructor( - public readonly recipie: AnyBPRecipie, - public readonly breakpoints: IBreakpoint[], + public readonly recipie: IBPRecipie, + public readonly breakpoints: IBreakpoint[], public readonly statusDescription: string) { if (this.breakpoints.length === 0) { throw new Error(`A breakpoint recipie that is binded needs to have at least one breakpoint that was binded for the recipie yet ${this} had none`); diff --git a/src/chrome/internal/breakpoints/bpRecipies.ts b/src/chrome/internal/breakpoints/bpRecipies.ts index 959c624e1..c00484bae 100644 --- a/src/chrome/internal/breakpoints/bpRecipies.ts +++ b/src/chrome/internal/breakpoints/bpRecipies.ts @@ -8,38 +8,37 @@ import { BPRecipie } from './bpRecipie'; import { printArray } from '../../collections/printting'; import { IResourceIdentifier } from '../sources/resourceIdentifier'; -export class BPRecipiesCommonLogic { - constructor(public readonly resource: TResource, public readonly breakpoints: BPRecipie[]) { +/** + * These classes are used to handle all the set of breakpoints for a single file as a unit, and be able to resolve them all together + */ +export class BaseBPRecipies { + constructor(public readonly source: TResource, public readonly breakpoints: BPRecipie[]) { this.breakpoints.forEach(breakpoint => { - const bpResource = breakpoint.location.resource; - if (!(bpResource).isEquivalentTo(this.resource)) { // TODO: Figure out a way to remove this any - throw new Error(`Expected all the breakpoints to have source ${resource} yet the breakpoint ${breakpoint} had ${bpResource} as it's source`); + const bpResource: TResource = breakpoint.location.resource; + if (!(bpResource).isEquivalentTo(this.source)) { // TODO: Figure out a way to remove this any + throw new Error(`Expected all the breakpoints to have source ${source} yet the breakpoint ${breakpoint} had ${bpResource} as it's source`); } }); } public toString(): string { - return printArray(`Bps @ ${this.resource}`, this.breakpoints); + return printArray(`BPs @ ${this.source}`, this.breakpoints); } } -export class BPRecipiesInLoadedSource extends BPRecipiesCommonLogic { - public get source(): ILoadedSource { - return this.resource; - } -} - -export class BPRecipiesInUnresolvedSource extends BPRecipiesCommonLogic { - public tryGettingBPsInLoadedSource(ifSuccesfulDo: (desiredBPsInLoadedSource: BPRecipiesInLoadedSource) => R, ifFaileDo: () => R): R { - return this.resource.tryResolving( +export class BPRecipiesInSource extends BaseBPRecipies { + public tryResolving(ifSuccesfulDo: (desiredBPsInLoadedSource: BPRecipiesInLoadedSource) => R, ifFaileDo: () => R): R { + return this.source.tryResolving( loadedSource => { - const loadedSourceBPs = this.breakpoints.map(breakpoint => breakpoint.resolvedToLoadedSource()); + const loadedSourceBPs = this.breakpoints.map(breakpoint => breakpoint.resolvedWithLoadedSource(loadedSource)); return ifSuccesfulDo(new BPRecipiesInLoadedSource(loadedSource, loadedSourceBPs)); }, ifFaileDo); } public get requestedSourcePath(): IResourceIdentifier { - return this.resource.sourceIdentifier; + return this.source.sourceIdentifier; } } + +export class BPRecipiesInLoadedSource extends BaseBPRecipies { } \ No newline at end of file diff --git a/src/chrome/internal/breakpoints/breakpoint.ts b/src/chrome/internal/breakpoints/breakpoint.ts index 7a63c0791..cfde21553 100644 --- a/src/chrome/internal/breakpoints/breakpoint.ts +++ b/src/chrome/internal/breakpoints/breakpoint.ts @@ -2,39 +2,41 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; +import { LocationInScript, LocationInLoadedSource } from '../locations/location'; import { IBPRecipie } from './bpRecipie'; -import { ILoadedSource } from '../sources/loadedSource'; import { IScript } from '../scripts/script'; -import { IURL } from '../sources/resourceIdentifier'; -import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; import { URLRegexp } from '../locations/subtypes'; - -// Should we rename this to ActionPoint? Given that it can be a LogPoint too? -export interface IBreakpoint { +import { IResourceIdentifier } from '../sources/resourceIdentifier'; +import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; +import { CDTPSupportedResources } from '../../cdtpDebuggee/cdtpPrimitives'; +import { ISource } from '../sources/source'; + +export type BPPossibleResources = IScript | ISource | URLRegexp | IResourceIdentifier; +export type ActualLocation = + TResource extends IScript ? LocationInScript : + TResource extends URLRegexp ? LocationInScript : + TResource extends IResourceIdentifier ? LocationInScript : + TResource extends ISource ? LocationInLoadedSource : + LocationInScript; + +/// We use the breakpoint class when the debugger actually configures a file to stop (or do something) at a certain place under certain conditions +export interface IBreakpoint { readonly recipie: IBPRecipie; - readonly actualLocation: LocationInScript; + readonly actualLocation: ActualLocation; } -export class Breakpoint implements IBreakpoint{ +export abstract class BaseBreakpoint implements IBreakpoint{ public toString(): string { return `${this.recipie} actual location is ${this.actualLocation}`; } - constructor(public readonly recipie: IBPRecipie, public readonly actualLocation: LocationInScript) { } + constructor(public readonly recipie: IBPRecipie, public readonly actualLocation: ActualLocation) { } } -export class BreakpointInLoadedSource extends Breakpoint { } - -export class BreakpointInScript extends Breakpoint { } - -export class BreakpointInUrl extends Breakpoint> { } - -export class BreakpointInUrlRegexp extends Breakpoint { } +export class MappableBreakpoint extends BaseBreakpoint { + public mappedToSource(): BreakpointInSource { + return new BreakpointInSource(this.recipie.unmappedBPRecipie, this.actualLocation.mappedToSource()); + } +} -// export type Breakpoint = -// TResource extends ILoadedSource ? BreakpointInLoadedSource : -// TResource extends IScript ? BreakpointInScript : -// TResource extends IResourceIdentifier ? BreakpointInUrl : -// TResource extends URLRegexp ? BreakpointInUrlRegexp : -// never; +export class BreakpointInSource extends BaseBreakpoint { } diff --git a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts b/src/chrome/internal/breakpoints/features/bpRecipieAtLoadedSourceLogic.ts similarity index 79% rename from src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts rename to src/chrome/internal/breakpoints/features/bpRecipieAtLoadedSourceLogic.ts index 2c2be2cf4..75e0eabe8 100644 --- a/src/chrome/internal/breakpoints/bpRecipieAtLoadedSourceLogic.ts +++ b/src/chrome/internal/breakpoints/features/bpRecipieAtLoadedSourceLogic.ts @@ -2,26 +2,26 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { BPRecipieInLoadedSource, BPRecipie } from './bpRecipie'; -import { ConditionalBreak, AlwaysBreak } from './bpActionWhenHit'; -import { IBreakpoint } from './breakpoint'; -import { ScriptOrSourceOrURLOrURLRegexp, LocationInScript, Position } from '../locations/location'; -import { ISource } from '../sources/source'; -import { chromeUtils, logger } from '../../..'; -import { createColumnNumber, createLineNumber } from '../locations/subtypes'; -import { RangeInScript } from '../locations/rangeInScript'; -import { BreakpointsRegistry } from './breakpointsRegistry'; -import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; -import { VoteRelevance, IVote, Abstained } from '../../communication/collaborativeDecision'; +import { BPRecipie } from '../bpRecipie'; +import { ConditionalPause, AlwaysPause } from '../bpActionWhenHit'; +import { LocationInScript, Position } from '../../locations/location'; +import { ISource } from '../../sources/source'; +import { chromeUtils, logger } from '../../../..'; +import { createColumnNumber, createLineNumber } from '../../locations/subtypes'; +import { RangeInScript } from '../../locations/rangeInScript'; +import { BreakpointsRegistry } from '../registries/breakpointsRegistry'; +import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; +import { VoteRelevance, IVote, Abstained } from '../../../communication/collaborativeDecision'; import { inject, injectable } from 'inversify'; -import { IDebuggeeBreakpoints } from '../../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; -import { IBreakpointFeaturesSupport } from '../../cdtpDebuggee/features/cdtpBreakpointFeaturesSupport'; -import { TYPES } from '../../dependencyInjection.ts/types'; -import { InformationAboutPausedProvider, NotifyStoppedCommonLogic } from '../features/takeProperActionOnPausedEvent'; -import { IEventsToClientReporter } from '../../client/eventSender'; -import { ReasonType } from '../../stoppedEvent'; -import { CDTPBreakpoint } from '../../cdtpDebuggee/cdtpPrimitives'; -import { CDTPBPRecipiesRegistry } from './registries/bpRecipieRegistry'; +import { IDebuggeeBreakpoints } from '../../../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; +import { IBreakpointFeaturesSupport } from '../../../cdtpDebuggee/features/cdtpBreakpointFeaturesSupport'; +import { TYPES } from '../../../dependencyInjection.ts/types'; +import { InformationAboutPausedProvider, NotifyStoppedCommonLogic } from '../../features/takeProperActionOnPausedEvent'; +import { IEventsToClientReporter } from '../../../client/eventSender'; +import { ReasonType } from '../../../stoppedEvent'; +import { CDTPBreakpoint } from '../../../cdtpDebuggee/cdtpPrimitives'; +import { CDTPBPRecipiesRegistry } from '../registries/bpRecipieRegistry'; +import { BPRecipieInLoadedSource } from '../BaseMappedBPRecipie'; export type Dummy = VoteRelevance; // If we don't do this the .d.ts doesn't include VoteRelevance and the compilation fails. Remove this when the issue disappears... @@ -36,7 +36,7 @@ export class HitBreakpoint extends NotifyStoppedCommonLogic { } export interface IBreakpointsInLoadedSource { - addBreakpointAtLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise[]>; + addBreakpointAtLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise; } export interface IBPRecipieAtLoadedSourceLogicDependencies { @@ -59,7 +59,7 @@ export class BPRecipieAtLoadedSourceLogic implements IBreakpointsInLoadedSource } } - public async addBreakpointAtLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise[]> { + public async addBreakpointAtLoadedSource(bpRecipie: BPRecipieInLoadedSource): Promise { const bpInScriptRecipie = bpRecipie.mappedToScript(); const bestLocation = await this.considerColumnAndSelectBestBPLocation(bpInScriptRecipie.location); const bpRecipieInBestLocation = bpInScriptRecipie.withLocationReplaced(bestLocation); diff --git a/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts b/src/chrome/internal/breakpoints/features/bpsDeltaCalculator.ts similarity index 92% rename from src/chrome/internal/breakpoints/bpsDeltaCalculator.ts rename to src/chrome/internal/breakpoints/features/bpsDeltaCalculator.ts index c42db4dfb..8d90968d7 100644 --- a/src/chrome/internal/breakpoints/bpsDeltaCalculator.ts +++ b/src/chrome/internal/breakpoints/features/bpsDeltaCalculator.ts @@ -2,12 +2,13 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { BPRecipieInSource, BPRecipie } from './bpRecipie'; -import { BPRecipiesInUnresolvedSource } from './bpRecipies'; -import { ISource } from '../sources/source'; -import { ILoadedSource } from '../sources/loadedSource'; -import { IBPActionWhenHit } from './bpActionWhenHit'; -import { SetUsingProjection } from '../../collections/setUsingProjection'; +import { BPRecipie } from '../bpRecipie'; +import { BPRecipieInSource } from '../bpRecipieInSource'; +import { BPRecipiesInSource } from '../bpRecipies'; +import { ISource } from '../../sources/source'; +import { ILoadedSource } from '../../sources/loadedSource'; +import { IBPActionWhenHit } from '../bpActionWhenHit'; +import { SetUsingProjection } from '../../../collections/setUsingProjection'; import assert = require('assert'); function canonicalizeBPLocation(breakpoint: BPRecipieInSource): string { @@ -19,7 +20,7 @@ export class BPRsDeltaCalculator { constructor( public readonly requestedSourceIdentifier: ISource, - private readonly _requestedBPRecipies: BPRecipiesInUnresolvedSource, + private readonly _requestedBPRecipies: BPRecipiesInSource, currentBPRecipies: BPRecipieInSource[]) { this._currentBPRecipies = new SetUsingProjection(canonicalizeBPLocation, currentBPRecipies); } diff --git a/src/chrome/internal/breakpoints/breakpointsLogic.ts b/src/chrome/internal/breakpoints/features/breakpointsLogic.ts similarity index 77% rename from src/chrome/internal/breakpoints/breakpointsLogic.ts rename to src/chrome/internal/breakpoints/features/breakpointsLogic.ts index 5039737cc..4c4214a37 100644 --- a/src/chrome/internal/breakpoints/breakpointsLogic.ts +++ b/src/chrome/internal/breakpoints/features/breakpointsLogic.ts @@ -2,32 +2,30 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { IBPRecipie } from './bpRecipie'; -import { ITelemetryPropertyCollector, IComponent, ConnectedCDAConfiguration } from '../../..'; -import { ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; -import { BPRecipiesInUnresolvedSource, BPRecipiesInLoadedSource } from './bpRecipies'; -import { Breakpoint } from './breakpoint'; -import { ReAddBPsWhenSourceIsLoaded, IEventsConsumedByReAddBPsWhenSourceIsLoaded } from './features/reAddBPsWhenSourceIsLoaded'; -import { asyncMap } from '../../collections/async'; -import { IBPRecipieStatus } from './bpRecipieStatus'; -import { ClientCurrentBPRecipiesRegistry } from './clientCurrentBPRecipiesRegistry'; -import { BreakpointsRegistry } from './breakpointsRegistry'; +import { IBPRecipie } from '../bpRecipie'; +import { ITelemetryPropertyCollector, IComponent, ConnectedCDAConfiguration } from '../../../..'; +import { BPRecipiesInSource, BPRecipiesInLoadedSource } from '../bpRecipies'; +import { ReAddBPsWhenSourceIsLoaded, IEventsConsumedByReAddBPsWhenSourceIsLoaded } from './reAddBPsWhenSourceIsLoaded'; +import { asyncMap } from '../../../collections/async'; +import { IBPRecipieStatus } from '../bpRecipieStatus'; +import { ClientCurrentBPRecipiesRegistry } from '../registries/clientCurrentBPRecipiesRegistry'; +import { BreakpointsRegistry } from '../registries/breakpointsRegistry'; import { BPRecipieAtLoadedSourceLogic } from './bpRecipieAtLoadedSourceLogic'; -import { RemoveProperty } from '../../../typeUtils'; -import { IEventsToClientReporter } from '../../client/eventSender'; -import { PauseScriptLoadsToSetBPs, IPauseScriptLoadsToSetBPsDependencies } from './features/pauseScriptLoadsToSetBPs'; +import { RemoveProperty } from '../../../../typeUtils'; +import { IEventsToClientReporter } from '../../../client/eventSender'; +import { PauseScriptLoadsToSetBPs, IPauseScriptLoadsToSetBPsDependencies } from './pauseScriptLoadsToSetBPs'; import { inject, injectable } from 'inversify'; -import { TYPES } from '../../dependencyInjection.ts/types'; -import { IDebuggeeBreakpoints } from '../../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; +import { TYPES } from '../../../dependencyInjection.ts/types'; +import { IDebuggeeBreakpoints } from '../../../cdtpDebuggee/features/cdtpDebuggeeBreakpoints'; import { BPRsDeltaInRequestedSource } from './bpsDeltaCalculator'; -import { CDTPBreakpoint } from '../../cdtpDebuggee/cdtpPrimitives'; -import { ISource } from '../sources/source'; +import { CDTPBreakpoint } from '../../../cdtpDebuggee/cdtpPrimitives'; +import { ISource } from '../../sources/source'; export interface InternalDependencies extends IEventsConsumedByReAddBPsWhenSourceIsLoaded, IPauseScriptLoadsToSetBPsDependencies { - onAsyncBreakpointResolved(listener: (params: Breakpoint) => void): void; + onAsyncBreakpointResolved(listener: (params: CDTPBreakpoint) => void): void; } export type EventsConsumedByBreakpointsLogic = RemoveProperty { + public async updateBreakpointsForFile(requestedBPs: BPRecipiesInSource, _?: ITelemetryPropertyCollector): Promise { const bpsDelta = this._clientBreakpointsRegistry.updateBPRecipiesAndCalculateDelta(requestedBPs); - const requestedBPsToAdd = new BPRecipiesInUnresolvedSource(bpsDelta.resource, bpsDelta.requestedToAdd); + const requestedBPsToAdd = new BPRecipiesInSource(bpsDelta.resource, bpsDelta.requestedToAdd); bpsDelta.requestedToAdd.forEach(requestedBP => this._breakpointRegistry.registerBPRecipie(requestedBP)); - await requestedBPsToAdd.tryGettingBPsInLoadedSource( + await requestedBPsToAdd.tryResolving( async requestedBPsToAddInLoadedSources => { // Match desired breakpoints to existing breakpoints - if (requestedBPsToAddInLoadedSources.resource.doesScriptHasUrl()) { + if (requestedBPsToAddInLoadedSources.source.doesScriptHasUrl()) { await this.addNewBreakpointsForFile(requestedBPsToAddInLoadedSources); await this.removeDeletedBreakpointsFromFile(bpsDelta); } else { @@ -70,7 +68,7 @@ export class BreakpointsLogic implements IComponent { }, () => { const existingUnbindedBPs = bpsDelta.existingToLeaveAsIs.filter(bp => !this._breakpointRegistry.getStatusOfBPRecipie(bp).isVerified()); - const requestedBPsPendingToAdd = new BPRecipiesInUnresolvedSource(bpsDelta.resource, bpsDelta.requestedToAdd.concat(existingUnbindedBPs)); + const requestedBPsPendingToAdd = new BPRecipiesInSource(bpsDelta.resource, bpsDelta.requestedToAdd.concat(existingUnbindedBPs)); if (this._isBpsWhileLoadingEnable) { this._bpsWhileLoadingLogic.enableIfNeccesary(); } diff --git a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts index b4bdd1369..efab40cc6 100644 --- a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts +++ b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts @@ -3,10 +3,11 @@ *--------------------------------------------------------*/ import { IComponent } from '../../features/feature'; -import { BPRecipieInSource, AnyBPRecipie } from '../bpRecipie'; -import { BreakOnHitCount } from '../bpActionWhenHit'; +import { IBPRecipie } from '../bpRecipie'; +import { BPRecipieInSource } from "../bpRecipieInSource"; +import { PauseOnHitCount } from '../bpActionWhenHit'; import { ValidatedMap } from '../../../collections/validatedMap'; -import { HitCountConditionParser, HitCountConditionFunction } from '../hitCountConditionParser'; +import { HitCountConditionParser, HitCountConditionFunction } from './hitCountConditionParser'; import { NotifyStoppedCommonLogic, InformationAboutPausedProvider } from '../../features/takeProperActionOnPausedEvent'; import { ReasonType } from '../../../stoppedEvent'; import { IVote, Abstained, VoteRelevance } from '../../../communication/collaborativeDecision'; @@ -14,6 +15,7 @@ import { injectable, inject } from 'inversify'; import { IEventsToClientReporter } from '../../../client/eventSender'; import { TYPES } from '../../../dependencyInjection.ts/types'; import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; +import { ScriptOrSourceOrURLOrURLRegexp } from '../../locations/location'; export interface IHitCountBreakpointsDependencies { registerAddBPRecipieHandler(handlerRequirements: (bpRecipie: BPRecipieInSource) => boolean, @@ -36,7 +38,7 @@ class HitCountBPData { } constructor( - public readonly hitBPRecipie: BPRecipieInSource, + public readonly hitBPRecipie: BPRecipieInSource, private readonly _shouldPauseCondition: HitCountConditionFunction) { } } @@ -53,16 +55,16 @@ export class HitAndSatisfiedCountBPCondition extends NotifyStoppedCommonLogic { // TODO DIEGO: Install and use this feature @injectable() export class HitCountBreakpoints implements IComponent { - private readonly underlyingToBPRecipie = new ValidatedMap(); + private readonly underlyingToBPRecipie = new ValidatedMap, HitCountBPData>(); public install(): void { this._dependencies.registerAddBPRecipieHandler( - bpRecipie => bpRecipie.bpActionWhenHit.isBreakOnHitCount(), - bpRecipie => this.addBPRecipie(bpRecipie as BPRecipieInSource)); + bpRecipie => bpRecipie.bpActionWhenHit instanceof PauseOnHitCount, + bpRecipie => this.addBPRecipie(bpRecipie as BPRecipieInSource)); this._dependencies.subscriberForAskForInformationAboutPaused(paused => this.askForInformationAboutPaused(paused)); } - private async addBPRecipie(bpRecipie: BPRecipieInSource): Promise { + private async addBPRecipie(bpRecipie: BPRecipieInSource): Promise { const underlyingBPRecipie = bpRecipie.withAlwaysBreakAction(); const shouldPauseCondition = new HitCountConditionParser(bpRecipie.bpActionWhenHit.pauseOnHitCondition).parse(); this._dependencies.addBPRecipie(underlyingBPRecipie); diff --git a/src/chrome/internal/breakpoints/hitCountConditionParser.ts b/src/chrome/internal/breakpoints/features/hitCountConditionParser.ts similarity index 100% rename from src/chrome/internal/breakpoints/hitCountConditionParser.ts rename to src/chrome/internal/breakpoints/features/hitCountConditionParser.ts diff --git a/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts index b1320571b..cd77547ea 100644 --- a/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts +++ b/src/chrome/internal/breakpoints/features/pauseScriptLoadsToSetBPs.ts @@ -5,7 +5,7 @@ import { asyncMap } from '../../../collections/async'; import { ILoadedSource } from '../../sources/loadedSource'; import { IComponent } from '../../features/feature'; -import { LocationInScript, ScriptOrSourceOrURLOrURLRegexp } from '../../locations/location'; +import { LocationInScript } from '../../locations/location'; import { IBreakpoint } from '../breakpoint'; import { NotifyStoppedCommonLogic, ResumeCommonLogic, InformationAboutPausedProvider } from '../../features/takeProperActionOnPausedEvent'; import { ReasonType } from '../../../stoppedEvent'; @@ -15,17 +15,18 @@ import { TYPES } from '../../../dependencyInjection.ts/types'; import { IEventsToClientReporter } from '../../../client/eventSender'; import { IDebugeeExecutionController } from '../../../cdtpDebuggee/features/cdtpDebugeeExecutionController'; import { ReAddBPsWhenSourceIsLoaded } from './reAddBPsWhenSourceIsLoaded'; -import { BreakpointsRegistry } from '../breakpointsRegistry'; +import { BreakpointsRegistry } from '../registries/breakpointsRegistry'; import { IDOMInstrumentationBreakpoints } from '../../../cdtpDebuggee/features/cdtpDOMInstrumentationBreakpoints'; import { IDebugeeRuntimeVersionProvider } from '../../../cdtpDebuggee/features/cdtpDebugeeRuntimeVersionProvider'; import { PausedEvent } from '../../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; +import { IScript } from '../../scripts/script'; export type Dummy = VoteRelevance; // If we don't do this the .d.ts doesn't include VoteRelevance and the compilation fails. Remove this when the issue disappears... export interface IPauseScriptLoadsToSetBPsDependencies { subscriberForAskForInformationAboutPaused(listener: InformationAboutPausedProvider): void; waitUntilUnbindedBPsAreSet(loadedSource: ILoadedSource): Promise; - tryGettingBreakpointAtLocation(locationInScript: LocationInScript): IBreakpoint[]; + tryGettingBreakpointAtLocation(locationInScript: LocationInScript): IBreakpoint[]; publishGoingToPauseClient(): void; } diff --git a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts index b0083b0ed..da9a5a178 100644 --- a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts +++ b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts @@ -2,7 +2,7 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { BPRecipiesInUnresolvedSource } from '../bpRecipies'; +import { BPRecipiesInSource } from '../bpRecipies'; import { ILoadedSource } from '../../sources/loadedSource'; import { asyncMap } from '../../../collections/async'; import { BPRecipieIsUnbinded, BPRecipieIsBinded } from '../bpRecipieStatus'; @@ -11,7 +11,7 @@ import { IEventsToClientReporter } from '../../../client/eventSender'; import { IPromiseDefer, promiseDefer } from '../../../../utils'; import { IComponent } from '../../features/feature'; import { injectable, inject } from 'inversify'; -import { IBreakpointsInLoadedSource } from '../bpRecipieAtLoadedSourceLogic'; +import { IBreakpointsInLoadedSource } from './bpRecipieAtLoadedSourceLogic'; import { TYPES } from '../../../dependencyInjection.ts/types'; export interface IEventsConsumedByReAddBPsWhenSourceIsLoaded { @@ -21,14 +21,14 @@ export interface IEventsConsumedByReAddBPsWhenSourceIsLoaded { @injectable() export class ReAddBPsWhenSourceIsLoaded implements IComponent { - private readonly _sourcePathToBPRecipies = newResourceIdentifierMap(); + private readonly _sourcePathToBPRecipies = newResourceIdentifierMap(); private readonly _sourcePathToBPsAreSetDefer = newResourceIdentifierMap>(); public install(): void { this._dependencies.onLoadedSourceIsAvailable(source => this.onLoadedSourceIsAvailable(source)); } - public replaceBPsForSourceWith(requestedBPs: BPRecipiesInUnresolvedSource): void { + public replaceBPsForSourceWith(requestedBPs: BPRecipiesInSource): void { this._sourcePathToBPRecipies.set(requestedBPs.requestedSourcePath, requestedBPs); } @@ -56,9 +56,11 @@ export class ReAddBPsWhenSourceIsLoaded implements IComponent { const remainingBPRecipies = new Set(unbindBPRecipies.breakpoints); await asyncMap(unbindBPRecipies.breakpoints, async bpRecipie => { try { - const bpStatus = await this._breakpointsInLoadedSource.addBreakpointAtLoadedSource(bpRecipie.resolvedWithLoadedSource(source)); + const bpRecepieResolved = bpRecipie.resolvedWithLoadedSource(source); + const bpStatus = await this._breakpointsInLoadedSource.addBreakpointAtLoadedSource(bpRecepieResolved); + const mappedBreakpoints = bpStatus.map(breakpoint => breakpoint.mappedToSource()); this._eventsToClientReporter.sendBPStatusChanged({ - bpRecipieStatus: new BPRecipieIsBinded(bpRecipie, bpStatus, 'TODO DIEGO'), + bpRecipieStatus: new BPRecipieIsBinded(bpRecipie.unmappedBPRecipie, mappedBreakpoints, 'TODO DIEGO'), reason: 'changed' }); remainingBPRecipies.delete(bpRecipie); @@ -77,7 +79,7 @@ export class ReAddBPsWhenSourceIsLoaded implements IComponent { if (remainingBPRecipies.size > 0) { // TODO DIEGO: Add telemetry given that we don't expect this to happen // If we still have BPs recipies that we couldn't add, we put them back in - this._sourcePathToBPRecipies.set(source.identifier, new BPRecipiesInUnresolvedSource(unbindBPRecipies.resource, Array.from(remainingBPRecipies))); + this._sourcePathToBPRecipies.set(source.identifier, new BPRecipiesInSource(unbindBPRecipies.source, Array.from(remainingBPRecipies))); } if (this._sourcePathToBPRecipies.size === 0) { diff --git a/src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts b/src/chrome/internal/breakpoints/features/targetDuplicatedBPsLogic.ts similarity index 100% rename from src/chrome/internal/breakpoints/targetDuplicatedBPsLogic.ts rename to src/chrome/internal/breakpoints/features/targetDuplicatedBPsLogic.ts diff --git a/src/chrome/internal/breakpoints/breakpointsRegistry.ts b/src/chrome/internal/breakpoints/registries/breakpointsRegistry.ts similarity index 70% rename from src/chrome/internal/breakpoints/breakpointsRegistry.ts rename to src/chrome/internal/breakpoints/registries/breakpointsRegistry.ts index 61f87a2d9..d6e936991 100644 --- a/src/chrome/internal/breakpoints/breakpointsRegistry.ts +++ b/src/chrome/internal/breakpoints/registries/breakpointsRegistry.ts @@ -2,17 +2,16 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { IBPRecipieStatus, BPRecipieIsBinded, BPRecipieIsUnbinded } from './bpRecipieStatus'; -import { ValidatedMultiMap } from '../../collections/validatedMultiMap'; -import { IBPRecipie } from './bpRecipie'; -import { LocationInScript } from '../locations/location'; +import { IBPRecipieStatus, BPRecipieIsBinded, BPRecipieIsUnbinded } from '../bpRecipieStatus'; +import { ValidatedMultiMap } from '../../../collections/validatedMultiMap'; +import { IBPRecipie } from '../bpRecipie'; +import { LocationInScript } from '../../locations/location'; import { injectable } from 'inversify'; -import { CDTPBreakpoint } from '../../cdtpDebuggee/cdtpPrimitives'; -import { ISource } from '../sources/source'; +import { CDTPBreakpoint } from '../../../cdtpDebuggee/cdtpPrimitives'; +import { ISource } from '../../sources/source'; @injectable() export class BreakpointsRegistry { - // TODO DIEGO: Figure out how to handle if two breakpoint rules set a breakpoint in the same location so it ends up being the same breakpoint id private readonly _unmappedRecipieToBreakpoints = new ValidatedMultiMap, CDTPBreakpoint>(); public registerBPRecipie(bpRecipie: IBPRecipie): void { @@ -24,9 +23,10 @@ export class BreakpointsRegistry { } public getStatusOfBPRecipie(bpRecipie: IBPRecipie): IBPRecipieStatus { - const breakpoints = this._unmappedRecipieToBreakpoints.get(bpRecipie); - if (breakpoints.size > 0) { - return new BPRecipieIsBinded(bpRecipie, Array.from(breakpoints), 'TODO DIEGO'); + const breakpoints = Array.from(this._unmappedRecipieToBreakpoints.get(bpRecipie)); + if (breakpoints.length > 0) { + const mappedBreakpoints = breakpoints.map(breakpoint => breakpoint.mappedToSource()); + return new BPRecipieIsBinded(bpRecipie, mappedBreakpoints, 'TODO DIEGO'); } else { return new BPRecipieIsUnbinded(bpRecipie, 'TODO DIEGO'); } diff --git a/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts b/src/chrome/internal/breakpoints/registries/clientCurrentBPRecipiesRegistry.ts similarity index 70% rename from src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts rename to src/chrome/internal/breakpoints/registries/clientCurrentBPRecipiesRegistry.ts index 2077667f4..8e4962820 100644 --- a/src/chrome/internal/breakpoints/clientCurrentBPRecipiesRegistry.ts +++ b/src/chrome/internal/breakpoints/registries/clientCurrentBPRecipiesRegistry.ts @@ -2,18 +2,18 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { BPRecipiesInUnresolvedSource } from './bpRecipies'; +import { BPRecipiesInSource } from '../bpRecipies'; -import { BPRsDeltaCalculator, BPRsDeltaInRequestedSource } from './bpsDeltaCalculator'; -import { BPRecipieInSource } from './bpRecipie'; -import { newResourceIdentifierMap, IResourceIdentifier } from '../sources/resourceIdentifier'; +import { BPRsDeltaCalculator, BPRsDeltaInRequestedSource } from '../features/bpsDeltaCalculator'; +import { BPRecipieInSource } from '../bpRecipieInSource'; +import { newResourceIdentifierMap, IResourceIdentifier } from '../../sources/resourceIdentifier'; export class ClientCurrentBPRecipiesRegistry { private readonly _requestedSourcePathToCurrentBPRecipies = newResourceIdentifierMap(); - public updateBPRecipiesAndCalculateDelta(requestedBPRecipies: BPRecipiesInUnresolvedSource): BPRsDeltaInRequestedSource { + public updateBPRecipiesAndCalculateDelta(requestedBPRecipies: BPRecipiesInSource): BPRsDeltaInRequestedSource { const bpsDelta = this.calculateBPSDeltaFromExistingBPs(requestedBPRecipies); - this.registerCurrentBPRecipies(requestedBPRecipies.resource.sourceIdentifier, bpsDelta.matchesForRequested); + this.registerCurrentBPRecipies(requestedBPRecipies.source.sourceIdentifier, bpsDelta.matchesForRequested); return bpsDelta; } @@ -21,9 +21,9 @@ export class ClientCurrentBPRecipiesRegistry { this._requestedSourcePathToCurrentBPRecipies.setAndReplaceIfExist(requestedSourceIdentifier, Array.from(bpRecipies)); } - private calculateBPSDeltaFromExistingBPs(requestedBPRecipies: BPRecipiesInUnresolvedSource): BPRsDeltaInRequestedSource { + private calculateBPSDeltaFromExistingBPs(requestedBPRecipies: BPRecipiesInSource): BPRsDeltaInRequestedSource { const bpRecipiesInSource = this._requestedSourcePathToCurrentBPRecipies.getOrAdd(requestedBPRecipies.requestedSourcePath, () => []); - return new BPRsDeltaCalculator(requestedBPRecipies.resource, requestedBPRecipies, bpRecipiesInSource).calculate(); + return new BPRsDeltaCalculator(requestedBPRecipies.source, requestedBPRecipies, bpRecipiesInSource).calculate(); } public toString(): string { diff --git a/src/chrome/internal/locations/location.ts b/src/chrome/internal/locations/location.ts index 9445e08cc..e9b084e18 100644 --- a/src/chrome/internal/locations/location.ts +++ b/src/chrome/internal/locations/location.ts @@ -3,13 +3,13 @@ *--------------------------------------------------------*/ import * as Validation from '../../../validation'; -import { IScript } from '../scripts/script'; -import { ISource } from '../sources/source'; -import { ILoadedSource } from '../sources/loadedSource'; +import { IScript, Script } from '../scripts/script'; +import { ISource, isSource } from '../sources/source'; +import { ILoadedSource, isLoadedSource } from '../sources/loadedSource'; import { logger } from 'vscode-debugadapter'; -import { ColumnNumber, LineNumber, URLRegexp } from './subtypes'; +import { ColumnNumber, LineNumber, URLRegexp, createURLRegexp } from './subtypes'; import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; -import { IResourceIdentifier, parseResourceIdentifier, IURL } from '../sources/resourceIdentifier'; +import { IResourceIdentifier, parseResourceIdentifier, IURL, isResourceIdentifier } from '../sources/resourceIdentifier'; import { IEquivalenceComparable } from '../../utils/equivalence'; export type integer = number; @@ -41,15 +41,33 @@ export interface ILocation extends IEq readonly resource: T; } -export type ScriptOrSourceOrURLOrURLRegexp = IScript | ILoadedSource | ISource | URLRegexp | IURL; +// The LocationInUrl is used with the URL that is associated with each Script in CDTP. This should be a URL, but it could also be a string that is not a valid URL +// For that reason we use IResourceIdentifier for this type, instead of IURL +export type ScriptOrSourceOrURLOrURLRegexp = ISource | ILoadedSource | IScript | URLRegexp | IResourceIdentifier; export type Location = - T extends ISource ? LocationInSource : // Used when receiving locations from the client - T extends ILoadedSource ? LocationInLoadedSource : // Used to translate between locations on the client and the debugee - T extends IScript ? LocationInScript : // Used when receiving locations from the debugee - T extends URLRegexp ? LocationInUrlRegexp : // Used when setting a breakpoint by URL in a local file path in windows, to make it case insensitive - T extends IURL ? LocationInUrl : // Used when setting a breakpoint by URL for case-insensitive URLs - ILocation; // TODO: Figure out how to replace this by never (We run into some issues with the isEquivalentTo call if we do) + ILocation & (T extends ISource ? LocationInSource : // Used when receiving locations from the client + T extends ILoadedSource ? LocationInLoadedSource : // Used to translate between locations on the client and the debugee + T extends IScript ? LocationInScript : // Used when receiving locations from the debugee + T extends URLRegexp ? LocationInUrlRegexp : // Used when setting a breakpoint by URL in a local file path in windows, to make it case insensitive + T extends IResourceIdentifier ? LocationInUrl : // Used when setting a breakpoint by URL for case-insensitive URLs + ILocation); // TODO: Figure out how to replace this by never (We run into some issues with the isEquivalentTo call if we do) + +export function createLocation(resource: T, position: Position): Location { + if (isSource(resource)) { + return >new LocationInSource(resource, position); // TODO: Figure out way to remove this cast + } else if (isLoadedSource(resource)) { + return >new LocationInLoadedSource(resource, position); // TODO: Figure out way to remove this cast + } else if (resource instanceof Script) { + return >new LocationInScript(resource, position); // TODO: Figure out way to remove this cast + } else if (typeof resource === 'string') { + return >new LocationInUrlRegexp(createURLRegexp(resource), position); // TODO: Figure out way to remove this cast + } else if (isResourceIdentifier(resource)) { + return >new LocationInUrl(>resource, position); // TODO: Figure out way to remove this cast + } else { + throw Error(`Can't create a location because the type of resource ${resource} wasn't recognized`); + } +} abstract class LocationCommonLogic implements ILocation { public isEquivalentTo(right: this): boolean { @@ -151,8 +169,10 @@ export class LocationInLoadedSource extends LocationCommonLogic { } } +// The LocationInUrl is used with the URL that is associated with each Script in CDTP. This should be a URL, but it could also be a string that is not a valid URL +// For that reason we use IResourceIdentifier for this type, instead of IURL export class LocationInUrl extends LocationCommonLogic> { - public get url(): IURL { + public get url(): IResourceIdentifier { return this.resource; } } diff --git a/src/chrome/internal/sources/loadedSource.ts b/src/chrome/internal/sources/loadedSource.ts index 95271b715..b4b13e240 100644 --- a/src/chrome/internal/sources/loadedSource.ts +++ b/src/chrome/internal/sources/loadedSource.ts @@ -12,12 +12,21 @@ import { IEquivalenceComparable } from '../../utils/equivalence'; * This interface represents a source or text that is related to a script that the debugee is executing. The text can be the contents of the script itself, * or a file from which the script was loaded, or a file that was compiled to generate the contents of the script */ +const ImplementsLoadedSource = Symbol(); export interface ILoadedSource extends IEquivalenceComparable { + [ImplementsLoadedSource]: void; + readonly script: IScript; readonly identifier: IResourceIdentifier; readonly origin: string; doesScriptHasUrl(): boolean; // TODO DIEGO: Figure out if we can delete this property isMappedSource(): boolean; + + isEquivalentTo(right: ILoadedSource): boolean; +} + +export function isLoadedSource(object: object): object is ILoadedSource { + return object.hasOwnProperty(ImplementsLoadedSource); } /** @@ -29,7 +38,9 @@ export interface ILoadedSource extends IEquivalenceComparable * 2. Two: We assume one path is from the webserver, and the other path is in the workspace: RuntimeScriptWithSourceOnWorkspace */ -abstract class LoadedSourceWithURLCommonLogic implements ILoadedSource { +abstract class BaseLoadedSourceWithURL implements ILoadedSource { + [ImplementsLoadedSource]: void; + public isMappedSource(): boolean { return false; } @@ -52,12 +63,14 @@ abstract class LoadedSourceWithURLCommonLogic implements ILoad public readonly origin: string) { } } -export class ScriptRunFromLocalStorage extends LoadedSourceWithURLCommonLogic implements ILoadedSource { } -export class DynamicScript extends LoadedSourceWithURLCommonLogic implements ILoadedSource { } -export class ScriptRuntimeSource extends LoadedSourceWithURLCommonLogic implements ILoadedSource { } -export class ScriptDevelopmentSource extends LoadedSourceWithURLCommonLogic implements ILoadedSource { } +export class ScriptRunFromLocalStorage extends BaseLoadedSourceWithURL implements ILoadedSource { } +export class DynamicScript extends BaseLoadedSourceWithURL implements ILoadedSource { } +export class ScriptRuntimeSource extends BaseLoadedSourceWithURL implements ILoadedSource { } +export class ScriptDevelopmentSource extends BaseLoadedSourceWithURL implements ILoadedSource { } export class NoURLScriptSource implements ILoadedSource { + [ImplementsLoadedSource]: void; + public get identifier(): IResourceIdentifier { return parseResourceIdentifier(`${NoURLScriptSource.EVAL_PSEUDO_PREFIX}${this.name.textRepresentation}` as any); } @@ -90,7 +103,7 @@ export class NoURLScriptSource implements ILoadedSource { } // This represents a path to a development source that was compiled to generate the runtime code of the script -export class MappedSource extends LoadedSourceWithURLCommonLogic implements ILoadedSource { +export class MappedSource extends BaseLoadedSourceWithURL implements ILoadedSource { public isMappedSource(): boolean { return true; } diff --git a/src/chrome/internal/sources/resourceIdentifier.ts b/src/chrome/internal/sources/resourceIdentifier.ts index 21ddaf375..0672594cc 100644 --- a/src/chrome/internal/sources/resourceIdentifier.ts +++ b/src/chrome/internal/sources/resourceIdentifier.ts @@ -3,10 +3,10 @@ *--------------------------------------------------------*/ import * as path from 'path'; -import { utils } from '../../..'; import { IValidatedMap } from '../../collections/validatedMap'; import { MapUsingProjection } from '../../collections/mapUsingProjection'; import { IEquivalenceComparable } from '../../utils/equivalence'; +import * as utils from '../../../utils'; /** * Hierarchy: @@ -23,14 +23,23 @@ import { IEquivalenceComparable } from '../../utils/equivalence'; */ /** This interface represents a text to identify a particular resource. This class will properly compare urls and file paths, while preserving the original case that was used for the identifier */ +const ImplementsResourceIdentifier = Symbol(); export interface IResourceIdentifier extends IEquivalenceComparable { + [ImplementsResourceIdentifier]: void; + readonly textRepresentation: TString; readonly canonicalized: string; isEquivalentTo(right: IResourceIdentifier): boolean; isLocalFilePath(): boolean; } +export function isResourceIdentifier(object: object): object is IResourceIdentifier { + return object.hasOwnProperty(ImplementsResourceIdentifier); +} + abstract class IsEquivalentCommonLogic { + [ImplementsResourceIdentifier]: void; + public abstract get canonicalized(): string; public isEquivalentTo(right: IResourceIdentifier): boolean { @@ -102,6 +111,8 @@ export class LocalFileURL extends IsEquivalentC // Any URL that is not a 'file:///' url export class NonLocalFileURL extends IsEquivalentAndConstructorCommonLogic implements IURL { + [ImplementsResourceIdentifier]: void; + public toString(): string { return path.basename(this.textRepresentation); } diff --git a/src/chrome/internal/sources/source.ts b/src/chrome/internal/sources/source.ts index cdfbb9ca8..5f7e4c89c 100644 --- a/src/chrome/internal/sources/source.ts +++ b/src/chrome/internal/sources/source.ts @@ -11,12 +11,23 @@ import { IEquivalenceComparable } from '../../utils/equivalence'; * VS Code debug protocol sends breakpoint requests with a path?: string; or sourceReference?: number; Before we can use the path, we need to wait for the related script to be loaded so we can match it with a script id. * This set of classes will let us represent the information we get from either a path or a sourceReference, and then let us try to resolve it to a script id when possible. */ +const ImplementsSource = Symbol(); export interface ISource extends IEquivalenceComparable { + [ImplementsSource]: void; + readonly sourceIdentifier: IResourceIdentifier; tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, failedAction: (sourceIdentifier: IResourceIdentifier) => R): R; + + isEquivalentTo(right: ISource): boolean; } -abstract class SourceCommonLogic implements ISource { +export function isSource(object: object): object is ISource { + return object.hasOwnProperty(ImplementsSource); +} + +abstract class BaseSource implements ISource { + [ImplementsSource]: void; + public abstract tryResolving(succesfulAction: (loadedSource: ILoadedSource) => R, failedAction: (identifier: IResourceIdentifier) => R): R; public abstract get sourceIdentifier(): IResourceIdentifier; @@ -26,7 +37,7 @@ abstract class SourceCommonLogic implements ISource { } // Find the related source by using the source's path -export class SourceToBeResolvedViaPath extends SourceCommonLogic implements ISource { +export class SourceToBeResolvedViaPath extends BaseSource implements ISource { public tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, failedAction: (sourceIdentifier: IResourceIdentifier) => R) { return this._sourceResolver.tryResolving(this.sourceIdentifier, succesfulAction, failedAction); } @@ -41,7 +52,7 @@ export class SourceToBeResolvedViaPath extends SourceCommonLogic implements ISou } // This source was already loaded, so we store it in this class -export class SourceAlreadyResolvedToLoadedSource extends SourceCommonLogic implements ISource { +export class SourceAlreadyResolvedToLoadedSource extends BaseSource implements ISource { public tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, _failedAction: (sourceIdentifier: IResourceIdentifier) => R) { return succesfulAction(this.loadedSource); } diff --git a/src/chrome/internal/sources/unresolvedSource.ts b/src/chrome/internal/sources/unresolvedSource.ts index 8d90e3b42..c6fc6af54 100644 --- a/src/chrome/internal/sources/unresolvedSource.ts +++ b/src/chrome/internal/sources/unresolvedSource.ts @@ -13,7 +13,7 @@ export interface IUnresolvedSource extends IEquivalenceComparable { tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, failedAction: (sourceIdentifier: IResourceIdentifier) => R): R; } -abstract class UnresolvedSourceCommonLogic implements IUnresolvedSource { +abstract class BaseUnresolvedSource implements IUnresolvedSource { public abstract tryResolving(succesfulAction: (loadedSource: ILoadedSource) => R, failedAction: (identifier: IResourceIdentifier) => R): R; public abstract get sourceIdentifier(): IResourceIdentifier; @@ -23,7 +23,7 @@ abstract class UnresolvedSourceCommonLogic implements IUnresolvedSource { } // Find the source to resolve to by using the path -export class SourceToBeResolvedViaPath extends UnresolvedSourceCommonLogic implements IUnresolvedSource { +export class SourceToBeResolvedViaPath extends BaseUnresolvedSource implements IUnresolvedSource { public tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, failedAction: (sourceIdentifier: IResourceIdentifier) => R) { return this._sourceResolver.tryResolving(this.sourceIdentifier, succesfulAction, failedAction); } @@ -37,7 +37,7 @@ export class SourceToBeResolvedViaPath extends UnresolvedSourceCommonLogic imple } } -export class SourceAlreadyResolvedToLoadedSource extends UnresolvedSourceCommonLogic implements IUnresolvedSource { +export class SourceAlreadyResolvedToLoadedSource extends BaseUnresolvedSource implements IUnresolvedSource { public tryResolving(succesfulAction: (resolvedSource: ILoadedSource) => R, _failedAction: (sourceIdentifier: IResourceIdentifier) => R) { return succesfulAction(this.loadedSource); } From 9ed85456f09bb646a48e0e87800df73252a33e9e Mon Sep 17 00:00:00 2001 From: D Date: Tue, 22 Jan 2019 14:41:08 -0800 Subject: [PATCH 17/23] Clean up breakpoint model --- src/chrome/cdtpDebuggee/cdtpPrimitives.ts | 4 +- .../features/cdtpDebuggeeBreakpoints.ts | 6 +- .../client/chromeDebugAdapter/cdaState.ts | 115 ------------------ src/chrome/client/internalToClient.ts | 2 +- .../breakpoints/baseMappedBPRecipie.ts | 25 +++- .../internal/breakpoints/bpActionWhenHit.ts | 8 +- src/chrome/internal/breakpoints/bpRecipie.ts | 26 ++-- .../internal/breakpoints/bpRecipieInSource.ts | 18 +-- .../internal/breakpoints/bpRecipieStatus.ts | 1 + src/chrome/internal/breakpoints/bpRecipies.ts | 2 +- src/chrome/internal/breakpoints/breakpoint.ts | 23 +++- .../features/hitCountBreakpoints.ts | 2 +- .../features/reAddBPsWhenSourceIsLoaded.ts | 2 +- 13 files changed, 76 insertions(+), 158 deletions(-) delete mode 100644 src/chrome/client/chromeDebugAdapter/cdaState.ts diff --git a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts index 9d7b621ed..a3078b2b8 100644 --- a/src/chrome/cdtpDebuggee/cdtpPrimitives.ts +++ b/src/chrome/cdtpDebuggee/cdtpPrimitives.ts @@ -7,13 +7,13 @@ import { CDTPScriptUrl } from '../internal/sources/resourceIdentifierSubtypes'; import { URLRegexp } from '../internal/locations/subtypes'; import { AlwaysPause, ConditionalPause } from '../internal/breakpoints/bpActionWhenHit'; import { IResourceIdentifier } from '../internal/sources/resourceIdentifier'; -import { IBPRecipie } from '../internal/breakpoints/bpRecipie'; import { MappableBreakpoint } from '../internal/breakpoints/breakpoint'; +import { IMappedBPRecipie } from '../internal/breakpoints/baseMappedBPRecipie'; export type integer = number; // The IResourceIdentifier is used with the URL that is associated with each Script in CDTP. This should be a URL, but it could also be a string that is not a valid URL // For that reason we use IResourceIdentifier for this type, instead of IURL export type CDTPSupportedResources = IScript | IResourceIdentifier | URLRegexp; export type CDTPSupportedHitActions = AlwaysPause | ConditionalPause; -export type CDTPBPRecipie = IBPRecipie; +export type CDTPBPRecipie = IMappedBPRecipie; export type CDTPBreakpoint = MappableBreakpoint; diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts index ee1be98be..2aad9f00f 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts @@ -23,7 +23,7 @@ import { IURL, IResourceIdentifier } from '../../internal/sources/resourceIdenti import { CDTPScriptUrl } from '../../internal/sources/resourceIdentifierSubtypes'; import { URLRegexp } from '../../internal/locations/subtypes'; import { MappableBreakpoint, ActualLocation } from '../../internal/breakpoints/breakpoint'; -import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp } from '../../internal/breakpoints/BaseMappedBPRecipie'; +import { BPRecipieInScript, BPRecipieInUrl, BPRecipieInUrlRegexp, IMappedBPRecipie } from '../../internal/breakpoints/BaseMappedBPRecipie'; import { ConditionalPause } from '../../internal/breakpoints/bpActionWhenHit'; type SetBPInCDTPCall = (resource: TResource, position: Position, cdtpConditionField: string) => Promise; @@ -94,7 +94,7 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< } private async setBreakpointHelper | URLRegexp, TBPActionWhenHit extends CDTPSupportedHitActions> - (bpRecipie: IBPRecipie, + (bpRecipie: IMappedBPRecipie, setBPInCDTPCall: SetBPInCDTPCall): Promise[]> { const cdtpConditionField = this.getCDTPConditionField(bpRecipie); const resource: TResource = bpRecipie.location.resource; // TODO: Figure out why the is needed and remove it @@ -133,7 +133,7 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< : undefined; } - private async toBreakpoinInResource(bpRecipie: IBPRecipie, actualLocation: CDTP.Debugger.Location): Promise> { + private async toBreakpoinInResource(bpRecipie: IMappedBPRecipie, actualLocation: CDTP.Debugger.Location): Promise> { const breakpoint = new MappableBreakpoint(bpRecipie, >await this.toLocationInScript(actualLocation)); return breakpoint; } diff --git a/src/chrome/client/chromeDebugAdapter/cdaState.ts b/src/chrome/client/chromeDebugAdapter/cdaState.ts deleted file mode 100644 index 83962e1e4..000000000 --- a/src/chrome/client/chromeDebugAdapter/cdaState.ts +++ /dev/null @@ -1,115 +0,0 @@ -/*--------------------------------------------------------- - * Copyright (C) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------*/ - - import { ITelemetryPropertyCollector, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IEvaluateResponseBody, IGetLoadedSourcesResponseBody, IDebugAdapterState, ILaunchRequestArgs, IAttachRequestArgs, IExceptionInfoResponseBody } from '../../../debugAdapterInterfaces'; -import { DebugProtocol } from 'vscode-debugprotocol'; -import { PromiseOrNot } from '../../utils/promises'; -import { ChromeDebugLogic } from '../../chromeDebugAdapter'; - -export abstract class BaseUnconnectedCDA implements IDebugAdapterState { - public abstract chromeDebugAdapter(): ChromeDebugLogic; - - public initialize(_args: DebugProtocol.InitializeRequestArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise<{capabilities: DebugProtocol.Capabilities, newState: IDebugAdapterState}> { - return this.throwNotConnectedError(); - } - - public launch(_args: ILaunchRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { - return this.throwNotConnectedError(); - } - - public attach(_args: IAttachRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { - return this.throwNotConnectedError(); - } - - public restartFrame(_args: DebugProtocol.RestartFrameRequest): Promise { - return this.throwNotConnectedError(); - } - - public exceptionInfo(_args: DebugProtocol.ExceptionInfoArguments): Promise { - return this.throwNotConnectedError(); - } - - public shutdown(): void { - return this.throwNotConnectedError(); - } - - public disconnect(_args: DebugProtocol.DisconnectArguments): Promise { - return this.throwNotConnectedError(); - } - - public setBreakpoints(_args: DebugProtocol.SetBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - public setExceptionBreakpoints(_args: DebugProtocol.SetExceptionBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - public configurationDone(): Promise { - return this.throwNotConnectedError(); - } - - public continue(): Promise { - - return this.throwNotConnectedError(); - } - - public next(): Promise { - - return this.throwNotConnectedError(); - } - - public stepIn(): Promise { - - return this.throwNotConnectedError(); - } - - public stepOut(): Promise { - return this.throwNotConnectedError(); - } - - public pause(): Promise { - return this.throwNotConnectedError(); - } - - public stackTrace(_args: DebugProtocol.StackTraceArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - public scopes(_args: DebugProtocol.ScopesArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - public variables(_args: DebugProtocol.VariablesArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - public source(_args: DebugProtocol.SourceArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - public threads(): Promise<{ threads: DebugProtocol.Thread[]; }> { - return this.throwNotConnectedError(); - } - - public evaluate(_args: DebugProtocol.EvaluateArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - public loadedSources(_args: DebugProtocol.LoadedSourcesArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - public setFunctionBreakpoints(_args: DebugProtocol.SetFunctionBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - public setVariable(_args: DebugProtocol.SetVariableArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): Promise { - return this.throwNotConnectedError(); - } - - private throwNotConnectedError(): never { - throw new Error("Can't execute this request when the debug adapter is not connected to the target"); - } -} \ No newline at end of file diff --git a/src/chrome/client/internalToClient.ts b/src/chrome/client/internalToClient.ts index 12ca73444..8e82171fa 100644 --- a/src/chrome/client/internalToClient.ts +++ b/src/chrome/client/internalToClient.ts @@ -95,7 +95,7 @@ export class InternalToClient { public async toBPRecipieStatus(bpRecipieStatus: IBPRecipieStatus): Promise { const clientStatus = { - id: this.toBreakpointId(bpRecipieStatus.recipie.unmappedBPRecipie), + id: this.toBreakpointId(bpRecipieStatus.recipie), verified: bpRecipieStatus.isVerified(), message: bpRecipieStatus.statusDescription }; diff --git a/src/chrome/internal/breakpoints/baseMappedBPRecipie.ts b/src/chrome/internal/breakpoints/baseMappedBPRecipie.ts index 46434829f..eb5fdc198 100644 --- a/src/chrome/internal/breakpoints/baseMappedBPRecipie.ts +++ b/src/chrome/internal/breakpoints/baseMappedBPRecipie.ts @@ -10,7 +10,18 @@ import { utils } from '../../..'; import { IURL } from '../sources/resourceIdentifier'; import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; -export abstract class BaseMappedBPRecipie extends BaseBPRecipie { +export interface IMappedBPRecipie + extends IBPRecipie { + unmappedBPRecipie: BPRecipieInSource; +} + +/** + * This is the base class for classes representing BP Recipies that were mapped in some way (The unmapped BP recipie is the exact + * recipie specified by the client using the ISource interface) + */ +abstract class BaseMappedBPRecipie + extends BaseBPRecipie { + constructor(public readonly unmappedBPRecipie: BPRecipieInSource, public readonly location: Location) { super(); } @@ -21,6 +32,7 @@ export abstract class BaseMappedBPRecipie): boolean { return this.location.isEquivalentTo(right.location) + && (right instanceof BaseMappedBPRecipie) && right.unmappedBPRecipie.isEquivalentTo(this.unmappedBPRecipie); } @@ -29,7 +41,7 @@ export abstract class BaseMappedBPRecipie extends BaseMappedBPRecipie { +export class BPRecipieInLoadedSource extends BaseMappedBPRecipie { public mappedToScript(): BPRecipieInScript { return new BPRecipieInScript(this.unmappedBPRecipie, this.location.mappedToScript()); } @@ -38,10 +50,17 @@ export class BPRecipieInLoadedSource { private static nextBPGuid = 89000000; + /** + * We use CDTP.getPossibleBreakpoints to find the best position to set a breakpoint. We use withLocationReplaced to get a new + * BPRecipieInScript instance that is located on the place suggested by CDTP.getPossibleBreakpoints + */ public withLocationReplaced(newLocation: LocationInScript): BPRecipieInScript { return new BPRecipieInScript(this.unmappedBPRecipie, newLocation); } + /** + * We use mappedToUrlRegexp to transform this BP Recipie into a similar recipie specified in an URL Regexp instead. + */ public mappedToUrlRegexp(): BPRecipieInUrlRegexp { const urlRegexp = createURLRegexp(utils.pathToRegex(this.location.script.url, `${BPRecipieInScript.nextBPGuid++}`)); return new BPRecipieInUrlRegexp(this.unmappedBPRecipie, new LocationInUrlRegexp(urlRegexp, this.location.position)); @@ -54,4 +73,4 @@ export class BPRecipieInScript extends BaseMappedBPRecipie, CDTPSupportedHitActions> { } -export class BPRecipieInUrlRegexp extends BaseMappedBPRecipie { } \ No newline at end of file +export class BPRecipieInUrlRegexp extends BaseMappedBPRecipie { } diff --git a/src/chrome/internal/breakpoints/bpActionWhenHit.ts b/src/chrome/internal/breakpoints/bpActionWhenHit.ts index 1f80138f6..908f5e55a 100644 --- a/src/chrome/internal/breakpoints/bpActionWhenHit.ts +++ b/src/chrome/internal/breakpoints/bpActionWhenHit.ts @@ -5,11 +5,11 @@ import { IEquivalenceComparable } from '../../utils/equivalence'; /** - * These classes represents the different actions that a pausepoint can take when hit - * Pausepoint: AlwaysPause - * Conditional Pausepoint: ConditionalPause + * These classes represents the different actions that a breakpoint can take when hit + * Breakpoint: AlwaysPause + * Conditional Breakpoint: ConditionalPause * Logpoint: LogMessage - * Hit Count Pausepoint: PauseOnHitCount + * Hit Count Breakpoint: PauseOnHitCount */ export interface IBPActionWhenHit extends IEquivalenceComparable { isEquivalentTo(bpActionWhenHit: IBPActionWhenHit): boolean; diff --git a/src/chrome/internal/breakpoints/bpRecipie.ts b/src/chrome/internal/breakpoints/bpRecipie.ts index 5dcf79396..87f0f2f86 100644 --- a/src/chrome/internal/breakpoints/bpRecipie.ts +++ b/src/chrome/internal/breakpoints/bpRecipie.ts @@ -6,7 +6,7 @@ import { ISource } from '../sources/source'; import { Location, ScriptOrSourceOrURLOrURLRegexp } from '../locations/location'; import { ILoadedSource } from '../sources/loadedSource'; import { IScript } from '../scripts/script'; -import { IBPActionWhenHit } from './bpActionWhenHit'; +import { IBPActionWhenHit, AlwaysPause, ConditionalPause } from './bpActionWhenHit'; import { IResourceIdentifier } from '../sources/resourceIdentifier'; import { URLRegexp } from '../locations/subtypes'; import { IEquivalenceComparable } from '../../utils/equivalence'; @@ -14,19 +14,16 @@ import { BPRecipieInLoadedSource, BPRecipieInScript, BPRecipieInUrl, BPRecipieIn import { BPRecipieInSource } from './bpRecipieInSource'; /** - * IBPRecipie represents the instruction to set a breakpoint with some particular properties. Assuming that IBPRecipie ends up creating an actual + * IBPRecipie represents the instruction/recipie to set a breakpoint with some particular properties. Assuming that IBPRecipie ends up creating an actual * breakpoint in the debuggee, an instance of Breakpoint will be created to represent that actual breakpoint. */ export interface IBPRecipie extends IEquivalenceComparable { readonly location: Location; readonly bpActionWhenHit: TBPActionWhenHit; - - readonly unmappedBPRecipie: BPRecipie; // We store the original bpRecipie before any mapping was done, to make it easier to send updates of the status to the client } -export abstract class BaseBPRecipie implements IBPRecipie { - public abstract get unmappedBPRecipie(): BPRecipieInSource; +export abstract class BaseBPRecipie implements IBPRecipie { public abstract get bpActionWhenHit(): TBPActionWhenHit; public abstract get location(): Location; public abstract isEquivalentTo(right: this): boolean; @@ -36,10 +33,13 @@ export abstract class BaseBPRecipie = IBPRecipie & ( - TResource extends ISource ? BPRecipieInSource : - TResource extends ILoadedSource ? BPRecipieInLoadedSource : - TResource extends IScript ? BPRecipieInScript : - TResource extends IResourceIdentifier ? BPRecipieInUrl : - TResource extends URLRegexp ? BPRecipieInUrlRegexp : - never); +export type BPRecipie + = IBPRecipie & ( + TResource extends ISource ? BPRecipieInSource : + TResource extends ILoadedSource ? BPRecipieInLoadedSource : + TBPActionWhenHit extends (AlwaysPause | ConditionalPause) ? (TResource extends IScript ? BPRecipieInScript : + TResource extends IResourceIdentifier ? BPRecipieInUrl : + TResource extends URLRegexp ? BPRecipieInUrlRegexp : + never) + : never + ); diff --git a/src/chrome/internal/breakpoints/bpRecipieInSource.ts b/src/chrome/internal/breakpoints/bpRecipieInSource.ts index 8145c189c..7f00086b4 100644 --- a/src/chrome/internal/breakpoints/bpRecipieInSource.ts +++ b/src/chrome/internal/breakpoints/bpRecipieInSource.ts @@ -15,27 +15,29 @@ export class BPRecipieInSource { - return this; - } - + /** + * Hit breakpoints are implemented by setting an always break breakpoint, and then auto-resuming until the hit condition is true. + * We use this method to create the always break breakpoint for a hit count breakpoint + */ public withAlwaysBreakAction(): BPRecipieInSource { return new BPRecipieInSource(this.location, new AlwaysPause()); } - public tryResolvingSource(succesfulAction: (breakpointInLoadedSource: BPRecipieInLoadedSource) => R, failedAction: (breakpointInUnbindedSource: BPRecipieInSource) => R): R { + public tryResolvingSource(succesfulAction: (breakpointInLoadedSource: BPRecipieInLoadedSource) => R, + failedAction: (breakpointInUnbindedSource: BPRecipieInSource) => R): R { + return this.location.tryResolvingSource( - locationInLoadedSource => succesfulAction(new BPRecipieInLoadedSource(this, locationInLoadedSource)), + locationInLoadedSource => succesfulAction(new BPRecipieInLoadedSource(this, locationInLoadedSource)), () => failedAction(this)); } - public resolvedToLoadedSource(): BPRecipieInLoadedSource { + public resolvedToLoadedSource(): BPRecipieInLoadedSource { return this.tryResolvingSource( breakpointInLoadedSource => breakpointInLoadedSource, () => { throw new Error(`Failed to convert ${this} into a breakpoint in a loaded source`); }); } - public resolvedWithLoadedSource(source: ILoadedSource): BPRecipieInLoadedSource { + public resolvedWithLoadedSource(source: ILoadedSource): BPRecipieInLoadedSource { return new BPRecipieInLoadedSource(this, this.location.resolvedWith(source)); } } diff --git a/src/chrome/internal/breakpoints/bpRecipieStatus.ts b/src/chrome/internal/breakpoints/bpRecipieStatus.ts index 650560424..9031d9e52 100644 --- a/src/chrome/internal/breakpoints/bpRecipieStatus.ts +++ b/src/chrome/internal/breakpoints/bpRecipieStatus.ts @@ -8,6 +8,7 @@ import { IBreakpoint } from './breakpoint'; import { printArray } from '../../collections/printting'; import { ISource } from '../sources/source'; +/** These interface and classes represent the status of a BP Recipie (Is it binded or not?) */ export interface IBPRecipieStatus { readonly recipie: IBPRecipie; readonly statusDescription: string; diff --git a/src/chrome/internal/breakpoints/bpRecipies.ts b/src/chrome/internal/breakpoints/bpRecipies.ts index c00484bae..a639944e8 100644 --- a/src/chrome/internal/breakpoints/bpRecipies.ts +++ b/src/chrome/internal/breakpoints/bpRecipies.ts @@ -27,7 +27,7 @@ export class BaseBPRecipies { } export class BPRecipiesInSource extends BaseBPRecipies { - public tryResolving(ifSuccesfulDo: (desiredBPsInLoadedSource: BPRecipiesInLoadedSource) => R, ifFaileDo: () => R): R { + public tryResolving(ifSuccesfulDo: (bpsInLoadedSource: BPRecipiesInLoadedSource) => R, ifFaileDo: () => R): R { return this.source.tryResolving( loadedSource => { const loadedSourceBPs = this.breakpoints.map(breakpoint => breakpoint.resolvedWithLoadedSource(loadedSource)); diff --git a/src/chrome/internal/breakpoints/breakpoint.ts b/src/chrome/internal/breakpoints/breakpoint.ts index cfde21553..03ed753e0 100644 --- a/src/chrome/internal/breakpoints/breakpoint.ts +++ b/src/chrome/internal/breakpoints/breakpoint.ts @@ -3,13 +3,15 @@ *--------------------------------------------------------*/ import { LocationInScript, LocationInLoadedSource } from '../locations/location'; -import { IBPRecipie } from './bpRecipie'; import { IScript } from '../scripts/script'; import { URLRegexp } from '../locations/subtypes'; import { IResourceIdentifier } from '../sources/resourceIdentifier'; import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; -import { CDTPSupportedResources } from '../../cdtpDebuggee/cdtpPrimitives'; +import { CDTPSupportedResources, CDTPSupportedHitActions } from '../../cdtpDebuggee/cdtpPrimitives'; import { ISource } from '../sources/source'; +import { IMappedBPRecipie } from './baseMappedBPRecipie'; +import { BPRecipieInSource } from './bpRecipieInSource'; +import { IBPRecipie } from './bpRecipie'; export type BPPossibleResources = IScript | ISource | URLRegexp | IResourceIdentifier; export type ActualLocation = @@ -25,18 +27,27 @@ export interface IBreakpoint { readonly actualLocation: ActualLocation; } -export abstract class BaseBreakpoint implements IBreakpoint{ +abstract class BaseBreakpoint implements IBreakpoint { + public abstract get recipie(): IBPRecipie; + public abstract get actualLocation(): ActualLocation; + public toString(): string { return `${this.recipie} actual location is ${this.actualLocation}`; } - - constructor(public readonly recipie: IBPRecipie, public readonly actualLocation: ActualLocation) { } } export class MappableBreakpoint extends BaseBreakpoint { public mappedToSource(): BreakpointInSource { return new BreakpointInSource(this.recipie.unmappedBPRecipie, this.actualLocation.mappedToSource()); } + + constructor(public readonly recipie: IMappedBPRecipie, public readonly actualLocation: ActualLocation) { + super(); + } } -export class BreakpointInSource extends BaseBreakpoint { } +export class BreakpointInSource extends BaseBreakpoint { + constructor(public readonly recipie: BPRecipieInSource, public readonly actualLocation: ActualLocation) { + super(); + } +} diff --git a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts index efab40cc6..493ef8b63 100644 --- a/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts +++ b/src/chrome/internal/breakpoints/features/hitCountBreakpoints.ts @@ -4,7 +4,7 @@ import { IComponent } from '../../features/feature'; import { IBPRecipie } from '../bpRecipie'; -import { BPRecipieInSource } from "../bpRecipieInSource"; +import { BPRecipieInSource } from '../bpRecipieInSource'; import { PauseOnHitCount } from '../bpActionWhenHit'; import { ValidatedMap } from '../../../collections/validatedMap'; import { HitCountConditionParser, HitCountConditionFunction } from './hitCountConditionParser'; diff --git a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts index da9a5a178..7e18e8e5d 100644 --- a/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts +++ b/src/chrome/internal/breakpoints/features/reAddBPsWhenSourceIsLoaded.ts @@ -60,7 +60,7 @@ export class ReAddBPsWhenSourceIsLoaded implements IComponent { const bpStatus = await this._breakpointsInLoadedSource.addBreakpointAtLoadedSource(bpRecepieResolved); const mappedBreakpoints = bpStatus.map(breakpoint => breakpoint.mappedToSource()); this._eventsToClientReporter.sendBPStatusChanged({ - bpRecipieStatus: new BPRecipieIsBinded(bpRecipie.unmappedBPRecipie, mappedBreakpoints, 'TODO DIEGO'), + bpRecipieStatus: new BPRecipieIsBinded(bpRecipie, mappedBreakpoints, 'TODO DIEGO'), reason: 'changed' }); remainingBPRecipies.delete(bpRecipie); From fd98a89ef42edd47c2846a7081d287a715302e3f Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 21 Jan 2019 19:05:04 +0000 Subject: [PATCH 18/23] Fix skipFiles/toggle skip files --- .../client/chromeDebugAdapter/chromeDebugAdapterV2.ts | 6 +++++- src/chrome/client/chromeDebugAdapter/connectedCDA.ts | 6 +++++- .../client/chromeDebugAdapter/unconnectedCDACommonLogic.ts | 6 +++++- src/chrome/client/requests.ts | 2 +- src/chrome/internal/features/skipFiles.ts | 2 +- src/debugAdapterInterfaces.d.ts | 2 ++ 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts b/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts index 7f0230538..990f5afb4 100644 --- a/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts +++ b/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts @@ -5,7 +5,7 @@ import { IDebugAdapter, ITelemetryPropertyCollector, PromiseOrNot, ILaunchRequestArgs, IAttachRequestArgs, IThreadsResponseBody, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, - IEvaluateResponseBody, IExceptionInfoResponseBody, IGetLoadedSourcesResponseBody, IDebugAdapterState + IEvaluateResponseBody, IExceptionInfoResponseBody, IGetLoadedSourcesResponseBody, IDebugAdapterState, IToggleSkipFileStatusArgs } from '../../..'; import { DebugProtocol } from 'vscode-debugprotocol'; import { ChromeDebugSession, IChromeDebugSessionOpts } from '../../chromeDebugSession'; @@ -127,4 +127,8 @@ export class ChromeDebugAdapter implements IDebugAdapter { public async exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): Promise { return this._state.exceptionInfo(args); } + + public async toggleSkipFileStatus(args: IToggleSkipFileStatusArgs): Promise { + this._state.toggleSkipFileStatus(args); + } } \ No newline at end of file diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts index af5e051a7..d1e1d0cb5 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts @@ -26,7 +26,7 @@ import { Target } from '../../communication/targetChannels'; import { IDebuggeeRunner } from '../../debugeeStartup/debugeeLauncher'; import { StepProgressEventsEmitter } from '../../../executionTimingsReporter'; import { TelemetryPropertyCollector, ITelemetryPropertyCollector } from '../../../telemetry'; -import { ICommunicator, utils } from '../../..'; +import { ICommunicator, utils, IToggleSkipFileStatusArgs } from '../../..'; import { CallFramePresentation } from '../../internal/stackTraces/callFramePresentation'; // TODO DIEGO: Remember to call here and only here this._lineColTransformer.convertDebuggerLocationToClient(stackFrame); for all responses @@ -205,6 +205,10 @@ export class ConnectedCDA implements IDebugAdapterState { return this._internalToVsCode.toExceptionInfo(await this._pauseOnException.latestExceptionInfo()); } + public async toggleSkipFileStatus(args: IToggleSkipFileStatusArgs): Promise { + this._skipFilesLogic.toggleSkipFileStatus(args); + } + public launch(_args: ILaunchRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): never { throw new Error("Can't launch to a new target while connected to a previous target"); } diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts index 184f279d6..36554a711 100644 --- a/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts @@ -4,7 +4,7 @@ import { ITelemetryPropertyCollector, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody, IVariablesResponseBody, ISourceResponseBody, IEvaluateResponseBody, IGetLoadedSourcesResponseBody } from '../../../debugAdapterInterfaces'; import { DebugProtocol } from 'vscode-debugprotocol'; -import { ChromeDebugLogic, ILaunchRequestArgs, IAttachRequestArgs, IExceptionInfoResponseBody, IDebugAdapterState } from '../../..'; +import { ChromeDebugLogic, ILaunchRequestArgs, IAttachRequestArgs, IExceptionInfoResponseBody, IDebugAdapterState, IToggleSkipFileStatusArgs } from '../../..'; import { PromiseOrNot } from '../../utils/promises'; export abstract class BaseUnconnectedCDA implements IDebugAdapterState { @@ -112,4 +112,8 @@ export abstract class BaseUnconnectedCDA implements IDebugAdapterState { private throwNotConnectedError(): never { throw new Error("Can't execute this request when the debug adapter is not connected to the target"); } + + public async toggleSkipFileStatus(_args: IToggleSkipFileStatusArgs): Promise { + return this.throwNotConnectedError(); + } } \ No newline at end of file diff --git a/src/chrome/client/requests.ts b/src/chrome/client/requests.ts index e76bb0fa6..e8c00ba62 100644 --- a/src/chrome/client/requests.ts +++ b/src/chrome/client/requests.ts @@ -2,5 +2,5 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -export const AvailableCommands = new Set(['runInTerminal', 'initialize', 'configurationDone', 'launch', 'attach', 'restart', 'disconnect', 'terminate', 'setBreakpoints', 'setFunctionBreakpoints', 'setExceptionBreakpoints', 'continue', 'next', 'stepIn', 'stepOut', 'stepBack', 'reverseContinue', 'restartFrame', 'goto', 'pause', 'stackTrace', 'scopes', 'variables', 'setVariable', 'source', 'threads', 'terminateThreads', 'modules', 'loadedSources', 'evaluate', 'setExpression', 'stepInTargets', 'gotoTargets', 'completions', 'exceptionInfo']); +export const AvailableCommands = new Set(['runInTerminal', 'initialize', 'configurationDone', 'launch', 'attach', 'restart', 'disconnect', 'terminate', 'setBreakpoints', 'setFunctionBreakpoints', 'setExceptionBreakpoints', 'continue', 'next', 'stepIn', 'stepOut', 'stepBack', 'reverseContinue', 'restartFrame', 'goto', 'pause', 'stackTrace', 'scopes', 'variables', 'setVariable', 'source', 'threads', 'terminateThreads', 'modules', 'loadedSources', 'evaluate', 'setExpression', 'stepInTargets', 'gotoTargets', 'completions', 'exceptionInfo', 'toggleSkipFileStatus']); export type CommandText = 'runInTerminal' | 'initialize' | 'configurationDone' | 'launch' | 'attach' | 'restart' | 'disconnect' | 'terminate' | 'setBreakpoints' | 'setFunctionBreakpoints' | 'setExceptionBreakpoints' | 'continue' | 'next' | 'stepIn' | 'stepOut' | 'stepBack' | 'reverseContinue' | 'restartFrame' | 'goto' | 'pause' | 'stackTrace' | 'scopes' | 'variables' | 'setVariable' | 'source' | 'threads' | 'terminateThreads' | 'modules' | 'loadedSources' | 'evaluate' | 'setExpression' | 'stepInTargets' | 'gotoTargets' | 'completions' | 'exceptionInfo'; diff --git a/src/chrome/internal/features/skipFiles.ts b/src/chrome/internal/features/skipFiles.ts index c373cdbfa..c57f28460 100644 --- a/src/chrome/internal/features/skipFiles.ts +++ b/src/chrome/internal/features/skipFiles.ts @@ -196,7 +196,7 @@ export class SkipFilesLogic implements IComponent, ISta this._skipFileStatuses.set(s, isSkippedFile); if ((isSkippedFile && !inLibRange) || (!isSkippedFile && inLibRange)) { - const details = await this.sourceMapTransformer.allSourcePathDetails(mappedUrl.canonicalized); + const details = await this.sourceMapTransformer.allSourcePathDetails(script.url); const detail = details.find(d => parseResourceIdentifier(d.inferredPath).isEquivalentTo(s)); libPositions.push({ lineNumber: detail.startPosition.line, diff --git a/src/debugAdapterInterfaces.d.ts b/src/debugAdapterInterfaces.d.ts index 3550e9246..744e2a9e2 100644 --- a/src/debugAdapterInterfaces.d.ts +++ b/src/debugAdapterInterfaces.d.ts @@ -193,6 +193,8 @@ export interface IConnectedDebugAdapter { setFunctionBreakpoints(args: DebugProtocol.SetFunctionBreakpointsArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; setVariable(args: DebugProtocol.SetVariableArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; + + toggleSkipFileStatus(args: IToggleSkipFileStatusArgs): Promise; } export type IDebugAdapter = IConnectedDebugAdapter & IUnconnectedDebugAdapter & IUninitializedDebugAdapter; From 77ea3e0215f9230ab9b29e323ff8346569d91ba3 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sat, 26 Jan 2019 22:36:03 +0000 Subject: [PATCH 19/23] Use sourcesMapper for skipFiles --- .../cdtpBlackboxPatternsConfigurer.ts | 12 +++-- src/chrome/internal/features/skipFiles.ts | 52 +++++++++---------- src/chrome/internal/scripts/sourcesMapper.ts | 6 +-- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts b/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts index 64a6e18a7..2be6cf3be 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer.ts @@ -7,10 +7,11 @@ import { IScript } from '../../internal/scripts/script'; import { CDTPScriptsRegistry } from '../registries/cdtpScriptsRegistry'; import { inject, injectable } from 'inversify'; import { TYPES } from '../../dependencyInjection.ts/types'; +import { IPositionInScript } from '../../internal/scripts/sourcesMapper'; export interface IBlackboxPatternsConfigurer { setBlackboxPatterns(params: CDTP.Debugger.SetBlackboxPatternsRequest): Promise; - setBlackboxedRanges(script: IScript, positions: CDTP.Debugger.ScriptPosition[]): Promise; + setBlackboxedRanges(script: IScript, positions: IPositionInScript[]): Promise; } @injectable() @@ -24,8 +25,13 @@ export class CDTPBlackboxPatternsConfigurer implements IBlackboxPatternsConfigur private readonly _scriptsRegistry: CDTPScriptsRegistry) { } - public setBlackboxedRanges(script: IScript, positions: CDTP.Debugger.ScriptPosition[]): Promise { - return this.api.setBlackboxedRanges({ scriptId: this._scriptsRegistry.getCdtpId(script), positions: positions }); + public setBlackboxedRanges(script: IScript, positions: IPositionInScript[]): Promise { + const cdtpPositions: CDTP.Debugger.ScriptPosition[] = positions.map(p => ({ + lineNumber: p.line, + columnNumber: p.column + })); + + return this.api.setBlackboxedRanges({ scriptId: this._scriptsRegistry.getCdtpId(script), positions: cdtpPositions }); } public setBlackboxPatterns(params: CDTP.Debugger.SetBlackboxPatternsRequest): Promise { diff --git a/src/chrome/internal/features/skipFiles.ts b/src/chrome/internal/features/skipFiles.ts index c57f28460..1259f8857 100644 --- a/src/chrome/internal/features/skipFiles.ts +++ b/src/chrome/internal/features/skipFiles.ts @@ -2,24 +2,24 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { Protocol as CDTP } from 'devtools-protocol'; +import { inject, injectable, LazyServiceIdentifer } from 'inversify'; import { logger } from 'vscode-debugadapter/lib/logger'; -import { IScript } from '../scripts/script'; -import { StackTracesLogic, IStackTracePresentationLogicProvider } from '../stackTraces/stackTracesLogic'; -import { newResourceIdentifierMap, IResourceIdentifier, parseResourceIdentifier } from '../sources/resourceIdentifier'; -import { IComponent } from './feature'; -import { LocationInLoadedSource } from '../locations/location'; -import { ICallFramePresentationDetails, CallFramePresentation } from '../stackTraces/callFramePresentation'; import * as nls from 'vscode-nls'; -import { injectable, inject, LazyServiceIdentifer } from 'inversify'; -import { TYPES } from '../../dependencyInjection.ts/types'; -import { ClientToInternal } from '../../client/clientToInternal'; -import { IScriptParsedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; -import { IBlackboxPatternsConfigurer } from '../../cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer'; import { IToggleSkipFileStatusArgs } from '../../../debugAdapterInterfaces'; import * as utils from '../../../utils'; -import { BaseSourceMapTransformer } from '../../../transformers/baseSourceMapTransformer'; +import { IScriptParsedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpOnScriptParsedEventProvider'; +import { IBlackboxPatternsConfigurer } from '../../cdtpDebuggee/features/cdtpBlackboxPatternsConfigurer'; import { ConnectedCDAConfiguration } from '../../client/chromeDebugAdapter/cdaConfiguration'; +import { ClientToInternal } from '../../client/clientToInternal'; +import { TYPES } from '../../dependencyInjection.ts/types'; +import { LocationInLoadedSource } from '../locations/location'; +import { createColumnNumber, createLineNumber } from '../locations/subtypes'; +import { IScript } from '../scripts/script'; +import { IPositionInScript } from '../scripts/sourcesMapper'; +import { IResourceIdentifier, newResourceIdentifierMap } from '../sources/resourceIdentifier'; +import { CallFramePresentation, ICallFramePresentationDetails } from '../stackTraces/callFramePresentation'; +import { IStackTracePresentationLogicProvider, StackTracesLogic } from '../stackTraces/stackTracesLogic'; +import { IComponent } from './feature'; const localize = nls.loadMessageBundle(); export interface IEventsConsumedBySkipFilesLogic { @@ -182,7 +182,7 @@ export class SkipFilesLogic implements IComponent, ISta public async resolveSkipFiles(script: IScript, mappedUrl: IResourceIdentifier, sources: IResourceIdentifier[], toggling?: boolean): Promise { if (sources && sources.length) { const parentIsSkipped = this.shouldSkipSource(script.runtimeSource.identifier); - const libPositions: CDTP.Debugger.ScriptPosition[] = []; + const libPositions: IPositionInScript[] = []; // Figure out skip/noskip transitions within script let inLibRange = parentIsSkipped; @@ -196,12 +196,13 @@ export class SkipFilesLogic implements IComponent, ISta this._skipFileStatuses.set(s, isSkippedFile); if ((isSkippedFile && !inLibRange) || (!isSkippedFile && inLibRange)) { - const details = await this.sourceMapTransformer.allSourcePathDetails(script.url); - const detail = details.find(d => parseResourceIdentifier(d.inferredPath).isEquivalentTo(s)); - libPositions.push({ - lineNumber: detail.startPosition.line, - columnNumber: detail.startPosition.column - }); + const sourcesMapper = script.sourcesMapper; + const pos = sourcesMapper.getPositionInScript({ source: s.canonicalized, line: createLineNumber(0) }); + if (!pos) { + throw new Error(`Source '${s.canonicalized}' start not found in script.`) + } + + libPositions.push(pos); inLibRange = !inLibRange; } } @@ -209,15 +210,15 @@ export class SkipFilesLogic implements IComponent, ISta // If there's any change from the default, set proper blackboxed ranges if (libPositions.length || toggling) { if (parentIsSkipped) { - libPositions.splice(0, 0, { lineNumber: 0, columnNumber: 0 }); + libPositions.splice(0, 0, { line: createLineNumber(0), column: createColumnNumber(0) }); } - if (libPositions[0].lineNumber !== 0 || libPositions[0].columnNumber !== 0) { + if (libPositions[0].line !== 0 || libPositions[0].column !== 0) { // The list of blackboxed ranges must start with 0,0 for some reason. // https://github.com/Microsoft/vscode-chrome-debug/issues/667 libPositions[0] = { - lineNumber: 0, - columnNumber: 0 + line: createLineNumber(0), + column: createColumnNumber(0) }; } @@ -231,7 +232,7 @@ export class SkipFilesLogic implements IComponent, ISta const status = await this.getSkipStatus(mappedUrl); const skippedByPattern = this.matchesSkipFilesPatterns(mappedUrl); if (typeof status === 'boolean' && status !== skippedByPattern) { - const positions = status ? [{ lineNumber: 0, columnNumber: 0 }] : []; + const positions = status ? [{ line: createLineNumber(0), column: createColumnNumber(0) }] : []; this._blackboxPatternsConfigurer.setBlackboxedRanges(script, positions).catch(() => this.warnNoSkipFiles()); } } @@ -285,7 +286,6 @@ export class SkipFilesLogic implements IComponent, ISta constructor( @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedBySkipFilesLogic, @inject(new LazyServiceIdentifer(() => TYPES.StackTracesLogic)) private readonly stackTracesLogic: StackTracesLogic, - @inject(TYPES.BaseSourceMapTransformer) private readonly sourceMapTransformer: BaseSourceMapTransformer, @inject(TYPES.ClientToInternal) private readonly _clientToInternal: ClientToInternal, @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration, @inject(TYPES.IBlackboxPatternsConfigurer) private readonly _blackboxPatternsConfigurer: IBlackboxPatternsConfigurer, diff --git a/src/chrome/internal/scripts/sourcesMapper.ts b/src/chrome/internal/scripts/sourcesMapper.ts index bd1efdd7a..2387fd055 100644 --- a/src/chrome/internal/scripts/sourcesMapper.ts +++ b/src/chrome/internal/scripts/sourcesMapper.ts @@ -11,13 +11,13 @@ export interface ISourcesMapper { getPositionInScript(positionInSource: IPositionInSource): IPositionInScript | null; } -interface IPositionInSource { +export interface IPositionInSource { readonly source: string; readonly line: LineNumber; readonly column?: ColumnNumber; } -interface IPositionInScript { +export interface IPositionInScript { readonly line: LineNumber; readonly column?: ColumnNumber; } @@ -34,7 +34,7 @@ export class SourcesMapper implements ISourcesMapper { public getPositionInScript(positionInSource: IPositionInSource): IPositionInScript | null { const mappedPosition = this._sourceMap.generatedPositionFor(positionInSource.source, positionInSource.line, positionInSource.column || 0); - return mappedPosition && mappedPosition.line + return mappedPosition && typeof mappedPosition.line === 'number' ? { line: createLineNumber(mappedPosition.line), column: createColumnNumber(mappedPosition.column) } : null; } From 2b4a2167ca1cc314e2b9396c23d3be78f6710768 Mon Sep 17 00:00:00 2001 From: digeff Date: Mon, 28 Jan 2019 13:58:48 -0800 Subject: [PATCH 20/23] Finish merge --- .../eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts | 5 +---- .../cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts | 4 ++-- src/chrome/chromeDebugAdapter.ts | 3 +-- src/chrome/client/chromeDebugAdapter/connectedCDA.ts | 7 ++++--- src/chrome/client/internalToClient.ts | 4 ---- src/chrome/internal/locations/location.ts | 2 +- src/chrome/target/events.ts | 5 ++--- tsconfig.json | 5 ----- 8 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts index 5c2b455be..e274e14cb 100644 --- a/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts +++ b/src/chrome/cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider.ts @@ -5,7 +5,6 @@ import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; import { asyncMap } from '../../collections/async'; import { CDTPStackTraceParser } from '../protocolParsers/cdtpStackTraceParser'; -import { adaptToSinglIntoToMulti } from '../../../utils'; import { CDTPBreakpointIdsRegistry } from '../registries/cdtpBreakpointIdsRegistry'; import { ScriptCallFrame, CodeFlowFrame } from '../../internal/stackTraces/callFrame'; import { asyncUndefinedOnFailure } from '../../utils/failures'; @@ -46,8 +45,6 @@ export class CDTDebuggeeExecutionEventsProvider extends CDTPEventsEmitterDiagnos private readonly _cdtpLocationParser = new CDTPLocationParser(this._scriptsRegistry); private readonly _stackTraceParser = new CDTPStackTraceParser(this._scriptsRegistry); - private getBPsFromIDs = adaptToSinglIntoToMulti(this, this.getBPFromID); - public readonly onPaused = this.addApiListener('paused', async (params: CDTP.Debugger.PausedEvent) => { if (params.callFrames.length === 0) { throw new Error(`Expected a pause event to have at least a single call frame: ${JSON.stringify(params)}`); @@ -55,7 +52,7 @@ export class CDTDebuggeeExecutionEventsProvider extends CDTPEventsEmitterDiagnos const callFrames = await asyncMap(params.callFrames, (callFrame, index) => this.toCallFrame(index, callFrame)); - return new PausedEvent(callFrames, params.reason, params.data, this.getBPsFromIDs(params.hitBreakpoints), + return new PausedEvent(callFrames, params.reason, params.data, await asyncMap(params.hitBreakpoints, hbp => this.getBPFromID(hbp)), params.asyncStackTrace && await this._stackTraceParser.toStackTraceCodeFlow(params.asyncStackTrace), params.asyncStackTraceId, params.asyncCallStackTraceId); }); diff --git a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts index 2aad9f00f..2c8920c43 100644 --- a/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts +++ b/src/chrome/cdtpDebuggee/features/cdtpDebuggeeBreakpoints.ts @@ -15,7 +15,7 @@ import { CDTPLocationParser } from '../protocolParsers/cdtpLocationParser'; import { CDTPEventsEmitterDiagnosticsModule } from '../infrastructure/cdtpDiagnosticsModule'; import { CDTPDomainsEnabler } from '../infrastructure/cdtpDomainsEnabler'; import { Position } from '../../internal/locations/location'; -import { singleOne } from '../../collections/utilities'; +import { singleElementOfArray } from '../../collections/utilities'; import { CDTPSupportedResources, CDTPSupportedHitActions, CDTPBreakpoint } from '../cdtpPrimitives'; import { Listeners } from '../../communication/listeners'; import { IScript } from '../../internal/scripts/script'; @@ -74,7 +74,7 @@ export class CDTPDebuggeeBreakpoints extends CDTPEventsEmitterDiagnosticsModule< return { breakpointId: response.breakpointId, locations: [response.actualLocation] }; }); - return singleOne(breakpoints); + return singleElementOfArray(breakpoints); } public async setBreakpointByUrl(bpRecipie: BPRecipieInUrl): Promise>[]> { diff --git a/src/chrome/chromeDebugAdapter.ts b/src/chrome/chromeDebugAdapter.ts index c5c7dc152..10abdf778 100644 --- a/src/chrome/chromeDebugAdapter.ts +++ b/src/chrome/chromeDebugAdapter.ts @@ -22,8 +22,7 @@ import { stackTraceWithoutLogpointFrame } from './internalSourceBreakpoint'; import * as errors from '../errors'; import * as utils from '../utils'; -import { promiseDefer } from '../utils'; -import { telemetry, BatchTelemetryReporter, IExecutionResultTelemetryProperties } from '../telemetry'; +import { telemetry, BatchTelemetryReporter } from '../telemetry'; import { StepProgressEventsEmitter } from '../executionTimingsReporter'; import { LineColTransformer } from '../transformers/lineNumberTransformer'; diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts index d1e1d0cb5..83054f82c 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts @@ -2,7 +2,7 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ - import * as errors from '../../../errors'; +import * as errors from '../../../errors'; import { DebugProtocol } from 'vscode-debugprotocol'; import { ChromeDebugLogic } from '../../chromeDebugAdapter'; import { ClientToInternal } from '../clientToInternal'; @@ -28,6 +28,7 @@ import { StepProgressEventsEmitter } from '../../../executionTimingsReporter'; import { TelemetryPropertyCollector, ITelemetryPropertyCollector } from '../../../telemetry'; import { ICommunicator, utils, IToggleSkipFileStatusArgs } from '../../..'; import { CallFramePresentation } from '../../internal/stackTraces/callFramePresentation'; +import { asyncMap } from '../../collections/async'; // TODO DIEGO: Remember to call here and only here this._lineColTransformer.convertDebuggerLocationToClient(stackFrame); for all responses @injectable() @@ -86,7 +87,7 @@ export class ConnectedCDA implements IDebugAdapterState { if (args.breakpoints) { const desiredBPRecipies = this._clientToInternal.toBPRecipies(args); const bpRecipiesStatus = await this._breakpointsLogic.updateBreakpointsForFile(desiredBPRecipies, telemetryPropertyCollector); - return { breakpoints: await this._internalToVsCode.toBPRecipiesStatus(bpRecipiesStatus) }; + return { breakpoints: await asyncMap(bpRecipiesStatus, bprs => this._internalToVsCode.toBPRecipieStatus(bprs)) }; } else { throw new Error(`Expected the set breakpoints arguments to have a list of breakpoints yet it was ${args.breakpoints}`); } @@ -186,7 +187,7 @@ export class ConnectedCDA implements IDebugAdapterState { } public async loadedSources(): Promise { - return { sources: await this._internalToVsCode.toSourceTrees(await this._sourcesLogic.getLoadedSourcesTrees()) }; + return { sources: await asyncMap(await this._sourcesLogic.getLoadedSourcesTrees(), st => this._internalToVsCode.toSourceTree(st)) }; } public setFunctionBreakpoints(_args: DebugProtocol.SetFunctionBreakpointsArguments, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): PromiseOrNot { diff --git a/src/chrome/client/internalToClient.ts b/src/chrome/client/internalToClient.ts index 8e82171fa..441bb62cd 100644 --- a/src/chrome/client/internalToClient.ts +++ b/src/chrome/client/internalToClient.ts @@ -5,7 +5,6 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { utils, LineColTransformer, IExceptionInfoResponseBody } from '../..'; import * as pathModule from 'path'; -import { asyncAdaptToSinglIntoToMulti } from '../../utils'; import { ILoadedSource, ILoadedSourceTreeNode } from '../internal/sources/loadedSource'; import { LocationInLoadedSource } from '../internal/locations/location'; import { RemoveProperty } from '../../typeUtils'; @@ -30,9 +29,6 @@ interface IClientLocationInSource { @injectable() export class InternalToClient { - public readonly toSourceTrees = asyncAdaptToSinglIntoToMulti(this, this.toSourceTree); - public readonly toBPRecipiesStatus = asyncAdaptToSinglIntoToMulti(this, this.toBPRecipieStatus); - public toStackFrames(rows: IStackTracePresentationRow[]): Promise { return asyncMap(rows, row => this.toStackFrame(row)); } diff --git a/src/chrome/internal/locations/location.ts b/src/chrome/internal/locations/location.ts index 56b047f94..4fd877eb2 100644 --- a/src/chrome/internal/locations/location.ts +++ b/src/chrome/internal/locations/location.ts @@ -9,7 +9,7 @@ import { ILoadedSource, isLoadedSource } from '../sources/loadedSource'; import { logger } from 'vscode-debugadapter'; import { ColumnNumber, LineNumber, URLRegexp, createURLRegexp } from './subtypes'; import { CDTPScriptUrl } from '../sources/resourceIdentifierSubtypes'; -import { IResourceIdentifier, parseResourceIdentifier, IURL } from '../sources/resourceIdentifier'; +import { IResourceIdentifier, parseResourceIdentifier, IURL, isResourceIdentifier } from '../sources/resourceIdentifier'; import { IEquivalenceComparable } from '../../utils/equivalence'; export type integer = number; diff --git a/src/chrome/target/events.ts b/src/chrome/target/events.ts index f0a29c492..130f2dd41 100644 --- a/src/chrome/target/events.ts +++ b/src/chrome/target/events.ts @@ -1,7 +1,6 @@ +import { Protocol as CDTP } from 'devtools-protocol'; import { IScript } from '../internal/scripts/script'; -import { Crdp } from '../..'; - export type integer = number; /** @@ -14,7 +13,7 @@ export interface ScriptParsedEvent { readonly startColumn: integer; readonly endLine: integer; readonly endColumn: integer; - readonly executionContextId: Crdp.Runtime.ExecutionContextId; + readonly executionContextId: CDTP.Runtime.ExecutionContextId; readonly hash: string; readonly executionContextAuxData?: any; readonly isLiveEdit?: boolean; diff --git a/tsconfig.json b/tsconfig.json index 14f7e935a..98d82aad4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,13 +27,8 @@ }, "include": [ "src/**/*.ts", -<<<<<<< HEAD "test/testDebug/**/*.ts", "test-DoNot-/**/*.ts", -||||||| merged common ancestors - "test/**/*.ts", -======= ->>>>>>> origin/v2 "node_modules/@types/**/*.ts" ] } \ No newline at end of file From e6991d05ad5dc05ddb9963c49e54f5567f017d6f Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 21 Jan 2019 21:50:20 +0000 Subject: [PATCH 21/23] Fix smartstep, toggle smart step --- src/chrome/chromeDebugSession.ts | 46 +++++------ .../chromeDebugAdapterV2.ts | 6 +- .../client/chromeDebugAdapter/connectedCDA.ts | 6 +- .../unconnectedCDACommonLogic.ts | 4 + src/chrome/client/eventSender.ts | 4 +- src/chrome/client/requests.ts | 2 +- .../communication/collaborativeDecision.ts | 12 +++ src/chrome/internal/features/smartStep.ts | 79 +++++++------------ .../features/takeProperActionOnPausedEvent.ts | 4 +- src/debugAdapterInterfaces.d.ts | 1 + 10 files changed, 84 insertions(+), 80 deletions(-) diff --git a/src/chrome/chromeDebugSession.ts b/src/chrome/chromeDebugSession.ts index 009084bc2..cc2045efe 100644 --- a/src/chrome/chromeDebugSession.ts +++ b/src/chrome/chromeDebugSession.ts @@ -151,32 +151,32 @@ export class ChromeDebugSession extends LoggingDebugSession implements IObservab if (AvailableCommands.has(request.command)) { const command = request.command as CommandText; - // We want the request to be non-blocking, so we won't await for reportTelemetry - return this.reportTelemetry(`ClientRequest/${request.command}`, async (reportFailure, telemetryPropertyCollector) => { - const response: DebugProtocol.Response = new Response(request); - try { - logger.verbose(`From client: ${request.command}(${JSON.stringify(request.arguments) })`); - - if (!(request.command in this._debugAdapter)) { - reportFailure('The debug adapter doesn\'t recognize this command'); - this.sendUnknownCommandResponse(response, request.command); - } else { - telemetryPropertyCollector.addTelemetryProperty('requestType', request.type); - const requestHandler = (this._debugAdapter as any) [command] as Function; - if (requestHandler instanceof Function) { - response.body = await requestHandler.call(this._debugAdapter, request.arguments, telemetryPropertyCollector, request.seq); + // We want the request to be non-blocking, so we won't await for reportTelemetry + return this.reportTelemetry(`ClientRequest/${request.command}`, async (reportFailure, telemetryPropertyCollector) => { + const response: DebugProtocol.Response = new Response(request); + try { + logger.verbose(`From client: ${request.command}(${JSON.stringify(request.arguments) })`); + + if (!(request.command in this._debugAdapter)) { + reportFailure('The debug adapter doesn\'t recognize this command'); + this.sendUnknownCommandResponse(response, request.command); } else { - throw new Error(`Couldn't find a handler for request ${command}`); + telemetryPropertyCollector.addTelemetryProperty('requestType', request.type); + const requestHandler = (this._debugAdapter as any) [command] as Function; + if (requestHandler instanceof Function) { + response.body = await requestHandler.call(this._debugAdapter, request.arguments, telemetryPropertyCollector, request.seq); + } else { + throw new Error(`Couldn't find a handler for request ${command}`); + } + this.sendResponse(response); } - this.sendResponse(response); - } - } catch (e) { - if (!this.isEvaluateRequest(request.command, e)) { - reportFailure(e); + } catch (e) { + if (!this.isEvaluateRequest(request.command, e)) { + reportFailure(e); + } + this.failedRequest(request.command, response, e); } - this.failedRequest(request.command, response, e); - } - }); + }); } else { throw new Error(`The client requested ${request.command} which is not a recognized command`); } diff --git a/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts b/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts index 990f5afb4..3f94cefb6 100644 --- a/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts +++ b/src/chrome/client/chromeDebugAdapter/chromeDebugAdapterV2.ts @@ -129,6 +129,10 @@ export class ChromeDebugAdapter implements IDebugAdapter { } public async toggleSkipFileStatus(args: IToggleSkipFileStatusArgs): Promise { - this._state.toggleSkipFileStatus(args); + return this._state.toggleSkipFileStatus(args); + } + + public async toggleSmartStep(): Promise { + return this._state.toggleSmartStep(); } } \ No newline at end of file diff --git a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts index 83054f82c..970ac2ef7 100644 --- a/src/chrome/client/chromeDebugAdapter/connectedCDA.ts +++ b/src/chrome/client/chromeDebugAdapter/connectedCDA.ts @@ -207,7 +207,11 @@ export class ConnectedCDA implements IDebugAdapterState { } public async toggleSkipFileStatus(args: IToggleSkipFileStatusArgs): Promise { - this._skipFilesLogic.toggleSkipFileStatus(args); + return this._skipFilesLogic.toggleSkipFileStatus(args); + } + + public async toggleSmartStep(): Promise { + return this._smartStepLogic.toggleSmartStep(); } public launch(_args: ILaunchRequestArgs, _telemetryPropertyCollector?: ITelemetryPropertyCollector, _requestSeq?: number): never { diff --git a/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts index 36554a711..aed1ef1e6 100644 --- a/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts +++ b/src/chrome/client/chromeDebugAdapter/unconnectedCDACommonLogic.ts @@ -109,6 +109,10 @@ export abstract class BaseUnconnectedCDA implements IDebugAdapterState { return this.throwNotConnectedError(); } + public toggleSmartStep(): Promise { + return this.throwNotConnectedError(); + } + private throwNotConnectedError(): never { throw new Error("Can't execute this request when the debug adapter is not connected to the target"); } diff --git a/src/chrome/client/eventSender.ts b/src/chrome/client/eventSender.ts index e18522892..62c7a25db 100644 --- a/src/chrome/client/eventSender.ts +++ b/src/chrome/client/eventSender.ts @@ -49,7 +49,7 @@ export interface IEventsToClientReporter { sendSourceWasLoaded(params: ISourceWasLoadedParameters): Promise; sendBPStatusChanged(params: IBPStatusChangedParameters): Promise; sendExceptionThrown(params: IExceptionThrownParameters): Promise; - sendDebugeeIsStopped(params: IDebugeeIsStoppedParameters): Promise; + sendDebuggeeIsStopped(params: IDebugeeIsStoppedParameters): Promise; } @injectable() @@ -90,7 +90,7 @@ export class EventSender implements IEventsToClientReporter { }); } - public async sendDebugeeIsStopped(params: IDebugeeIsStoppedParameters): Promise { + public async sendDebuggeeIsStopped(params: IDebugeeIsStoppedParameters): Promise { return this._session.sendEvent(new StoppedEvent2(params.reason, /*threadId=*/ChromeDebugLogic.THREAD_ID, params.exception)); } diff --git a/src/chrome/client/requests.ts b/src/chrome/client/requests.ts index e8c00ba62..f184a8261 100644 --- a/src/chrome/client/requests.ts +++ b/src/chrome/client/requests.ts @@ -2,5 +2,5 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -export const AvailableCommands = new Set(['runInTerminal', 'initialize', 'configurationDone', 'launch', 'attach', 'restart', 'disconnect', 'terminate', 'setBreakpoints', 'setFunctionBreakpoints', 'setExceptionBreakpoints', 'continue', 'next', 'stepIn', 'stepOut', 'stepBack', 'reverseContinue', 'restartFrame', 'goto', 'pause', 'stackTrace', 'scopes', 'variables', 'setVariable', 'source', 'threads', 'terminateThreads', 'modules', 'loadedSources', 'evaluate', 'setExpression', 'stepInTargets', 'gotoTargets', 'completions', 'exceptionInfo', 'toggleSkipFileStatus']); +export const AvailableCommands = new Set(['runInTerminal', 'initialize', 'configurationDone', 'launch', 'attach', 'restart', 'disconnect', 'terminate', 'setBreakpoints', 'setFunctionBreakpoints', 'setExceptionBreakpoints', 'continue', 'next', 'stepIn', 'stepOut', 'stepBack', 'reverseContinue', 'restartFrame', 'goto', 'pause', 'stackTrace', 'scopes', 'variables', 'setVariable', 'source', 'threads', 'terminateThreads', 'modules', 'loadedSources', 'evaluate', 'setExpression', 'stepInTargets', 'gotoTargets', 'completions', 'exceptionInfo', 'toggleSkipFileStatus', 'toggleSmartStep']); export type CommandText = 'runInTerminal' | 'initialize' | 'configurationDone' | 'launch' | 'attach' | 'restart' | 'disconnect' | 'terminate' | 'setBreakpoints' | 'setFunctionBreakpoints' | 'setExceptionBreakpoints' | 'continue' | 'next' | 'stepIn' | 'stepOut' | 'stepBack' | 'reverseContinue' | 'restartFrame' | 'goto' | 'pause' | 'stackTrace' | 'scopes' | 'variables' | 'setVariable' | 'source' | 'threads' | 'terminateThreads' | 'modules' | 'loadedSources' | 'evaluate' | 'setExpression' | 'stepInTargets' | 'gotoTargets' | 'completions' | 'exceptionInfo'; diff --git a/src/chrome/communication/collaborativeDecision.ts b/src/chrome/communication/collaborativeDecision.ts index af7ab73da..5a356ab5f 100644 --- a/src/chrome/communication/collaborativeDecision.ts +++ b/src/chrome/communication/collaborativeDecision.ts @@ -53,6 +53,18 @@ export class Abstained extends VoteCommonLogic { } } +export class VoteOverride extends VoteCommonLogic { + public readonly relevance = VoteRelevance.OverrideOtherVotes; + + constructor (private readonly _callback: () => Promise) { + super(); + } + + public async execute(): Promise { + return this._callback(); + } +} + export class ExecuteDecisionBasedOnVotes { private readonly _votesByRelevance: ValidatedMultiMap>; diff --git a/src/chrome/internal/features/smartStep.ts b/src/chrome/internal/features/smartStep.ts index f9474f596..e3e181675 100644 --- a/src/chrome/internal/features/smartStep.ts +++ b/src/chrome/internal/features/smartStep.ts @@ -2,21 +2,21 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ -import { BasePathTransformer } from '../../../transformers/basePathTransformer'; +import { inject, injectable } from 'inversify'; +import { logger } from 'vscode-debugadapter'; +import * as nls from 'vscode-nls'; +import { ConnectedCDAConfiguration, utils } from '../../..'; import { BaseSourceMapTransformer } from '../../../transformers/baseSourceMapTransformer'; -import { ScriptCallFrame } from '../stackTraces/callFrame'; import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; -import { InformationAboutPausedProvider } from './takeProperActionOnPausedEvent'; -import { logger } from 'vscode-debugadapter'; -import { IComponent } from './feature'; +import { Abstained, IVote, VoteOverride } from '../../communication/collaborativeDecision'; +import { TYPES } from '../../dependencyInjection.ts/types'; import { LocationInLoadedSource } from '../locations/location'; import { ICallFramePresentationDetails } from '../stackTraces/callFramePresentation'; -import { Abstained, VoteRelevance, VoteCommonLogic, IVote } from '../../communication/collaborativeDecision'; -import * as nls from 'vscode-nls'; -import { injectable, inject } from 'inversify'; import { IStackTracePresentationLogicProvider } from '../stackTraces/stackTracesLogic'; -import { TYPES } from '../../dependencyInjection.ts/types'; -import { utils, ConnectedCDAConfiguration } from '../../..'; +import { Stepping } from '../stepping/stepping'; +import { IComponent } from './feature'; +import { InformationAboutPausedProvider } from './takeProperActionOnPausedEvent'; + const localize = nls.loadMessageBundle(); export interface IEventsConsumedBySmartStepLogic { @@ -27,45 +27,22 @@ export interface ISmartStepLogicConfiguration { isEnabled: boolean; } -export interface IShouldStepInToAvoidSkippedSourceDependencies { - stepIntoDebugee(): Promise; -} -export class ShouldStepInToAvoidSkippedSource extends VoteCommonLogic { - public readonly relevance = VoteRelevance.OverrideOtherVotes; - - private readonly _dependencies: IShouldStepInToAvoidSkippedSourceDependencies; - - public async execute(): Promise { - return this._dependencies.stepIntoDebugee(); - } -} - @injectable() export class SmartStepLogic implements IComponent, IStackTracePresentationLogicProvider { private _smartStepCount = 0; private _isEnabled = false; - public isEnabled(): boolean { - return this._isEnabled; - } - - public toggleEnabled(): void { - this.enable(!this._isEnabled); - } - - public enable(shouldEnable: boolean): void { - this._isEnabled = shouldEnable; - } - public async toggleSmartStep(): Promise { - this.toggleEnabled(); - this.stepInIfOnSkippedSource(); + this._isEnabled = !this._isEnabled; + this.sendUpdatedPause(); } public async askForInformationAboutPaused(paused: PausedEvent): Promise> { - if (this.isEnabled() && await this.shouldSkip(paused.callFrames[0])) { - this._smartStepCount++; - return new ShouldStepInToAvoidSkippedSource(); + if (this._isEnabled && await this.shouldSkip(paused)) { + return new VoteOverride(() => { + this._smartStepCount++; + return this._stepping.stepIn(); + }); } else { if (this._smartStepCount > 0) { logger.log(`SmartStep: Skipped ${this._smartStepCount} steps`); @@ -75,21 +52,23 @@ export class SmartStepLogic implements IComponent, IStackTracePresentationLogicP } } - public stepInIfOnSkippedSource(): void { - throw new Error('Not implemented TODO DIEGO'); + public sendUpdatedPause(): void { + // TODO + // this._eventsToClientReporter.sendDebuggeeIsStopped({ reason: Reason}) } - public async shouldSkip(frame: ScriptCallFrame): Promise { + public async shouldSkip(paused: PausedEvent): Promise { if (!this._isEnabled) return false; - const clientPath = this._pathTransformer.getClientPathFromTargetPath(frame.location.script.runtimeSource.identifier) - || frame.location.script.runtimeSource.identifier; - const mapping = await this._sourceMapTransformer.mapToAuthored(clientPath.canonicalized, frame.codeFlow.location.position.lineNumber, frame.codeFlow.location.position.columnNumber); + if (paused.reason !== 'other') return false; + + const frame = paused.callFrames[0]; + const mapping = await this._sourceMapTransformer.mapToAuthored(frame.location.script.url, frame.codeFlow.location.position.lineNumber, frame.codeFlow.location.position.columnNumber); if (mapping) { return false; } - if ((await this._sourceMapTransformer.allSources(clientPath.canonicalized)).length) { + if ((await this._sourceMapTransformer.allSources(frame.location.script.runtimeSource.identifier.canonicalized)).length) { return true; } @@ -97,7 +76,7 @@ export class SmartStepLogic implements IComponent, IStackTracePresentationLogicP } public getCallFrameAdditionalDetails(locationInLoadedSource: LocationInLoadedSource): ICallFramePresentationDetails[] { - return this.isEnabled && !locationInLoadedSource.source.isMappedSource() + return this._isEnabled && !locationInLoadedSource.source.isMappedSource() ? [{ additionalSourceOrigins: [localize('smartStepFeatureName', 'smartStep')], sourcePresentationHint: 'deemphasize' @@ -117,9 +96,9 @@ export class SmartStepLogic implements IComponent, IStackTracePresentationLogicP constructor( @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedBySmartStepLogic, - @inject(TYPES.BasePathTransformer) private readonly _pathTransformer: BasePathTransformer, @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, - @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration + @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration, + @inject(TYPES.Stepping) private readonly _stepping: Stepping ) { } } \ No newline at end of file diff --git a/src/chrome/internal/features/takeProperActionOnPausedEvent.ts b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts index a79cac863..b748f1988 100644 --- a/src/chrome/internal/features/takeProperActionOnPausedEvent.ts +++ b/src/chrome/internal/features/takeProperActionOnPausedEvent.ts @@ -29,7 +29,7 @@ export abstract class NotifyStoppedCommonLogic extends VoteCommonLogic { public async execute(): Promise { this._publishGoingToPauseClient(); - this._eventsToClientReporter.sendDebugeeIsStopped({ reason: this.reason, exception: this.exception }); + this._eventsToClientReporter.sendDebuggeeIsStopped({ reason: this.reason, exception: this.exception }); } } @@ -89,7 +89,7 @@ export class TakeActionBasedOnInformation { private readonly _eventsToClientReporter: IEventsToClientReporter) { this._takeActionBasedOnVotes = new ExecuteDecisionBasedOnVotes(async () => { // If we don't have any information whatsoever, then we assume that we stopped due to a debugger statement - return this._eventsToClientReporter.sendDebugeeIsStopped({ reason: 'debugger_statement' }); + return this._eventsToClientReporter.sendDebuggeeIsStopped({ reason: 'debugger_statement' }); }, piecesOfInformation); } } \ No newline at end of file diff --git a/src/debugAdapterInterfaces.d.ts b/src/debugAdapterInterfaces.d.ts index 744e2a9e2..a1f982b35 100644 --- a/src/debugAdapterInterfaces.d.ts +++ b/src/debugAdapterInterfaces.d.ts @@ -195,6 +195,7 @@ export interface IConnectedDebugAdapter { setVariable(args: DebugProtocol.SetVariableArguments, telemetryPropertyCollector?: ITelemetryPropertyCollector, requestSeq?: number): PromiseOrNot; toggleSkipFileStatus(args: IToggleSkipFileStatusArgs): Promise; + toggleSmartStep(): Promise; } export type IDebugAdapter = IConnectedDebugAdapter & IUnconnectedDebugAdapter & IUninitializedDebugAdapter; From 1f0d03fbf26bd416a26092068e0f0338cc6cce3a Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sat, 26 Jan 2019 22:43:26 +0000 Subject: [PATCH 22/23] Use mappedSources for smartStep --- src/chrome/internal/features/smartStep.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chrome/internal/features/smartStep.ts b/src/chrome/internal/features/smartStep.ts index e3e181675..0e82c7ec1 100644 --- a/src/chrome/internal/features/smartStep.ts +++ b/src/chrome/internal/features/smartStep.ts @@ -68,7 +68,7 @@ export class SmartStepLogic implements IComponent, IStackTracePresentationLogicP return false; } - if ((await this._sourceMapTransformer.allSources(frame.location.script.runtimeSource.identifier.canonicalized)).length) { + if (frame.location.script.mappedSources.length) { return true; } From 6c69834b0feac2881f22750cf358ded61f420cdc Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sun, 3 Feb 2019 19:15:58 +0000 Subject: [PATCH 23/23] Use new API instead of sourceMapTransformer --- src/chrome/internal/features/smartStep.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/chrome/internal/features/smartStep.ts b/src/chrome/internal/features/smartStep.ts index 0e82c7ec1..3d4f7c10f 100644 --- a/src/chrome/internal/features/smartStep.ts +++ b/src/chrome/internal/features/smartStep.ts @@ -6,7 +6,6 @@ import { inject, injectable } from 'inversify'; import { logger } from 'vscode-debugadapter'; import * as nls from 'vscode-nls'; import { ConnectedCDAConfiguration, utils } from '../../..'; -import { BaseSourceMapTransformer } from '../../../transformers/baseSourceMapTransformer'; import { PausedEvent } from '../../cdtpDebuggee/eventsProviders/cdtpDebuggeeExecutionEventsProvider'; import { Abstained, IVote, VoteOverride } from '../../communication/collaborativeDecision'; import { TYPES } from '../../dependencyInjection.ts/types'; @@ -63,8 +62,7 @@ export class SmartStepLogic implements IComponent, IStackTracePresentationLogicP if (paused.reason !== 'other') return false; const frame = paused.callFrames[0]; - const mapping = await this._sourceMapTransformer.mapToAuthored(frame.location.script.url, frame.codeFlow.location.position.lineNumber, frame.codeFlow.location.position.columnNumber); - if (mapping) { + if (frame.location.mappedToSource().resource.isMappedSource()) { return false; } @@ -96,7 +94,6 @@ export class SmartStepLogic implements IComponent, IStackTracePresentationLogicP constructor( @inject(TYPES.EventsConsumedByConnectedCDA) private readonly _dependencies: IEventsConsumedBySmartStepLogic, - @inject(TYPES.BaseSourceMapTransformer) private readonly _sourceMapTransformer: BaseSourceMapTransformer, @inject(TYPES.ConnectedCDAConfiguration) private readonly _configuration: ConnectedCDAConfiguration, @inject(TYPES.Stepping) private readonly _stepping: Stepping ) {