-
-
Notifications
You must be signed in to change notification settings - Fork 183
Expand file tree
/
Copy pathpaths.ts
More file actions
155 lines (149 loc) Β· 6.79 KB
/
paths.ts
File metadata and controls
155 lines (149 loc) Β· 6.79 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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import fileUrl = require('file-url')
import * as url from 'url'
import * as path from 'path'
import { decode } from 'urlencode'
import RelateUrl from 'relateurl'
/**
* Options to make sure that RelateUrl only outputs relative URLs and performs not other "smart" modifications.
* They would mess up things like prefix checking.
*/
const RELATE_URL_OPTIONS: RelateUrl.Options = {
// Make sure RelateUrl does not prefer root-relative URLs if shorter
output: RelateUrl.PATH_RELATIVE,
// Make sure RelateUrl does not remove trailing slash if present
removeRootTrailingSlash: false,
// Make sure RelateUrl does not remove default ports
defaultPorts: {},
}
/**
* Like `path.relative()` but for URLs.
* Inverse of `url.resolve()` or `new URL(relative, base)`.
*/
const relativeUrl = (from: string, to: string): string => RelateUrl.relate(from, to, RELATE_URL_OPTIONS)
/** converts a server-side Xdebug file URI to a local path for VS Code with respect to source root settings */
export function convertDebuggerPathToClient(
fileUri: string | url.Url,
pathMapping?: { [index: string]: string }
): string {
let localSourceRoot: string | undefined
let serverSourceRoot: string | undefined
if (typeof fileUri === 'string') {
fileUri = url.parse(fileUri)
}
// convert the file URI to a path
let serverPath = decode(fileUri.pathname!)
// strip the trailing slash from Windows paths (indicated by a drive letter with a colon)
const serverIsWindows = /^\/[a-zA-Z]:\//.test(serverPath)
if (serverIsWindows) {
serverPath = serverPath.substr(1)
}
if (pathMapping) {
for (const mappedServerPath of Object.keys(pathMapping)) {
const mappedLocalSource = pathMapping[mappedServerPath]
// normalize slashes for windows-to-unix
const serverRelative = (serverIsWindows ? path.win32 : path.posix).relative(mappedServerPath, serverPath)
if (serverRelative.indexOf('..') !== 0) {
// If a matching mapping has previously been found, only update
// it if the current server path is longer than the previous one
// (longest prefix matching)
if (!serverSourceRoot || mappedServerPath.length > serverSourceRoot.length) {
serverSourceRoot = mappedServerPath
localSourceRoot = mappedLocalSource
}
}
}
}
let localPath: string
if (serverSourceRoot && localSourceRoot) {
const clientIsWindows =
/^[a-zA-Z]:\\/.test(localSourceRoot) ||
/^\\\\/.test(localSourceRoot) ||
/^[a-zA-Z]:$/.test(localSourceRoot) ||
/^[a-zA-Z]:\//.test(localSourceRoot)
// get the part of the path that is relative to the source root
let pathRelativeToSourceRoot = (serverIsWindows ? path.win32 : path.posix).relative(
serverSourceRoot,
serverPath
)
if (serverIsWindows && !clientIsWindows) {
pathRelativeToSourceRoot = pathRelativeToSourceRoot.replace(/\\/g, path.posix.sep)
}
if (clientIsWindows && /^[a-zA-Z]:$/.test(localSourceRoot)) {
// if local source root mapping is only drive letter, add backslash
localSourceRoot += '\\'
}
// resolve from the local source root
localPath = (clientIsWindows ? path.win32 : path.posix).resolve(localSourceRoot, pathRelativeToSourceRoot)
} else {
localPath = (serverIsWindows ? path.win32 : path.posix).normalize(serverPath)
}
return localPath
}
/** converts a local path from VS Code to a server-side Xdebug file URI with respect to source root settings */
export function convertClientPathToDebugger(localPath: string, pathMapping?: { [index: string]: string }): string {
let localSourceRoot: string | undefined
let serverSourceRoot: string | undefined
// Xdebug always lowercases Windows drive letters in file URIs
let localFileUri = fileUrl(
localPath.replace(/^[A-Z]:\\/, match => match.toLowerCase()),
{ resolve: false }
)
let serverFileUri: string
if (pathMapping) {
for (const mappedServerPath of Object.keys(pathMapping)) {
let mappedLocalSource = pathMapping[mappedServerPath]
if (/^[a-zA-Z]:$/.test(mappedLocalSource)) {
// if local source root mapping is only drive letter, add backslash
mappedLocalSource += '\\'
}
const localRelative = path.relative(mappedLocalSource, localPath)
if (localRelative.indexOf('..') !== 0) {
// If a matching mapping has previously been found, only update
// it if the current local path is longer than the previous one
// (longest prefix matching)
if (!localSourceRoot || mappedLocalSource.length > localSourceRoot.length) {
serverSourceRoot = mappedServerPath
localSourceRoot = mappedLocalSource
}
}
}
}
if (localSourceRoot) {
localSourceRoot = localSourceRoot.replace(/^[A-Z]:$/, match => match.toLowerCase())
localSourceRoot = localSourceRoot.replace(/^[A-Z]:\\/, match => match.toLowerCase())
localSourceRoot = localSourceRoot.replace(/^[A-Z]:\//, match => match.toLowerCase())
}
if (serverSourceRoot) {
serverSourceRoot = serverSourceRoot.replace(/^[A-Z]:$/, match => match.toLowerCase())
serverSourceRoot = serverSourceRoot.replace(/^[A-Z]:\\/, match => match.toLowerCase())
serverSourceRoot = serverSourceRoot.replace(/^[A-Z]:\//, match => match.toLowerCase())
}
if (serverSourceRoot && localSourceRoot) {
let localSourceRootUrl = fileUrl(localSourceRoot, { resolve: false })
if (!localSourceRootUrl.endsWith('/')) {
localSourceRootUrl += '/'
}
let serverSourceRootUrl = fileUrl(serverSourceRoot, { resolve: false })
if (!serverSourceRootUrl.endsWith('/')) {
serverSourceRootUrl += '/'
}
// get the part of the path that is relative to the source root
const urlRelativeToSourceRoot = relativeUrl(localSourceRootUrl, localFileUri)
// resolve from the server source root
serverFileUri = url.resolve(serverSourceRootUrl, urlRelativeToSourceRoot)
} else {
serverFileUri = localFileUri
}
return serverFileUri
}
export function isWindowsUri(path: string): boolean {
return /^file:\/\/\/[a-zA-Z]:\//.test(path)
}
export function isSameUri(clientUri: string, debuggerUri: string): boolean {
if (isWindowsUri(clientUri) || isWindowsUri(debuggerUri)) {
// compare case-insensitive on Windows
return debuggerUri.toLowerCase() === clientUri.toLowerCase()
} else {
return debuggerUri === clientUri
}
}