@cspell/url 8.17.1 → 8.17.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +234 -0
- package/dist/index.js +376 -0
- package/package.json +7 -6
- package/dist/FileUrlBuilder.d.mts +0 -86
- package/dist/FileUrlBuilder.mjs +0 -199
- package/dist/dataUrl.d.mts +0 -8
- package/dist/dataUrl.mjs +0 -25
- package/dist/defaultFileUrlBuilder.d.mts +0 -27
- package/dist/defaultFileUrlBuilder.mjs +0 -37
- package/dist/fileUrl.d.mts +0 -22
- package/dist/fileUrl.mjs +0 -58
- package/dist/index.d.mts +0 -7
- package/dist/index.mjs +0 -6
- package/dist/url.d.mts +0 -114
- package/dist/url.mjs +0 -187
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Try to determine the base name of a URL.
|
|
3
|
+
* @param url
|
|
4
|
+
* @returns the base name of a URL, including the trailing `/` if present.
|
|
5
|
+
*/
|
|
6
|
+
declare function urlBasename(url: string | URL): string;
|
|
7
|
+
declare function isDataURL(url: string | URL): boolean;
|
|
8
|
+
|
|
9
|
+
declare function encodePathChars(filepath: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Normalize a file path for use in a URL.
|
|
12
|
+
* ```js
|
|
13
|
+
* const url = new URL(normalizeFilePathForUrl('path\\to\\file.txt'), 'file:///Users/user/');
|
|
14
|
+
* // Result: file:///Users/user/path/to/file.txt
|
|
15
|
+
* ```
|
|
16
|
+
* @param filePath
|
|
17
|
+
* @returns a normalized file path for use as a relative path in a URL.
|
|
18
|
+
*/
|
|
19
|
+
declare function normalizeFilePathForUrl(filePath: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Try to make a file URL.
|
|
22
|
+
* - if filenameOrUrl is already a URL, it is returned as is.
|
|
23
|
+
* -
|
|
24
|
+
* @param filenameOrUrl
|
|
25
|
+
* @param relativeTo - optional URL, if given, filenameOrUrl will be parsed as relative.
|
|
26
|
+
* @returns a URL
|
|
27
|
+
*/
|
|
28
|
+
declare function toFileURL(filenameOrUrl: string | URL, relativeTo?: string | URL): URL;
|
|
29
|
+
/**
|
|
30
|
+
* Converts a file path to a URL and adds a trailing slash.
|
|
31
|
+
* @param dir - url to a directory
|
|
32
|
+
* @returns a URL
|
|
33
|
+
*/
|
|
34
|
+
declare function toFileDirURL(dir: string | URL): URL;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param url - URL or string to check if it is a file URL.
|
|
38
|
+
* @returns true if the URL is a file URL.
|
|
39
|
+
*/
|
|
40
|
+
declare function isFileURL(url: URL | string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Convert a URL into a string. If it is a file URL, convert it to a path.
|
|
43
|
+
* @param url - URL
|
|
44
|
+
* @returns path or href
|
|
45
|
+
*/
|
|
46
|
+
declare function toFilePathOrHref(url: URL | string): string;
|
|
47
|
+
|
|
48
|
+
interface ParsedPath {
|
|
49
|
+
/**
|
|
50
|
+
* The root of the path such as '/' or 'c:\'
|
|
51
|
+
*/
|
|
52
|
+
root: string;
|
|
53
|
+
/**
|
|
54
|
+
* The full directory path such as '/home/user/dir' or 'c:\path\dir'
|
|
55
|
+
*/
|
|
56
|
+
dir: string;
|
|
57
|
+
/**
|
|
58
|
+
* The file name including extension (if any) such as 'index.html'
|
|
59
|
+
*/
|
|
60
|
+
base: string;
|
|
61
|
+
/**
|
|
62
|
+
* The file extension (if any) such as '.html'
|
|
63
|
+
*/
|
|
64
|
+
ext: string;
|
|
65
|
+
/**
|
|
66
|
+
* The file name without extension (if any) such as 'index'
|
|
67
|
+
*/
|
|
68
|
+
name: string;
|
|
69
|
+
}
|
|
70
|
+
interface PathInterface {
|
|
71
|
+
sep: string;
|
|
72
|
+
resolve(...paths: string[]): string;
|
|
73
|
+
parse(path: string): ParsedPath;
|
|
74
|
+
normalize(path: string): string;
|
|
75
|
+
relative(from: string, to: string): string;
|
|
76
|
+
isAbsolute(path: string): boolean;
|
|
77
|
+
}
|
|
78
|
+
interface BuilderOptions {
|
|
79
|
+
windows?: boolean | undefined;
|
|
80
|
+
path?: PathInterface | undefined;
|
|
81
|
+
cwd?: URL | undefined;
|
|
82
|
+
}
|
|
83
|
+
declare class FileUrlBuilder {
|
|
84
|
+
#private;
|
|
85
|
+
private windows;
|
|
86
|
+
readonly path: PathInterface;
|
|
87
|
+
readonly cwd: URL;
|
|
88
|
+
constructor(options?: BuilderOptions);
|
|
89
|
+
/**
|
|
90
|
+
* Encode special characters in a file path to use in a URL.
|
|
91
|
+
* @param filepath
|
|
92
|
+
* @returns
|
|
93
|
+
*/
|
|
94
|
+
encodePathChars(filepath: string): string;
|
|
95
|
+
/**
|
|
96
|
+
* Normalize a file path for use in a URL.
|
|
97
|
+
* ```js
|
|
98
|
+
* const url = new URL(normalizeFilePathForUrl('path\\to\\file.txt'), 'file:///Users/user/');
|
|
99
|
+
* // Result: file:///Users/user/path/to/file.txt
|
|
100
|
+
* ```
|
|
101
|
+
* @param filePath
|
|
102
|
+
* @returns a normalized file path for use as a relative path in a URL.
|
|
103
|
+
*/
|
|
104
|
+
normalizeFilePathForUrl(filePath: string): string;
|
|
105
|
+
/**
|
|
106
|
+
* Try to make a file URL.
|
|
107
|
+
* - if filenameOrUrl is already a URL, it is returned as is.
|
|
108
|
+
* @param filenameOrUrl
|
|
109
|
+
* @param relativeTo - optional URL, if given, filenameOrUrl will be parsed as relative.
|
|
110
|
+
* @returns a URL
|
|
111
|
+
*/
|
|
112
|
+
toFileURL(filenameOrUrl: string | URL, relativeTo?: string | URL): URL;
|
|
113
|
+
/**
|
|
114
|
+
* Try to make a URL for a directory.
|
|
115
|
+
* - if dirOrUrl is already a URL, a slash is appended to the pathname.
|
|
116
|
+
* @param dirOrUrl - directory path to convert to a file URL.
|
|
117
|
+
* @param relativeTo - optional URL, if given, filenameOrUrl will be parsed as relative.
|
|
118
|
+
* @returns a URL
|
|
119
|
+
*/
|
|
120
|
+
toFileDirURL(dirOrUrl: string | URL, relativeTo?: string | URL): URL;
|
|
121
|
+
urlToFilePathOrHref(url: URL | string): string;
|
|
122
|
+
/**
|
|
123
|
+
* Calculate the relative path to go from `urlFrom` to `urlTo`.
|
|
124
|
+
* The protocol is not evaluated. Only the `url.pathname` is used.
|
|
125
|
+
* The result: `new URL(relative(urlFrom, urlTo), urlFrom).pathname === urlTo.pathname`
|
|
126
|
+
* @param urlFrom
|
|
127
|
+
* @param urlTo
|
|
128
|
+
* @returns the relative path
|
|
129
|
+
*/
|
|
130
|
+
relative(urlFrom: URL, urlTo: URL): string;
|
|
131
|
+
/**
|
|
132
|
+
* Get the parent directory of a URL.
|
|
133
|
+
* @param url
|
|
134
|
+
*/
|
|
135
|
+
urlDirname(url: URL | string): URL;
|
|
136
|
+
pathToFileURL(pathname: string, relativeToURL?: URL | string): URL;
|
|
137
|
+
rootFileURL(filePath?: string): URL;
|
|
138
|
+
/**
|
|
139
|
+
* Determine if a filePath is absolute.
|
|
140
|
+
*
|
|
141
|
+
* @param filePath
|
|
142
|
+
* @returns true if `URL` or `path.isAbsolute(filePath)`
|
|
143
|
+
*/
|
|
144
|
+
isAbsolute(filePath: string): boolean;
|
|
145
|
+
isUrlLike(url: string | URL): boolean;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Try to make a URL.
|
|
150
|
+
* @param url
|
|
151
|
+
* @param relativeTo - optional URL, if given, url will be parsed as relative.
|
|
152
|
+
* @returns a URL
|
|
153
|
+
*/
|
|
154
|
+
declare function toURL(url: string | URL, relativeTo?: string | URL): URL;
|
|
155
|
+
/**
|
|
156
|
+
* Try to determine the parent directory URL of the uri.
|
|
157
|
+
* If it is not a hierarchical URL, then it will return the URL.
|
|
158
|
+
* @param url - url to extract the dirname from.
|
|
159
|
+
* @returns a URL
|
|
160
|
+
*/
|
|
161
|
+
declare function urlParent(url: string | URL): URL;
|
|
162
|
+
/**
|
|
163
|
+
* Alias of {@link urlParent}
|
|
164
|
+
* Try to determine the parent directory URL of the uri.
|
|
165
|
+
* If it is not a hierarchical URL, then it will return the URL.
|
|
166
|
+
* @param url - url to extract the dirname from.
|
|
167
|
+
* @returns a URL
|
|
168
|
+
*/
|
|
169
|
+
declare const urlDirname: typeof urlParent;
|
|
170
|
+
/**
|
|
171
|
+
* return the basename (last portion of the URL pathname) of a path. It does NOT remove the trailing slash.
|
|
172
|
+
* @param path - URL pathname to extract the basename from.
|
|
173
|
+
*/
|
|
174
|
+
declare function basenameOfUrlPathname(path: string): string;
|
|
175
|
+
/**
|
|
176
|
+
* @param filename - filename to check if it is a string containing a URL.
|
|
177
|
+
*/
|
|
178
|
+
declare function isUrlLike(filename: string): boolean;
|
|
179
|
+
declare function isUrlLike(filename: URL): true;
|
|
180
|
+
/**
|
|
181
|
+
* @param filename - filename to check if it is a string containing a URL or a URL object.
|
|
182
|
+
*/
|
|
183
|
+
declare function isUrlLike(filename: string | URL): boolean;
|
|
184
|
+
/**
|
|
185
|
+
* @param filename - filename to check if it is a string containing a URL.
|
|
186
|
+
*/
|
|
187
|
+
declare function isNotUrlLike(filename: string): boolean;
|
|
188
|
+
declare function isNotUrlLike(filename: URL): false;
|
|
189
|
+
/**
|
|
190
|
+
* @param filename - filename to check if it is a string containing a URL or a URL object.
|
|
191
|
+
*/
|
|
192
|
+
declare function isNotUrlLike(filename: string | URL): filename is string;
|
|
193
|
+
/**
|
|
194
|
+
* Check if `url` is a URL instance.
|
|
195
|
+
* @returns
|
|
196
|
+
*/
|
|
197
|
+
declare function isURL(url: unknown): url is URL;
|
|
198
|
+
/**
|
|
199
|
+
*
|
|
200
|
+
* @param url - url to check
|
|
201
|
+
* @param protocol - protocol to check against - e.g. 'file:', 'http:', 'https:'
|
|
202
|
+
* @returns
|
|
203
|
+
*/
|
|
204
|
+
declare function hasProtocol(url: string | URL, protocol: string): boolean;
|
|
205
|
+
/**
|
|
206
|
+
* Attempts to add a trailing slash to the URL pathname if it does not already have one.
|
|
207
|
+
* Some If the pathname doesn't start with a `/`, a trailing slash is not added.
|
|
208
|
+
* @param url - a URL
|
|
209
|
+
* @returns
|
|
210
|
+
*/
|
|
211
|
+
declare function addTrailingSlash(url: URL): URL;
|
|
212
|
+
/**
|
|
213
|
+
* Calculate the relative path to go from `urlFrom` to `urlTo`.
|
|
214
|
+
* The protocol is not evaluated. Only the `url.pathname` is used.
|
|
215
|
+
* @param urlFrom
|
|
216
|
+
* @param urlTo
|
|
217
|
+
* @returns the relative path
|
|
218
|
+
*/
|
|
219
|
+
declare function urlRelative(urlFrom: string | URL, urlTo: string | URL): string;
|
|
220
|
+
/**
|
|
221
|
+
* Ensure that a windows file url is correctly formatted with a capitol letter for the drive.
|
|
222
|
+
*
|
|
223
|
+
* @param url - URL to check.
|
|
224
|
+
* @returns a new URL if modified or converted from a string.
|
|
225
|
+
*/
|
|
226
|
+
declare function normalizeWindowsUrl(url: URL | string): URL;
|
|
227
|
+
/**
|
|
228
|
+
* There is a bug is NodeJS that sometimes causes UNC paths converted to a URL to be prefixed with `file:////`.
|
|
229
|
+
* @param url - URL to check.
|
|
230
|
+
* @returns fixed URL if needed.
|
|
231
|
+
*/
|
|
232
|
+
declare function fixUncUrl(url: URL): URL;
|
|
233
|
+
|
|
234
|
+
export { type BuilderOptions, FileUrlBuilder, type PathInterface, addTrailingSlash, basenameOfUrlPathname, encodePathChars, fixUncUrl, hasProtocol, isDataURL, isFileURL, isNotUrlLike, isURL, isUrlLike, normalizeFilePathForUrl, normalizeWindowsUrl, toFileDirURL, toFilePathOrHref, toFileURL, toURL, urlBasename, urlDirname, urlParent, urlRelative };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
// src/url.mts
|
|
2
|
+
var isURLRegEx = /^(\w[\w-]{1,63}:\/|data:|stdin:)/i;
|
|
3
|
+
function toURL(url, relativeTo) {
|
|
4
|
+
return normalizeWindowsUrl(url instanceof URL ? url : new URL(url, relativeTo));
|
|
5
|
+
}
|
|
6
|
+
function urlParent(url) {
|
|
7
|
+
url = toURL(url);
|
|
8
|
+
if (url.protocol === "data:") {
|
|
9
|
+
return url;
|
|
10
|
+
}
|
|
11
|
+
const hasTrailingSlash = url.pathname.endsWith("/");
|
|
12
|
+
if (!url.pathname.startsWith("/")) {
|
|
13
|
+
const parts = url.pathname.split("/").slice(0, hasTrailingSlash ? -2 : -1);
|
|
14
|
+
let pathname = parts.join("/");
|
|
15
|
+
pathname = pathname && pathname + "/" || "";
|
|
16
|
+
return new URL(url.protocol + (url.host ? "//" + url.host : "") + pathname + url.search + url.hash);
|
|
17
|
+
}
|
|
18
|
+
return new URL(hasTrailingSlash ? ".." : ".", url);
|
|
19
|
+
}
|
|
20
|
+
var urlDirname = urlParent;
|
|
21
|
+
function basenameOfUrlPathname(path) {
|
|
22
|
+
const adj = path.endsWith("/") ? 2 : 0;
|
|
23
|
+
const idx = path.lastIndexOf("/", path.length - adj);
|
|
24
|
+
return idx >= 0 ? path.slice(idx + 1) : path;
|
|
25
|
+
}
|
|
26
|
+
function isUrlLike(filename) {
|
|
27
|
+
return filename instanceof URL || isURLRegEx.test(filename);
|
|
28
|
+
}
|
|
29
|
+
function isNotUrlLike(filename) {
|
|
30
|
+
return !isUrlLike(filename);
|
|
31
|
+
}
|
|
32
|
+
function isURL(url) {
|
|
33
|
+
return url instanceof URL;
|
|
34
|
+
}
|
|
35
|
+
function hasProtocol(url, protocol) {
|
|
36
|
+
protocol = protocol.endsWith(":") ? protocol : protocol + ":";
|
|
37
|
+
return typeof url === "string" ? url.startsWith(protocol) : url.protocol === protocol;
|
|
38
|
+
}
|
|
39
|
+
function addTrailingSlash(url) {
|
|
40
|
+
if (url.pathname.endsWith("/")) return url;
|
|
41
|
+
const urlWithSlash = new URL(url.href);
|
|
42
|
+
urlWithSlash.pathname += "/";
|
|
43
|
+
return urlWithSlash;
|
|
44
|
+
}
|
|
45
|
+
function urlRelative(urlFrom, urlTo) {
|
|
46
|
+
return urlToUrlRelative(toURL(urlFrom), toURL(urlTo));
|
|
47
|
+
}
|
|
48
|
+
function urlToUrlRelative(urlFrom, urlTo) {
|
|
49
|
+
let pFrom = urlFrom.pathname;
|
|
50
|
+
const pTo = urlTo.pathname;
|
|
51
|
+
if (pFrom === pTo) return "";
|
|
52
|
+
pFrom = pFrom.endsWith("/") ? pFrom : new URL("./", urlFrom).pathname;
|
|
53
|
+
if (pTo.startsWith(pFrom)) return decodeURIComponent(pTo.slice(pFrom.length));
|
|
54
|
+
const p0 = pFrom;
|
|
55
|
+
const p1 = pTo;
|
|
56
|
+
if (p1.startsWith(p0)) {
|
|
57
|
+
return decodeURIComponent(p0 === p1 ? "" : p1.slice(p0.lastIndexOf("/") + 1));
|
|
58
|
+
}
|
|
59
|
+
const p0Parts = p0.split("/").slice(0, -1);
|
|
60
|
+
const p1Parts = p1.split("/");
|
|
61
|
+
let i = 0;
|
|
62
|
+
for (i = 0; i < p0Parts.length && i < p1Parts.length - 1 && p0Parts[i] === p1Parts[i]; ++i) {
|
|
63
|
+
}
|
|
64
|
+
const rel = "../".repeat(p0Parts.length - i) + p1Parts.slice(i).join("/");
|
|
65
|
+
return decodeURIComponent(rel.length < p1.length ? rel : p1);
|
|
66
|
+
}
|
|
67
|
+
var regExpWindowsPath = /^[\\/]([a-zA-Z]:[\\/])/;
|
|
68
|
+
var badUncLocalhostUrl = /^(\/+[a-zA-Z])\$/;
|
|
69
|
+
function normalizeWindowsUrl(url) {
|
|
70
|
+
url = typeof url === "string" ? new URL(url) : url;
|
|
71
|
+
if (url.protocol === "file:") {
|
|
72
|
+
let pathname = url.pathname.replaceAll("%3A", ":").replaceAll("%3a", ":").replaceAll("%24", "$");
|
|
73
|
+
if (!url.host) {
|
|
74
|
+
pathname = pathname.replace(badUncLocalhostUrl, "$1:");
|
|
75
|
+
}
|
|
76
|
+
pathname = pathname.replace(regExpWindowsPath, (d) => d.toUpperCase());
|
|
77
|
+
if (pathname !== url.pathname) {
|
|
78
|
+
url = new URL(url);
|
|
79
|
+
url.pathname = pathname;
|
|
80
|
+
return fixUncUrl(url);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return fixUncUrl(url);
|
|
84
|
+
}
|
|
85
|
+
function fixUncUrl(url) {
|
|
86
|
+
if (url.href.startsWith("file:////")) {
|
|
87
|
+
return new URL(url.href.replace(/^file:\/{4}/, "file://"));
|
|
88
|
+
}
|
|
89
|
+
return url;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/dataUrl.mts
|
|
93
|
+
var regMatchFilename = /filename=([^;,]*)/;
|
|
94
|
+
function urlBasename(url) {
|
|
95
|
+
function guessDataUrlName(header) {
|
|
96
|
+
const filenameMatch = header.match(regMatchFilename);
|
|
97
|
+
if (filenameMatch) return filenameMatch[1];
|
|
98
|
+
const mime = header.split(";", 1)[0];
|
|
99
|
+
return mime.replaceAll(/\W/g, ".");
|
|
100
|
+
}
|
|
101
|
+
url = toURL(url);
|
|
102
|
+
if (url.protocol === "data:") {
|
|
103
|
+
return guessDataUrlName(url.pathname.split(",", 1)[0]);
|
|
104
|
+
}
|
|
105
|
+
return basenameOfUrlPathname(url.pathname);
|
|
106
|
+
}
|
|
107
|
+
function isDataURL(url) {
|
|
108
|
+
return hasProtocol(url, "data:");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/FileUrlBuilder.mts
|
|
112
|
+
import assert from "node:assert";
|
|
113
|
+
import Path from "node:path";
|
|
114
|
+
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
115
|
+
|
|
116
|
+
// src/fileUrl.mts
|
|
117
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
118
|
+
var isWindows = process.platform === "win32";
|
|
119
|
+
var windowsUrlPathRegExp = /^\/[a-zA-Z]:\//;
|
|
120
|
+
function isWindowsPathnameWithDriveLatter(pathname) {
|
|
121
|
+
return windowsUrlPathRegExp.test(pathname);
|
|
122
|
+
}
|
|
123
|
+
function isFileURL(url) {
|
|
124
|
+
return hasProtocol(url, "file:");
|
|
125
|
+
}
|
|
126
|
+
function toFilePathOrHref(url) {
|
|
127
|
+
return isFileURL(url) && url.toString().startsWith("file:///") ? toFilePath(url) : url.toString();
|
|
128
|
+
}
|
|
129
|
+
function toFilePath(url) {
|
|
130
|
+
try {
|
|
131
|
+
if (isWindows) {
|
|
132
|
+
const u = new URL(url);
|
|
133
|
+
if (!isWindowsPathnameWithDriveLatter(u.pathname)) {
|
|
134
|
+
const cwdUrl = pathToFileURL(process.cwd());
|
|
135
|
+
if (cwdUrl.hostname) {
|
|
136
|
+
return fileURLToPath(new URL(u.pathname, cwdUrl));
|
|
137
|
+
}
|
|
138
|
+
const drive = cwdUrl.pathname.split("/")[1];
|
|
139
|
+
u.pathname = `/${drive}${u.pathname}`;
|
|
140
|
+
return fileURLToPath(u);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return pathWindowsDriveLetterToUpper(fileURLToPath(url));
|
|
144
|
+
} catch {
|
|
145
|
+
return url.toString();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
var regExpWindowsPathDriveLetter = /^([a-zA-Z]):[\\/]/;
|
|
149
|
+
function pathWindowsDriveLetterToUpper(absoluteFilePath) {
|
|
150
|
+
return absoluteFilePath.replace(regExpWindowsPathDriveLetter, (s) => s.toUpperCase());
|
|
151
|
+
}
|
|
152
|
+
var regExpWindowsFileUrl = /^file:\/\/\/[a-zA-Z]:\//;
|
|
153
|
+
function isWindowsFileUrl(url) {
|
|
154
|
+
return regExpWindowsFileUrl.test(url.toString());
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/FileUrlBuilder.mts
|
|
158
|
+
var isWindowsPathRegEx = regExpWindowsPathDriveLetter;
|
|
159
|
+
var isWindowsPathname = regExpWindowsPath;
|
|
160
|
+
var percentRegEx = /%/g;
|
|
161
|
+
var backslashRegEx = /\\/g;
|
|
162
|
+
var newlineRegEx = /\n/g;
|
|
163
|
+
var carriageReturnRegEx = /\r/g;
|
|
164
|
+
var tabRegEx = /\t/g;
|
|
165
|
+
var questionRegex = /\?/g;
|
|
166
|
+
var hashRegex = /#/g;
|
|
167
|
+
var ProtocolFile = "file:";
|
|
168
|
+
var FileUrlBuilder = class {
|
|
169
|
+
windows;
|
|
170
|
+
path;
|
|
171
|
+
cwd;
|
|
172
|
+
constructor(options = {}) {
|
|
173
|
+
const sep = options.path?.sep;
|
|
174
|
+
this.windows = options.windows ?? (sep ? sep === "\\" : void 0) ?? isWindows;
|
|
175
|
+
this.path = options.path ?? (this.windows ? Path.win32 : Path.posix);
|
|
176
|
+
this.cwd = options.cwd ?? this.pathToFileURL(this.path.resolve() + "/", this.rootFileURL());
|
|
177
|
+
assert(
|
|
178
|
+
this.path.sep === (this.windows ? "\\" : "/"),
|
|
179
|
+
`Path separator should match OS type Windows: ${this.windows === true ? "true" : (this.windows ?? "undefined") || "false"}, sep: ${this.path.sep}, options: ` + JSON.stringify({
|
|
180
|
+
isWindows,
|
|
181
|
+
sep: `${sep}`,
|
|
182
|
+
windows: options.windows,
|
|
183
|
+
pathSep: options.path?.sep,
|
|
184
|
+
n: options.path?.normalize("path/file.txt"),
|
|
185
|
+
cwd: options.cwd?.href,
|
|
186
|
+
win32: this.path === Path.win32,
|
|
187
|
+
posix: this.path === Path.posix,
|
|
188
|
+
"win32.normalize": this.path.normalize === Path.win32.normalize,
|
|
189
|
+
"posix.normalize": this.path.normalize === Path.posix.normalize
|
|
190
|
+
})
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Encode special characters in a file path to use in a URL.
|
|
195
|
+
* @param filepath
|
|
196
|
+
* @returns
|
|
197
|
+
*/
|
|
198
|
+
encodePathChars(filepath) {
|
|
199
|
+
filepath = filepath.replaceAll(percentRegEx, "%25");
|
|
200
|
+
if (!this.windows && !isWindows && filepath.includes("\\")) {
|
|
201
|
+
filepath = filepath.replaceAll(backslashRegEx, "%5C");
|
|
202
|
+
}
|
|
203
|
+
filepath = filepath.replaceAll(newlineRegEx, "%0A");
|
|
204
|
+
filepath = filepath.replaceAll(carriageReturnRegEx, "%0D");
|
|
205
|
+
filepath = filepath.replaceAll(tabRegEx, "%09");
|
|
206
|
+
return filepath;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Normalize a file path for use in a URL.
|
|
210
|
+
* ```js
|
|
211
|
+
* const url = new URL(normalizeFilePathForUrl('path\\to\\file.txt'), 'file:///Users/user/');
|
|
212
|
+
* // Result: file:///Users/user/path/to/file.txt
|
|
213
|
+
* ```
|
|
214
|
+
* @param filePath
|
|
215
|
+
* @returns a normalized file path for use as a relative path in a URL.
|
|
216
|
+
*/
|
|
217
|
+
normalizeFilePathForUrl(filePath) {
|
|
218
|
+
filePath = this.encodePathChars(filePath);
|
|
219
|
+
filePath = filePath.replaceAll(questionRegex, "%3F");
|
|
220
|
+
filePath = filePath.replaceAll(hashRegex, "%23");
|
|
221
|
+
const pathname = filePath.replaceAll("\\", "/");
|
|
222
|
+
return pathname.replace(isWindowsPathRegEx, (drive) => `/${drive}`.toUpperCase());
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Try to make a file URL.
|
|
226
|
+
* - if filenameOrUrl is already a URL, it is returned as is.
|
|
227
|
+
* @param filenameOrUrl
|
|
228
|
+
* @param relativeTo - optional URL, if given, filenameOrUrl will be parsed as relative.
|
|
229
|
+
* @returns a URL
|
|
230
|
+
*/
|
|
231
|
+
toFileURL(filenameOrUrl, relativeTo) {
|
|
232
|
+
return normalizeWindowsUrl(this.#toFileURL(filenameOrUrl, relativeTo));
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Try to make a file URL.
|
|
236
|
+
* - if filenameOrUrl is already a URL, it is returned as is.
|
|
237
|
+
* @param filenameOrUrl
|
|
238
|
+
* @param relativeTo - optional URL, if given, filenameOrUrl will be parsed as relative.
|
|
239
|
+
* @returns a URL
|
|
240
|
+
*/
|
|
241
|
+
#toFileURL(filenameOrUrl, relativeTo) {
|
|
242
|
+
if (typeof filenameOrUrl !== "string") return filenameOrUrl;
|
|
243
|
+
if (isUrlLike(filenameOrUrl)) return normalizeWindowsUrl(new URL(filenameOrUrl));
|
|
244
|
+
relativeTo ??= this.cwd;
|
|
245
|
+
isWindows && (filenameOrUrl = filenameOrUrl.replaceAll("\\", "/"));
|
|
246
|
+
if (this.isAbsolute(filenameOrUrl) && isFileURL(relativeTo)) {
|
|
247
|
+
const pathname2 = this.normalizeFilePathForUrl(filenameOrUrl);
|
|
248
|
+
if (isWindowsFileUrl(relativeTo) && !isWindowsPathnameWithDriveLatter(pathname2)) {
|
|
249
|
+
const relFilePrefix = relativeTo.toString().slice(0, 10);
|
|
250
|
+
return normalizeWindowsUrl(new URL(relFilePrefix + pathname2));
|
|
251
|
+
}
|
|
252
|
+
return normalizeWindowsUrl(new URL("file://" + pathname2));
|
|
253
|
+
}
|
|
254
|
+
if (isUrlLike(relativeTo)) {
|
|
255
|
+
const pathname2 = this.normalizeFilePathForUrl(filenameOrUrl);
|
|
256
|
+
return normalizeWindowsUrl(new URL(pathname2, relativeTo));
|
|
257
|
+
}
|
|
258
|
+
const appendSlash = filenameOrUrl.endsWith("/") ? "/" : "";
|
|
259
|
+
const pathname = this.normalizeFilePathForUrl(this.path.resolve(relativeTo.toString(), filenameOrUrl)) + appendSlash;
|
|
260
|
+
return normalizeWindowsUrl(new URL("file://" + pathname));
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Try to make a URL for a directory.
|
|
264
|
+
* - if dirOrUrl is already a URL, a slash is appended to the pathname.
|
|
265
|
+
* @param dirOrUrl - directory path to convert to a file URL.
|
|
266
|
+
* @param relativeTo - optional URL, if given, filenameOrUrl will be parsed as relative.
|
|
267
|
+
* @returns a URL
|
|
268
|
+
*/
|
|
269
|
+
toFileDirURL(dirOrUrl, relativeTo) {
|
|
270
|
+
return addTrailingSlash(this.toFileURL(dirOrUrl, relativeTo));
|
|
271
|
+
}
|
|
272
|
+
urlToFilePathOrHref(url) {
|
|
273
|
+
url = this.toFileURL(url);
|
|
274
|
+
return this.#urlToFilePathOrHref(url);
|
|
275
|
+
}
|
|
276
|
+
#urlToFilePathOrHref(url) {
|
|
277
|
+
if (url.protocol !== ProtocolFile || url.hostname) return url.href;
|
|
278
|
+
const p = this.path === Path ? toFilePathOrHref(url) : decodeURIComponent(url.pathname.split("/").join(this.path.sep));
|
|
279
|
+
return pathWindowsDriveLetterToUpper(p.replace(isWindowsPathname, "$1"));
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Calculate the relative path to go from `urlFrom` to `urlTo`.
|
|
283
|
+
* The protocol is not evaluated. Only the `url.pathname` is used.
|
|
284
|
+
* The result: `new URL(relative(urlFrom, urlTo), urlFrom).pathname === urlTo.pathname`
|
|
285
|
+
* @param urlFrom
|
|
286
|
+
* @param urlTo
|
|
287
|
+
* @returns the relative path
|
|
288
|
+
*/
|
|
289
|
+
relative(urlFrom, urlTo) {
|
|
290
|
+
if (urlFrom.protocol === urlTo.protocol && urlFrom.protocol === ProtocolFile) {
|
|
291
|
+
if (urlFrom.href === urlTo.href) return "";
|
|
292
|
+
urlFrom = urlFrom.pathname.endsWith("/") ? urlFrom : new URL("./", urlFrom);
|
|
293
|
+
const fromPath = urlFrom.pathname;
|
|
294
|
+
const toPath = urlTo.pathname;
|
|
295
|
+
if (toPath.startsWith(fromPath)) return decodeURIComponent(toPath.slice(fromPath.length));
|
|
296
|
+
const pFrom = this.#urlToFilePathOrHref(urlFrom);
|
|
297
|
+
const pTo = this.#urlToFilePathOrHref(urlTo);
|
|
298
|
+
const toIsDir = urlTo.pathname.endsWith("/");
|
|
299
|
+
let pathname = this.normalizeFilePathForUrl(this.path.relative(pFrom, pTo));
|
|
300
|
+
if (toIsDir && !pathname.endsWith("/")) pathname += "/";
|
|
301
|
+
return decodeURIComponent(pathname);
|
|
302
|
+
}
|
|
303
|
+
return decodeURIComponent(urlToUrlRelative(urlFrom, urlTo));
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Get the parent directory of a URL.
|
|
307
|
+
* @param url
|
|
308
|
+
*/
|
|
309
|
+
urlDirname(url) {
|
|
310
|
+
return urlParent(this.toFileURL(url));
|
|
311
|
+
}
|
|
312
|
+
pathToFileURL(pathname, relativeToURL) {
|
|
313
|
+
return new URL(this.normalizeFilePathForUrl(pathname), relativeToURL || this.cwd);
|
|
314
|
+
}
|
|
315
|
+
rootFileURL(filePath) {
|
|
316
|
+
const path = this.path;
|
|
317
|
+
const p = path.parse(path.normalize(path.resolve(filePath ?? ".")));
|
|
318
|
+
return new URL(this.normalizeFilePathForUrl(p.root), this.#getFsRootURL());
|
|
319
|
+
}
|
|
320
|
+
#getFsRootURL() {
|
|
321
|
+
if (this.path === Path) return pathToFileURL2("/");
|
|
322
|
+
const p = this.path.resolve("/");
|
|
323
|
+
return new URL(this.normalizeFilePathForUrl(p), "file:///");
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Determine if a filePath is absolute.
|
|
327
|
+
*
|
|
328
|
+
* @param filePath
|
|
329
|
+
* @returns true if `URL` or `path.isAbsolute(filePath)`
|
|
330
|
+
*/
|
|
331
|
+
isAbsolute(filePath) {
|
|
332
|
+
return isUrlLike(filePath) || this.path.isAbsolute(filePath);
|
|
333
|
+
}
|
|
334
|
+
isUrlLike(url) {
|
|
335
|
+
return isUrlLike(url);
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
// src/defaultFileUrlBuilder.mts
|
|
340
|
+
var fileUrlBuilder = new FileUrlBuilder();
|
|
341
|
+
function encodePathChars(filepath) {
|
|
342
|
+
return fileUrlBuilder.encodePathChars(filepath);
|
|
343
|
+
}
|
|
344
|
+
function normalizeFilePathForUrl(filePath) {
|
|
345
|
+
return fileUrlBuilder.normalizeFilePathForUrl(filePath);
|
|
346
|
+
}
|
|
347
|
+
function toFileURL(filenameOrUrl, relativeTo) {
|
|
348
|
+
return fileUrlBuilder.toFileURL(filenameOrUrl, relativeTo);
|
|
349
|
+
}
|
|
350
|
+
function toFileDirURL(dir) {
|
|
351
|
+
return fileUrlBuilder.toFileDirURL(dir);
|
|
352
|
+
}
|
|
353
|
+
export {
|
|
354
|
+
FileUrlBuilder,
|
|
355
|
+
addTrailingSlash,
|
|
356
|
+
basenameOfUrlPathname,
|
|
357
|
+
encodePathChars,
|
|
358
|
+
fixUncUrl,
|
|
359
|
+
hasProtocol,
|
|
360
|
+
isDataURL,
|
|
361
|
+
isFileURL,
|
|
362
|
+
isNotUrlLike,
|
|
363
|
+
isURL,
|
|
364
|
+
isUrlLike,
|
|
365
|
+
normalizeFilePathForUrl,
|
|
366
|
+
normalizeWindowsUrl,
|
|
367
|
+
toFileDirURL,
|
|
368
|
+
toFilePathOrHref,
|
|
369
|
+
toFileURL,
|
|
370
|
+
toURL,
|
|
371
|
+
urlBasename,
|
|
372
|
+
urlDirname,
|
|
373
|
+
urlParent,
|
|
374
|
+
urlRelative
|
|
375
|
+
};
|
|
376
|
+
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public",
|
|
5
5
|
"provenance": true
|
|
6
6
|
},
|
|
7
|
-
"version": "8.17.
|
|
7
|
+
"version": "8.17.3",
|
|
8
8
|
"description": "URL parsing and manipulation utilities for cspell",
|
|
9
9
|
"keywords": [
|
|
10
10
|
"cspell",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"type": "module",
|
|
17
17
|
"sideEffects": false,
|
|
18
|
-
"module": "./dist/index.
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
19
|
"types": "./dist/index.d.ts",
|
|
20
20
|
"exports": {
|
|
21
21
|
".": {
|
|
22
|
-
"import": "./dist/index.
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
@@ -34,13 +34,14 @@
|
|
|
34
34
|
"!**/*.map"
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
|
-
"build": "
|
|
37
|
+
"build": "tsup-node",
|
|
38
38
|
"build:clean": "pnpm clean && pnpm build",
|
|
39
39
|
"clean": "shx rm -rf dist coverage",
|
|
40
40
|
"clean-build": "pnpm build:clean",
|
|
41
41
|
"coverage": "vitest run --coverage",
|
|
42
42
|
"test-watch": "vitest",
|
|
43
|
-
"test": "
|
|
43
|
+
"test:build": "tsc -p .",
|
|
44
|
+
"test": "pnpm test:build && vitest run",
|
|
44
45
|
"test:perf": "insight --file \"dist/perf/**/*.perf.{mjs,js}\" -t 1000",
|
|
45
46
|
"test:perf:ts": "insight --register ts-node/esm --file \"src/perf/**/*.perf.{mts,ts}\" -t 1000",
|
|
46
47
|
"test:perf:prof": "NODE_ENV=production node --cpu-prof ../../node_modules/perf-insight/bin.mjs --file \"dist/perf/**/*.perf.{mjs,js}\" -t 1000",
|
|
@@ -57,5 +58,5 @@
|
|
|
57
58
|
"engines": {
|
|
58
59
|
"node": ">=18.0"
|
|
59
60
|
},
|
|
60
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "9a0d2b4584112b33d137faa98e9931ad4e7b6050"
|
|
61
62
|
}
|