microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
bumo-glob-cli-fix

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/debugger/debugSessionBase.ts

330lines · modeblame

2c19da7fRedMickey6 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as path from "path";
5import * as fs from "fs";
09f6024fHeniker4 years ago6import * as vscode from "vscode";
623be8a6Ezio Li2 years ago7import { LoggingDebugSession, Logger, logger, ErrorDestination } from "@vscode/debugadapter";
2c19da7fRedMickey6 years ago8import { DebugProtocol } from "vscode-debugprotocol";
09f6024fHeniker4 years ago9import * as nls from "vscode-nls";
dc94981bQuan Jin3 years ago10import { stripJsonTrailingComma } from "../common/utils";
09f6024fHeniker4 years ago11import { getLoggingDirectory, LogHelper, LogLevel } from "../extension/log/LogHelper";
2c19da7fRedMickey6 years ago12import { ReactNativeProjectHelper } from "../common/reactNativeProjectHelper";
13import { ErrorHelper } from "../common/error/errorHelper";
14import { InternalErrorCode } from "../common/error/internalErrorCode";
e23d1841RedMickey6 years ago15import { InternalError, NestedError } from "../common/error/internalError";
bfcc8a29Samriel4 years ago16import { ILaunchArgs, IRunOptions, PlatformType } from "../extension/launchArgs";
2c19da7fRedMickey6 years ago17import { AppLauncher } from "../extension/appLauncher";
bfcc8a29Samriel4 years ago18import { RNPackageVersions } from "../common/projectVersionHelper";
43e6ccc3JiglioNero4 years ago19import { SettingsHelper } from "../extension/settingsHelper";
19df32dcRedMickey4 years ago20import { OutputChannelLogger } from "../extension/log/OutputChannelLogger";
d93677adRedMickey4 years ago21import { RNSession } from "./debugSessionWrapper";
bfcc8a29Samriel4 years ago22
34472878RedMickey5 years ago23nls.config({
24messageFormat: nls.MessageFormat.bundle,
25bundleFormat: nls.BundleFormat.standalone,
26})();
e23d1841RedMickey6 years ago27const localize = nls.loadMessageBundle();
2c19da7fRedMickey6 years ago28
29/**
30* Enum of possible statuses of debug session
31*/
32export enum DebugSessionStatus {
33/** A session has been just created */
34FirstConnection,
35/** This status is required in order to exclude the possible creation of several debug sessions at the first start */
36FirstConnectionPending,
37/** This status means that an application can be reloaded */
38ConnectionAllowed,
39/** This status means that an application is reloading now, and we shouldn't terminate the current debug session */
40ConnectionPending,
41/** A debuggee connected successfully */
42ConnectionDone,
43/** A debuggee failed to connect */
44ConnectionFailed,
19df32dcRedMickey4 years ago45/** The session is handling disconnect request now */
46Stopping,
47/** The session is stopped */
48Stopped,
2c19da7fRedMickey6 years ago49}
50
ebbd64f1RedMickey6 years ago51export interface TerminateEventArgs {
52debugSession: vscode.DebugSession;
53args: any;
54}
55
5471436aRedMickey5 years ago56export interface IAttachRequestArgs
57extends DebugProtocol.AttachRequestArguments,
58IRunOptions,
59vscode.DebugConfiguration {
259c018fYuri Skorokhodov5 years ago60webkitRangeMax: number;
61webkitRangeMin: number;
34472878RedMickey5 years ago62cwd: string /* Automatically set by VS Code to the currently opened folder */;
2c19da7fRedMickey6 years ago63port: number;
64url?: string;
6f9a0779JiglioNero5 years ago65useHermesEngine: boolean;
2c19da7fRedMickey6 years ago66address?: string;
67trace?: string;
5d47053fRedMickey6 years ago68skipFiles?: [];
1bdccb66RedMickey6 years ago69sourceMaps?: boolean;
70sourceMapPathOverrides?: { [key: string]: string };
2d89fb47Ezio Li3 years ago71jsDebugTrace?: boolean;
9f8c460dEzio Li2 years ago72browserTarget?: string;
2c19da7fRedMickey6 years ago73}
74
34472878RedMickey5 years ago75export interface ILaunchRequestArgs
76extends DebugProtocol.LaunchRequestArguments,
77IAttachRequestArgs {}
2c19da7fRedMickey6 years ago78
79export abstract class DebugSessionBase extends LoggingDebugSession {
09f6024fHeniker4 years ago80protected static rootSessionTerminatedEventEmitter: vscode.EventEmitter<TerminateEventArgs> =
81new vscode.EventEmitter<TerminateEventArgs>();
34472878RedMickey5 years ago82public static readonly onDidTerminateRootDebugSession =
83DebugSessionBase.rootSessionTerminatedEventEmitter.event;
ebbd64f1RedMickey6 years ago84
a2ddbba5RedMickey5 years ago85protected readonly stopCommand: string;
19df32dcRedMickey4 years ago86protected readonly terminateCommand: string;
ebbd64f1RedMickey6 years ago87protected readonly pwaNodeSessionName: string;
88
2c19da7fRedMickey6 years ago89protected appLauncher: AppLauncher;
90protected projectRootPath: string;
91protected isSettingsInitialized: boolean; // used to prevent parameters reinitialization when attach is called from launch function
92protected previousAttachArgs: IAttachRequestArgs;
93protected cdpProxyLogLevel: LogLevel;
94protected debugSessionStatus: DebugSessionStatus;
19df32dcRedMickey4 years ago95protected nodeSession: vscode.DebugSession | null;
d93677adRedMickey4 years ago96protected rnSession: RNSession;
97protected vsCodeDebugSession: vscode.DebugSession;
e23d1841RedMickey6 years ago98protected cancellationTokenSource: vscode.CancellationTokenSource;
2c19da7fRedMickey6 years ago99
d93677adRedMickey4 years ago100constructor(rnSession: RNSession) {
2c19da7fRedMickey6 years ago101super();
102
ebbd64f1RedMickey6 years ago103// constants definition
104this.pwaNodeSessionName = "pwa-node"; // the name of node debug session created by js-debug extension
a2ddbba5RedMickey5 years ago105this.stopCommand = "workbench.action.debug.stop"; // the command which simulates a click on the "Stop" button
19df32dcRedMickey4 years ago106this.terminateCommand = "terminate"; // the "terminate" command is sent from the client to the debug adapter in order to give the debuggee a chance for terminating itself
ebbd64f1RedMickey6 years ago107
108// variables definition
d93677adRedMickey4 years ago109this.rnSession = rnSession;
110this.vsCodeDebugSession = rnSession.vsCodeDebugSession;
2c19da7fRedMickey6 years ago111this.isSettingsInitialized = false;
112this.debugSessionStatus = DebugSessionStatus.FirstConnection;
e23d1841RedMickey6 years ago113this.cancellationTokenSource = new vscode.CancellationTokenSource();
19df32dcRedMickey4 years ago114this.nodeSession = null;
e23d1841RedMickey6 years ago115}
116
34472878RedMickey5 years ago117protected initializeRequest(
118response: DebugProtocol.InitializeResponse,
119// eslint-disable-next-line @typescript-eslint/no-unused-vars
120args: DebugProtocol.InitializeRequestArguments,
121): void {
e23d1841RedMickey6 years ago122response.body = response.body || {};
123
124response.body.supportsConfigurationDoneRequest = true;
125response.body.supportsEvaluateForHovers = true;
126response.body.supportTerminateDebuggee = true;
127response.body.supportsCancelRequest = true;
128
1bb1a217EzioLi2 years ago129response.body.exceptionBreakpointFilters = [
130{
131filter: "all",
132label: "Caught Exceptions",
133default: false,
134supportsCondition: true,
135description: "Breaks on all throw errors, even if they're caught later.",
136// eslint-disable-next-line @typescript-eslint/quotes
137conditionDescription: 'error.name == "MyError"',
138},
139{
140filter: "uncaught",
141label: "Uncaught Exceptions",
142default: false,
143supportsCondition: true,
144description: "Breaks only on errors or promise rejections that are not handled.",
145// eslint-disable-next-line @typescript-eslint/quotes
146conditionDescription: 'error.name == "MyError"',
147},
148];
149
e23d1841RedMickey6 years ago150this.sendResponse(response);
2c19da7fRedMickey6 years ago151}
152
34472878RedMickey5 years ago153protected abstract establishDebugSession(
154attachArgs: IAttachRequestArgs,
155resolve?: (value?: void | PromiseLike<void> | undefined) => void,
156): void;
b7451aefRedMickey6 years ago157
0d77292aJiglioNero4 years ago158protected async initializeSettings(args: any): Promise<void> {
2c19da7fRedMickey6 years ago159if (!this.isSettingsInitialized) {
160let chromeDebugCoreLogs = getLoggingDirectory();
161if (chromeDebugCoreLogs) {
162chromeDebugCoreLogs = path.join(chromeDebugCoreLogs, "DebugSessionLogs.txt");
163}
164let logLevel: string = args.trace;
165if (logLevel) {
166logLevel = logLevel.replace(logLevel[0], logLevel[0].toUpperCase());
167logger.setup(Logger.LogLevel[logLevel], chromeDebugCoreLogs || false);
34472878RedMickey5 years ago168this.cdpProxyLogLevel =
169LogLevel[logLevel] === LogLevel.Verbose ? LogLevel.Custom : LogLevel.None;
2c19da7fRedMickey6 years ago170} else {
171logger.setup(Logger.LogLevel.Log, chromeDebugCoreLogs || false);
34472878RedMickey5 years ago172this.cdpProxyLogLevel =
173LogHelper.LOG_LEVEL === LogLevel.Trace ? LogLevel.Custom : LogLevel.None;
2c19da7fRedMickey6 years ago174}
175
2db9ac85Yuri Skorokhodov5 years ago176if (typeof args.sourceMaps !== "boolean") {
2c19da7fRedMickey6 years ago177args.sourceMaps = true;
178}
179
5514e287RedMickey6 years ago180if (typeof args.enableDebug !== "boolean") {
181args.enableDebug = true;
182}
183
81fc1822JiglioNero4 years ago184// Now there is a problem with processing time of 'createFromSourceMap' function of js-debug
185// So we disable this functionality by default https://github.com/microsoft/vscode-js-debug/issues/1033
186if (typeof args.sourceMapRenames !== "boolean") {
187args.sourceMapRenames = false;
188}
189
43e6ccc3JiglioNero4 years ago190const projectRootPath = SettingsHelper.getReactNativeProjectRoot(args.cwd);
0d77292aJiglioNero4 years ago191const isReactProject = await ReactNativeProjectHelper.isReactNativeProject(
192projectRootPath,
193);
194if (!isReactProject) {
195throw ErrorHelper.getInternalError(InternalErrorCode.NotInReactNativeFolderError);
196}
4dfb1c4cetatanova5 years ago197
0d77292aJiglioNero4 years ago198const appLauncher = await AppLauncher.getOrCreateAppLauncherByProjectRootPath(
199projectRootPath,
4dfb1c4cetatanova5 years ago200);
0d77292aJiglioNero4 years ago201this.appLauncher = appLauncher;
202this.projectRootPath = projectRootPath;
203this.isSettingsInitialized = true;
204this.appLauncher.getOrUpdateNodeModulesRoot(true);
d93677adRedMickey4 years ago205if (this.vsCodeDebugSession.workspaceFolder) {
0d77292aJiglioNero4 years ago206this.appLauncher.updateDebugConfigurationRoot(
d93677adRedMickey4 years ago207this.vsCodeDebugSession.workspaceFolder.uri.fsPath,
0d77292aJiglioNero4 years ago208);
209}
b84470b5Ezio Li2 years ago210const settingsPort = this.appLauncher.getPackagerPort(projectRootPath);
211if (this.appLauncher.getPackager().getPort() != settingsPort) {
212this.appLauncher.getPackager().resetToSettingsPort();
213}
2c19da7fRedMickey6 years ago214}
215}
984ca036RedMickey6 years ago216
34472878RedMickey5 years ago217protected async disconnectRequest(
218response: DebugProtocol.DisconnectResponse,
219args: DebugProtocol.DisconnectArguments,
220// eslint-disable-next-line @typescript-eslint/no-unused-vars
221request?: DebugProtocol.Request,
222): Promise<void> {
a32e1e1fYuri Skorokhodov5 years ago223if (this.appLauncher) {
224await this.appLauncher.getRnCdpProxy().stopServer();
225}
e23d1841RedMickey6 years ago226
227this.cancellationTokenSource.cancel();
228this.cancellationTokenSource.dispose();
229
230// Then we tell the extension to stop monitoring the logcat, and then we disconnect the debugging session
259c018fYuri Skorokhodov5 years ago231if (this.previousAttachArgs && this.previousAttachArgs.platform === PlatformType.Android) {
e23d1841RedMickey6 years ago232try {
8df5011eYuri Skorokhodov5 years ago233this.appLauncher.getMobilePlatform().dispose();
e23d1841RedMickey6 years ago234} catch (err) {
34472878RedMickey5 years ago235logger.warn(
236localize(
237"CouldNotStopMonitoringLogcat",
238"Couldn't stop monitoring logcat: {0}",
239err.message || err,
240),
241);
e23d1841RedMickey6 years ago242}
243}
244
19df32dcRedMickey4 years ago245this.debugSessionStatus = DebugSessionStatus.Stopped;
67ffa5b4RedMickey6 years ago246await logger.dispose();
247
ebbd64f1RedMickey6 years ago248DebugSessionBase.rootSessionTerminatedEventEmitter.fire({
d93677adRedMickey4 years ago249debugSession: this.vsCodeDebugSession,
ebbd64f1RedMickey6 years ago250args: {
a2ddbba5RedMickey5 years ago251forcedStop: !!(<any>args).forcedStop,
ebbd64f1RedMickey6 years ago252},
253});
254
255this.sendResponse(response);
e23d1841RedMickey6 years ago256}
257
19df32dcRedMickey4 years ago258protected terminateWithErrorResponse(error: Error, response: DebugProtocol.Response): void {
e23d1841RedMickey6 years ago259// We can't print error messages after the debugging session is stopped. This could break the extension work.
34472878RedMickey5 years ago260if (
261(error instanceof InternalError || error instanceof NestedError) &&
262error.errorCode === InternalErrorCode.CancellationTokenTriggered
e23d1841RedMickey6 years ago263) {
264return;
265}
266
28ceac00RedMickey4 years ago267logger.error(error.message);
268
984ca036RedMickey6 years ago269this.sendErrorResponse(
270response,
e23d1841RedMickey6 years ago271{ format: error.message, id: 1 },
984ca036RedMickey6 years ago272undefined,
273undefined,
34472878RedMickey5 years ago274ErrorDestination.User,
984ca036RedMickey6 years ago275);
276}
2c19da7fRedMickey6 years ago277
bfcc8a29Samriel4 years ago278protected async preparePackagerBeforeAttach(
279args: IAttachRequestArgs,
280reactNativeVersions: RNPackageVersions,
281): Promise<void> {
282if (!(await this.appLauncher.getPackager().isRunning())) {
283const runOptions: ILaunchArgs = Object.assign(
284{ reactNativeVersions },
285this.appLauncher.prepareBaseRunOptions(args),
286);
287this.appLauncher.getPackager().setRunOptions(runOptions);
288await this.appLauncher.getPackager().start();
289}
290}
19df32dcRedMickey4 years ago291
292protected showError(error: Error): void {
293void vscode.window.showErrorMessage(error.message, {
294modal: true,
295});
296// We can't print error messages via debug session logger after the session is stopped. This could break the extension work.
297if (this.debugSessionStatus === DebugSessionStatus.Stopped) {
298OutputChannelLogger.getMainChannel().error(error.message);
299return;
300}
301logger.error(error.message);
302}
303
304protected async terminate(): Promise<void> {
305await vscode.commands.executeCommand(this.stopCommand, undefined, {
306sessionId: this.vsCodeDebugSession.id,
307});
308}
2c19da7fRedMickey6 years ago309}
dc94981bQuan Jin3 years ago310
311/**
312* Parses settings.json file for workspace root property
313*/
314export function getProjectRoot(args: any): string {
315const vsCodeRoot = args.cwd ? path.resolve(args.cwd) : path.resolve(args.program, "../..");
316const settingsPath = path.resolve(vsCodeRoot, ".vscode/settings.json");
317try {
318const settingsContent = fs.readFileSync(settingsPath, "utf8");
319const parsedSettings = stripJsonTrailingComma(settingsContent);
320const projectRootPath =
321parsedSettings["react-native-tools.projectRoot"] ||
322parsedSettings["react-native-tools"].projectRoot;
323return path.resolve(vsCodeRoot, projectRootPath);
324} catch (e) {
325logger.verbose(
326`${settingsPath} file doesn't exist or its content is incorrect. This file will be ignored.`,
327);
328return args.cwd ? path.resolve(args.cwd) : path.resolve(args.program, "../..");
329}
330}