Skip to content

Commit 26bb1cf

Browse files
committed
support preliminary breakpoints (android only, no source maps)
1 parent 306a23a commit 26bb1cf

File tree

2 files changed

+109
-5
lines changed

2 files changed

+109
-5
lines changed

adapter/pathTransformer.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import * as utils from '../webkit/utilities';
66
import {DebugProtocol} from 'vscode-debugprotocol';
7+
import * as path from 'path';
78
import {ISetBreakpointsArgs, IDebugTransformer, ILaunchRequestArgs, IAttachRequestArgs, IStackTraceResponseBody} from '../webkit/WebKitAdapterInterfaces';
89

910
interface IPendingBreakpoint {
@@ -21,6 +22,7 @@ export class PathTransformer implements IDebugTransformer {
2122
private _clientPathToWebkitUrl = new Map<string, string>();
2223
private _webkitUrlToClientPath = new Map<string, string>();
2324
private _pendingBreakpointsByPath = new Map<string, IPendingBreakpoint>();
25+
private inferedDeviceRoot :string = null;
2426

2527
public launch(args: ILaunchRequestArgs): void {
2628
this._webRoot = utils.getAppRoot(args);
@@ -51,7 +53,38 @@ export class PathTransformer implements IDebugTransformer {
5153
args.source.path = this._clientPathToWebkitUrl.get(url);
5254
utils.Logger.log(`Paths.setBP: Resolved ${url} to ${args.source.path}`);
5355
resolve();
54-
} else {
56+
}
57+
else if (this.inferedDeviceRoot) {
58+
utils.Logger.log(`Paths.setBP: No target url cached for client path: ${url}. Using inffered device root to set breakpoint`);
59+
60+
let inferedUrl = url.replace(this._webRoot, this.inferedDeviceRoot).replace(/\\/g, "/");
61+
62+
//change device path if {N} core module or {N} module
63+
if (inferedUrl.indexOf("/node_modules/tns-core-modules/") != -1)
64+
{
65+
inferedUrl = inferedUrl.replace("/node_modules/tns-core-modules/", "/app/tns_modules/");
66+
}
67+
else if (inferedUrl.indexOf("/node_modules/") != -1)
68+
{
69+
inferedUrl = inferedUrl.replace("/node_modules/", "/app/tns_modules/");
70+
}
71+
72+
//change platform specific paths
73+
if (inferedUrl.indexOf(".android.") != -1)
74+
{
75+
inferedUrl = inferedUrl.replace(".android.", ".");
76+
}
77+
else if (inferedUrl.indexOf(".ios.") != -1)
78+
{
79+
inferedUrl = inferedUrl.replace(".ios.", ".");
80+
}
81+
82+
args.source.path = inferedUrl;
83+
this._pendingBreakpointsByPath.set(args.source.path, { resolve, reject, args });
84+
utils.Logger.log("resolving infered promise on path " + url);
85+
resolve();
86+
}
87+
else {
5588
utils.Logger.log(`Paths.setBP: No target url cached for client path: ${url}, waiting for target script to be loaded.`);
5689
args.source.path = url;
5790
this._pendingBreakpointsByPath.set(args.source.path, { resolve, reject, args });
@@ -70,6 +103,17 @@ export class PathTransformer implements IDebugTransformer {
70103

71104
public scriptParsed(event: DebugProtocol.Event): void {
72105
const webkitUrl: string = event.body.scriptUrl;
106+
if (!this.inferedDeviceRoot)
107+
{
108+
this.inferedDeviceRoot = utils.inferDeviceRoot(this._webRoot, this._platform, webkitUrl);
109+
utils.Logger.log("\n\n\n ***Inferred device root: " + this.inferedDeviceRoot + "\n\n\n");
110+
111+
if (this.inferedDeviceRoot.indexOf("/data/user/0/") != -1)
112+
{
113+
this.inferedDeviceRoot = this.inferedDeviceRoot.replace("/data/user/0/", "/data/data/");
114+
}
115+
}
116+
73117
const clientPath = utils.webkitUrlToClientPath(this._webRoot, this._platform, webkitUrl);
74118

75119
if (!clientPath) {

webkit/utilities.ts

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,13 @@ export function webkitUrlToClientPath(webRoot: string, additionalFileExtension:
240240
return '';
241241
}
242242

243-
aUrl = decodeURI(aUrl);
244-
245-
// If we don't have the client workingDirectory for some reason, don't try to map the url to a client path
243+
// If we don't have the client workingDirectory for some reason, don't try to map the url to a client path
246244
if (!webRoot) {
247245
return '';
248246
}
249247

248+
aUrl = decodeURI(aUrl);
249+
250250
// Search the filesystem under the webRoot for the file that best matches the given url
251251
let pathName = url.parse(canonicalizeUrl(aUrl)).pathname;
252252
if (!pathName || pathName === '/') {
@@ -261,14 +261,16 @@ export function webkitUrlToClientPath(webRoot: string, additionalFileExtension:
261261
return nsProjectFile;
262262
}
263263

264+
let shiftedParts = [];
264265
let pathParts = pathName.split(path.sep);
265266
while (pathParts.length > 0) {
266267
const clientPath = path.join(webRoot, pathParts.join(path.sep));
267268
if (existsSync(clientPath)) {
268269
return canonicalizeUrl(clientPath);
269270
}
270271

271-
pathParts.shift();
272+
let shifted = pathParts.shift();
273+
shiftedParts.push(shifted);
272274
}
273275

274276
//check for {N} android internal files
@@ -285,6 +287,64 @@ export function webkitUrlToClientPath(webRoot: string, additionalFileExtension:
285287
return '';
286288
}
287289

290+
/**
291+
* Infers the device root of a given path.
292+
* The device root is the parent directory of all {N} source files
293+
* This implementation assumes that all files are all under one common root on the device
294+
* Returns all the device parent directories of a source file until the file is found on the client by client path
295+
*/
296+
export function inferDeviceRoot(projectRoot: string, additionalFileExtension: string, aUrl: string): string {
297+
if (!aUrl) {
298+
return null;
299+
}
300+
301+
// If we don't have the projectRoot for some reason, don't try to map the url to a client path
302+
if (!projectRoot) {
303+
return null;
304+
}
305+
306+
aUrl = decodeURI(aUrl);
307+
308+
// Search the filesystem under the webRoot for the file that best matches the given url
309+
let pathName = url.parse(canonicalizeUrl(aUrl)).pathname;
310+
if (!pathName || pathName === '/') {
311+
return null;
312+
}
313+
314+
// Dealing with the path portion of either a url or an absolute path to remote file.
315+
// Need to force path.sep separator
316+
pathName = pathName.replace(/\//g, path.sep);
317+
318+
let shiftedParts = [];
319+
let pathParts = pathName.split(path.sep);
320+
while (pathParts.length > 0) {
321+
const clientPath = path.join(projectRoot, pathParts.join(path.sep));
322+
if (existsSync(clientPath)) {
323+
//return canonicalizeUrl(clientPath);
324+
return shiftedParts.join(path.sep).replace(/\\/g, "/");
325+
}
326+
327+
let shifted = pathParts.shift();
328+
shiftedParts.push(shifted);
329+
}
330+
331+
//check for {N} android internal files
332+
shiftedParts = [];
333+
pathParts = pathName.split(path.sep);
334+
while (pathParts.length > 0) {
335+
const clientPath = path.join(projectRoot, "platforms/android/src/main/assets", pathParts.join(path.sep));
336+
if (existsSync(clientPath)) {
337+
//return canonicalizeUrl(clientPath);
338+
return shiftedParts.join(path.sep).replace(/\\/g, "/");
339+
}
340+
341+
let shifted = pathParts.shift();
342+
shiftedParts.push(shifted);
343+
}
344+
345+
return null;
346+
}
347+
288348
/**
289349
* Modify a url either from the client or the webkit target to a common format for comparing.
290350
* The client can handle urls in this format too.

0 commit comments

Comments
 (0)