-
Notifications
You must be signed in to change notification settings - Fork 124
Expand file tree
/
Copy pathsource_file_map.ts
More file actions
executable file
·98 lines (80 loc) · 3.54 KB
/
Copy pathsource_file_map.ts
File metadata and controls
executable file
·98 lines (80 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { PathKind, PathWin32, PathPosix } from "./path_kind";
interface Mapping {
"remote": string;
"local": string;
}
export class SourceFileMap {
private sortedMappings: { [key in keyof Mapping]: Mapping[] } = {remote: [], local: []};
private nativePath: PathKind;
constructor (map: { [index: string]: string }) {
const mappings: Mapping[] = [];
this.nativePath = this.getNativePath();
for (let [remotePrefix, localPrefix] of Object.entries(map)) {
// Normalize local path, adding trailing separator if missing.
localPrefix = this.nativePath.normalizeDir(localPrefix);
// Try to detect remote path.
const debuggerPath: PathKind = SourceFileMap.toPathKind(remotePrefix);
// Normalize remote path, adding trailing separator if missing.
remotePrefix = debuggerPath.normalizeDir(remotePrefix);
mappings.push({remote: remotePrefix, local: localPrefix});
}
// Sort with longest paths first in case some paths are subsets, so that
// we match the most appropriate (e.g., with path prefixes of '/home'
// and '/home/foo', and a complete path of '/home/foo/bar.c', we should
// match the '/home/foo' path prefix instead of '/home'.
this.sortedMappings.local = [...mappings].sort((a: Mapping, b: Mapping) => b.local.length - a.local.length);
this.sortedMappings.remote = [...mappings].sort((a: Mapping, b: Mapping) => b.remote.length - a.remote.length);
}
// The native path selection is isolated here to allow for easy unit testing
// allowing non-native path types to be tested by overriding this method in
// a subclass in the test harness.
protected getNativePath(): PathKind {
if (process.platform == "win32")
return PathWin32.getInstance();
else
return PathPosix.getInstance();
}
private static toPathKind(unknownPath: string): PathKind {
const pathPosix: PathKind = PathPosix.getInstance();
const pathWin32: PathKind = PathWin32.getInstance();
return pathPosix.isAbsolute(unknownPath) ? pathPosix : pathWin32;
}
private pathMatch(key: keyof Mapping, caseSensitive: boolean, path: string): Mapping | undefined {
for (const mapping of this.sortedMappings[key]) {
let matched: boolean;
if (caseSensitive)
matched = path.startsWith(mapping[key]);
else
matched = path.toLowerCase().startsWith(mapping[key].toLowerCase());
if (matched)
return mapping;
}
return undefined;
}
public toLocalPath(remotePath: string): string {
// Try to detect remote path.
const debuggerPath: PathKind = SourceFileMap.toPathKind(remotePath);
const normalizedRemotePath: string = debuggerPath.normalize(remotePath);
const mapping: Mapping | undefined =
this.pathMatch("remote", debuggerPath.caseSensitive, normalizedRemotePath);
if (mapping) {
const pathSuffix = normalizedRemotePath.substring(mapping.remote.length);
return this.nativePath.join(mapping.local, pathSuffix);
}
// No mapping found, so return unmapped path.
return remotePath;
}
public toRemotePath (localPath: string): string {
const normalizedLocalPath = this.nativePath.normalize(localPath);
const mapping: Mapping | undefined =
this.pathMatch("local", this.nativePath.caseSensitive, normalizedLocalPath);
if (mapping) {
const pathSuffix = normalizedLocalPath.substring(mapping.local.length);
// Try to detect remote path.
const debuggerPath = SourceFileMap.toPathKind(mapping.remote);
return debuggerPath.join(mapping.remote, pathSuffix);
}
// No mapping found, so return unmapped path.
return localPath;
}
}