@gjsify/url 0.3.12 → 0.3.14
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/lib/esm/index.js +435 -457
- package/package.json +4 -4
package/lib/esm/index.js
CHANGED
|
@@ -1,482 +1,460 @@
|
|
|
1
1
|
import GLib from "@girs/glib-2.0";
|
|
2
|
+
|
|
3
|
+
//#region src/index.ts
|
|
2
4
|
const PARSE_FLAGS = GLib.UriFlags.HAS_PASSWORD | GLib.UriFlags.ENCODED | GLib.UriFlags.SCHEME_NORMALIZE;
|
|
3
|
-
class URLSearchParams {
|
|
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
|
-
}
|
|
5
|
+
var URLSearchParams = class URLSearchParams {
|
|
6
|
+
_entries = [];
|
|
7
|
+
constructor(init) {
|
|
8
|
+
if (!init) return;
|
|
9
|
+
if (typeof init === "string") {
|
|
10
|
+
const s = init.startsWith("?") ? init.slice(1) : init;
|
|
11
|
+
if (s) {
|
|
12
|
+
for (const pair of s.split("&")) {
|
|
13
|
+
const eqIdx = pair.indexOf("=");
|
|
14
|
+
if (eqIdx === -1) {
|
|
15
|
+
this._entries.push([decodeComponent(pair), ""]);
|
|
16
|
+
} else {
|
|
17
|
+
this._entries.push([decodeComponent(pair.slice(0, eqIdx)), decodeComponent(pair.slice(eqIdx + 1))]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
} else if (Array.isArray(init)) {
|
|
22
|
+
for (const [k, v] of init) {
|
|
23
|
+
this._entries.push([String(k), String(v)]);
|
|
24
|
+
}
|
|
25
|
+
} else if (init instanceof URLSearchParams) {
|
|
26
|
+
this._entries = init._entries.map(([k, v]) => [k, v]);
|
|
27
|
+
} else {
|
|
28
|
+
for (const key of Object.keys(init)) {
|
|
29
|
+
this._entries.push([key, String(init[key])]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
get(name) {
|
|
34
|
+
for (const [k, v] of this._entries) {
|
|
35
|
+
if (k === name) return v;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
getAll(name) {
|
|
40
|
+
return this._entries.filter(([k]) => k === name).map(([, v]) => v);
|
|
41
|
+
}
|
|
42
|
+
set(name, value) {
|
|
43
|
+
let found = false;
|
|
44
|
+
this._entries = this._entries.filter(([k]) => {
|
|
45
|
+
if (k === name) {
|
|
46
|
+
if (!found) {
|
|
47
|
+
found = true;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
});
|
|
54
|
+
if (found) {
|
|
55
|
+
for (let i = 0; i < this._entries.length; i++) {
|
|
56
|
+
if (this._entries[i][0] === name) {
|
|
57
|
+
this._entries[i][1] = value;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
this._entries.push([name, value]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
has(name) {
|
|
66
|
+
return this._entries.some(([k]) => k === name);
|
|
67
|
+
}
|
|
68
|
+
delete(name) {
|
|
69
|
+
this._entries = this._entries.filter(([k]) => k !== name);
|
|
70
|
+
}
|
|
71
|
+
append(name, value) {
|
|
72
|
+
this._entries.push([name, value]);
|
|
73
|
+
}
|
|
74
|
+
sort() {
|
|
75
|
+
this._entries.sort((a, b) => {
|
|
76
|
+
if (a[0] < b[0]) return -1;
|
|
77
|
+
if (a[0] > b[0]) return 1;
|
|
78
|
+
return 0;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
toString() {
|
|
82
|
+
return this._entries.map(([k, v]) => encodeComponent(k) + "=" + encodeComponent(v)).join("&");
|
|
83
|
+
}
|
|
84
|
+
forEach(callback) {
|
|
85
|
+
for (const [k, v] of this._entries) {
|
|
86
|
+
callback(v, k, this);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
*entries() {
|
|
90
|
+
yield* this._entries;
|
|
91
|
+
}
|
|
92
|
+
*keys() {
|
|
93
|
+
for (const [k] of this._entries) yield k;
|
|
94
|
+
}
|
|
95
|
+
*values() {
|
|
96
|
+
for (const [, v] of this._entries) yield v;
|
|
97
|
+
}
|
|
98
|
+
[Symbol.iterator]() {
|
|
99
|
+
return this.entries();
|
|
100
|
+
}
|
|
101
|
+
get size() {
|
|
102
|
+
return this._entries.length;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
103
105
|
function decodeComponent(s) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
try {
|
|
107
|
+
return decodeURIComponent(s.replace(/\+/g, " "));
|
|
108
|
+
} catch {
|
|
109
|
+
return s;
|
|
110
|
+
}
|
|
109
111
|
}
|
|
110
112
|
function encodeComponent(s) {
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
class URL {
|
|
114
|
-
#uri;
|
|
115
|
-
// GLib.Uri
|
|
116
|
-
#searchParams;
|
|
117
|
-
constructor(url, base) {
|
|
118
|
-
const urlStr = url instanceof URL ? url.href : String(url);
|
|
119
|
-
try {
|
|
120
|
-
if (base !== void 0) {
|
|
121
|
-
const baseStr = base instanceof URL ? base.href : String(base);
|
|
122
|
-
const baseUri = GLib.Uri.parse(baseStr, PARSE_FLAGS);
|
|
123
|
-
this.#uri = baseUri.parse_relative(urlStr, PARSE_FLAGS);
|
|
124
|
-
} else {
|
|
125
|
-
this.#uri = GLib.Uri.parse(urlStr, PARSE_FLAGS);
|
|
126
|
-
}
|
|
127
|
-
} catch (e) {
|
|
128
|
-
throw new TypeError(`Invalid URL: ${urlStr}`);
|
|
129
|
-
}
|
|
130
|
-
if (!this.#uri) {
|
|
131
|
-
throw new TypeError(`Invalid URL: ${urlStr}`);
|
|
132
|
-
}
|
|
133
|
-
this.#searchParams = new URLSearchParams(this.#uri.get_query() || "");
|
|
134
|
-
}
|
|
135
|
-
get protocol() {
|
|
136
|
-
return this.#uri.get_scheme() + ":";
|
|
137
|
-
}
|
|
138
|
-
get hostname() {
|
|
139
|
-
return (this.#uri.get_host() || "").toLowerCase();
|
|
140
|
-
}
|
|
141
|
-
get port() {
|
|
142
|
-
const p = this.#uri.get_port();
|
|
143
|
-
if (p === -1) return "";
|
|
144
|
-
const scheme = this.#uri.get_scheme();
|
|
145
|
-
if ((scheme === "http" || scheme === "ws") && p === 80) return "";
|
|
146
|
-
if ((scheme === "https" || scheme === "wss") && p === 443) return "";
|
|
147
|
-
if (scheme === "ftp" && p === 21) return "";
|
|
148
|
-
return String(p);
|
|
149
|
-
}
|
|
150
|
-
get host() {
|
|
151
|
-
const hostname = this.hostname;
|
|
152
|
-
const port = this.port;
|
|
153
|
-
return port ? `${hostname}:${port}` : hostname;
|
|
154
|
-
}
|
|
155
|
-
get pathname() {
|
|
156
|
-
return this.#uri.get_path() || "/";
|
|
157
|
-
}
|
|
158
|
-
get search() {
|
|
159
|
-
const q = this.#uri.get_query();
|
|
160
|
-
return q ? "?" + q : "";
|
|
161
|
-
}
|
|
162
|
-
get hash() {
|
|
163
|
-
const f = this.#uri.get_fragment();
|
|
164
|
-
return f ? "#" + f : "";
|
|
165
|
-
}
|
|
166
|
-
get origin() {
|
|
167
|
-
const p = this.protocol;
|
|
168
|
-
if (p === "http:" || p === "https:" || p === "ftp:") {
|
|
169
|
-
return `${p}//${this.host}`;
|
|
170
|
-
}
|
|
171
|
-
return "null";
|
|
172
|
-
}
|
|
173
|
-
get username() {
|
|
174
|
-
return this.#uri.get_user() || "";
|
|
175
|
-
}
|
|
176
|
-
get password() {
|
|
177
|
-
return this.#uri.get_password() || "";
|
|
178
|
-
}
|
|
179
|
-
get href() {
|
|
180
|
-
let result = this.protocol;
|
|
181
|
-
const scheme = this.#uri.get_scheme();
|
|
182
|
-
const isSpecial = scheme === "http" || scheme === "https" || scheme === "ftp" || scheme === "file" || scheme === "ws" || scheme === "wss";
|
|
183
|
-
if (isSpecial || this.hostname) {
|
|
184
|
-
result += "//";
|
|
185
|
-
}
|
|
186
|
-
const user = this.username;
|
|
187
|
-
const pass = this.password;
|
|
188
|
-
if (user) {
|
|
189
|
-
result += user;
|
|
190
|
-
if (pass) result += ":" + pass;
|
|
191
|
-
result += "@";
|
|
192
|
-
}
|
|
193
|
-
result += this.hostname;
|
|
194
|
-
if (this.port) result += ":" + this.port;
|
|
195
|
-
const pathname = this.pathname;
|
|
196
|
-
result += pathname;
|
|
197
|
-
result += this.search;
|
|
198
|
-
result += this.hash;
|
|
199
|
-
return result;
|
|
200
|
-
}
|
|
201
|
-
get searchParams() {
|
|
202
|
-
return this.#searchParams;
|
|
203
|
-
}
|
|
204
|
-
toString() {
|
|
205
|
-
return this.href;
|
|
206
|
-
}
|
|
207
|
-
toJSON() {
|
|
208
|
-
return this.href;
|
|
209
|
-
}
|
|
210
|
-
// ---- URL.createObjectURL / URL.revokeObjectURL ----
|
|
211
|
-
//
|
|
212
|
-
// Consumers like Excalibur.js do `const src = URL.createObjectURL(blob);
|
|
213
|
-
// image.src = src;`. For that to work on GJS we need `src` to be a path
|
|
214
|
-
// `HTMLImageElement` / `HTMLAudioElement` / `FontFace` can actually read —
|
|
215
|
-
// i.e. a `file://` URL. We implement this as a static method on our own
|
|
216
|
-
// URL class (no globalThis monkey-patching):
|
|
217
|
-
//
|
|
218
|
-
// - Fast path: if the Blob already carries a `_tmpPath` (e.g. written
|
|
219
|
-
// by `@gjsify/fetch` XHR when `responseType='blob'`), wrap it as
|
|
220
|
-
// `file://<_tmpPath>`.
|
|
221
|
-
// - Slow path: if the Blob has `arrayBuffer()`/bytes but no `_tmpPath`,
|
|
222
|
-
// materialise the bytes into a GLib temp file and wrap that. This
|
|
223
|
-
// path is async in the spec — but W3C `createObjectURL` is sync. We
|
|
224
|
-
// read the bytes via `GLib.Bytes`-style synchronous access when
|
|
225
|
-
// possible and fall back to a sentinel if not.
|
|
226
|
-
//
|
|
227
|
-
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
|
|
228
|
-
static _objectURLPaths = /* @__PURE__ */ new Map();
|
|
229
|
-
static _objectURLCounter = 0;
|
|
230
|
-
static createObjectURL(blob) {
|
|
231
|
-
const tmp = blob?._tmpPath;
|
|
232
|
-
if (typeof tmp === "string" && tmp.length > 0) {
|
|
233
|
-
const url = `file://${tmp}`;
|
|
234
|
-
URL._objectURLPaths.set(url, tmp);
|
|
235
|
-
return url;
|
|
236
|
-
}
|
|
237
|
-
return "file:///dev/null";
|
|
238
|
-
}
|
|
239
|
-
static revokeObjectURL(url) {
|
|
240
|
-
const path = URL._objectURLPaths.get(url);
|
|
241
|
-
if (!path) return;
|
|
242
|
-
try {
|
|
243
|
-
GLib.unlink(path);
|
|
244
|
-
} catch {
|
|
245
|
-
}
|
|
246
|
-
URL._objectURLPaths.delete(url);
|
|
247
|
-
}
|
|
113
|
+
return encodeURIComponent(s).replace(/%20/g, "+");
|
|
248
114
|
}
|
|
115
|
+
var URL = class URL {
|
|
116
|
+
#uri;
|
|
117
|
+
#searchParams;
|
|
118
|
+
constructor(url, base) {
|
|
119
|
+
const urlStr = url instanceof URL ? url.href : String(url);
|
|
120
|
+
try {
|
|
121
|
+
if (base !== undefined) {
|
|
122
|
+
const baseStr = base instanceof URL ? base.href : String(base);
|
|
123
|
+
const baseUri = GLib.Uri.parse(baseStr, PARSE_FLAGS);
|
|
124
|
+
this.#uri = baseUri.parse_relative(urlStr, PARSE_FLAGS);
|
|
125
|
+
} else {
|
|
126
|
+
this.#uri = GLib.Uri.parse(urlStr, PARSE_FLAGS);
|
|
127
|
+
}
|
|
128
|
+
} catch (e) {
|
|
129
|
+
throw new TypeError(`Invalid URL: ${urlStr}`);
|
|
130
|
+
}
|
|
131
|
+
if (!this.#uri) {
|
|
132
|
+
throw new TypeError(`Invalid URL: ${urlStr}`);
|
|
133
|
+
}
|
|
134
|
+
this.#searchParams = new URLSearchParams(this.#uri.get_query() || "");
|
|
135
|
+
}
|
|
136
|
+
get protocol() {
|
|
137
|
+
return this.#uri.get_scheme() + ":";
|
|
138
|
+
}
|
|
139
|
+
get hostname() {
|
|
140
|
+
return (this.#uri.get_host() || "").toLowerCase();
|
|
141
|
+
}
|
|
142
|
+
get port() {
|
|
143
|
+
const p = this.#uri.get_port();
|
|
144
|
+
if (p === -1) return "";
|
|
145
|
+
const scheme = this.#uri.get_scheme();
|
|
146
|
+
if ((scheme === "http" || scheme === "ws") && p === 80) return "";
|
|
147
|
+
if ((scheme === "https" || scheme === "wss") && p === 443) return "";
|
|
148
|
+
if (scheme === "ftp" && p === 21) return "";
|
|
149
|
+
return String(p);
|
|
150
|
+
}
|
|
151
|
+
get host() {
|
|
152
|
+
const hostname = this.hostname;
|
|
153
|
+
const port = this.port;
|
|
154
|
+
return port ? `${hostname}:${port}` : hostname;
|
|
155
|
+
}
|
|
156
|
+
get pathname() {
|
|
157
|
+
return this.#uri.get_path() || "/";
|
|
158
|
+
}
|
|
159
|
+
get search() {
|
|
160
|
+
const q = this.#uri.get_query();
|
|
161
|
+
return q ? "?" + q : "";
|
|
162
|
+
}
|
|
163
|
+
get hash() {
|
|
164
|
+
const f = this.#uri.get_fragment();
|
|
165
|
+
return f ? "#" + f : "";
|
|
166
|
+
}
|
|
167
|
+
get origin() {
|
|
168
|
+
const p = this.protocol;
|
|
169
|
+
if (p === "http:" || p === "https:" || p === "ftp:") {
|
|
170
|
+
return `${p}//${this.host}`;
|
|
171
|
+
}
|
|
172
|
+
return "null";
|
|
173
|
+
}
|
|
174
|
+
get username() {
|
|
175
|
+
return this.#uri.get_user() || "";
|
|
176
|
+
}
|
|
177
|
+
get password() {
|
|
178
|
+
return this.#uri.get_password() || "";
|
|
179
|
+
}
|
|
180
|
+
get href() {
|
|
181
|
+
let result = this.protocol;
|
|
182
|
+
const scheme = this.#uri.get_scheme();
|
|
183
|
+
const isSpecial = scheme === "http" || scheme === "https" || scheme === "ftp" || scheme === "file" || scheme === "ws" || scheme === "wss";
|
|
184
|
+
if (isSpecial || this.hostname) {
|
|
185
|
+
result += "//";
|
|
186
|
+
}
|
|
187
|
+
const user = this.username;
|
|
188
|
+
const pass = this.password;
|
|
189
|
+
if (user) {
|
|
190
|
+
result += user;
|
|
191
|
+
if (pass) result += ":" + pass;
|
|
192
|
+
result += "@";
|
|
193
|
+
}
|
|
194
|
+
result += this.hostname;
|
|
195
|
+
if (this.port) result += ":" + this.port;
|
|
196
|
+
const pathname = this.pathname;
|
|
197
|
+
result += pathname;
|
|
198
|
+
result += this.search;
|
|
199
|
+
result += this.hash;
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
get searchParams() {
|
|
203
|
+
return this.#searchParams;
|
|
204
|
+
}
|
|
205
|
+
toString() {
|
|
206
|
+
return this.href;
|
|
207
|
+
}
|
|
208
|
+
toJSON() {
|
|
209
|
+
return this.href;
|
|
210
|
+
}
|
|
211
|
+
static _objectURLPaths = new Map();
|
|
212
|
+
static _objectURLCounter = 0;
|
|
213
|
+
static createObjectURL(blob) {
|
|
214
|
+
const tmp = blob?._tmpPath;
|
|
215
|
+
if (typeof tmp === "string" && tmp.length > 0) {
|
|
216
|
+
const url = `file://${tmp}`;
|
|
217
|
+
URL._objectURLPaths.set(url, tmp);
|
|
218
|
+
return url;
|
|
219
|
+
}
|
|
220
|
+
return "file:///dev/null";
|
|
221
|
+
}
|
|
222
|
+
static revokeObjectURL(url) {
|
|
223
|
+
const path = URL._objectURLPaths.get(url);
|
|
224
|
+
if (!path) return;
|
|
225
|
+
try {
|
|
226
|
+
GLib.unlink(path);
|
|
227
|
+
} catch {}
|
|
228
|
+
URL._objectURLPaths.delete(url);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
249
231
|
function parse(urlString, parseQueryString, slashesDenoteHost) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
232
|
+
if (typeof urlString !== "string") {
|
|
233
|
+
throw new TypeError("The \"url\" argument must be of type string. Received type " + typeof urlString);
|
|
234
|
+
}
|
|
235
|
+
const result = {
|
|
236
|
+
protocol: null,
|
|
237
|
+
slashes: null,
|
|
238
|
+
auth: null,
|
|
239
|
+
host: null,
|
|
240
|
+
port: null,
|
|
241
|
+
hostname: null,
|
|
242
|
+
hash: null,
|
|
243
|
+
search: null,
|
|
244
|
+
query: null,
|
|
245
|
+
pathname: null,
|
|
246
|
+
path: null,
|
|
247
|
+
href: urlString
|
|
248
|
+
};
|
|
249
|
+
let rest = urlString.trim();
|
|
250
|
+
const hashIdx = rest.indexOf("#");
|
|
251
|
+
if (hashIdx !== -1) {
|
|
252
|
+
result.hash = rest.slice(hashIdx);
|
|
253
|
+
rest = rest.slice(0, hashIdx);
|
|
254
|
+
}
|
|
255
|
+
const qIdx = rest.indexOf("?");
|
|
256
|
+
if (qIdx !== -1) {
|
|
257
|
+
result.search = rest.slice(qIdx);
|
|
258
|
+
result.query = parseQueryString ? Object.fromEntries(new URLSearchParams(rest.slice(qIdx + 1))) : rest.slice(qIdx + 1);
|
|
259
|
+
rest = rest.slice(0, qIdx);
|
|
260
|
+
}
|
|
261
|
+
const protoMatch = /^([a-z][a-z0-9.+-]*:)/i.exec(rest);
|
|
262
|
+
if (protoMatch) {
|
|
263
|
+
result.protocol = protoMatch[1].toLowerCase();
|
|
264
|
+
rest = rest.slice(result.protocol.length);
|
|
265
|
+
}
|
|
266
|
+
if (slashesDenoteHost || result.protocol) {
|
|
267
|
+
const hasSlashes = rest.startsWith("//");
|
|
268
|
+
if (hasSlashes) {
|
|
269
|
+
result.slashes = true;
|
|
270
|
+
rest = rest.slice(2);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (result.slashes || result.protocol && ![
|
|
274
|
+
"javascript:",
|
|
275
|
+
"data:",
|
|
276
|
+
"mailto:"
|
|
277
|
+
].includes(result.protocol)) {
|
|
278
|
+
let hostEnd = -1;
|
|
279
|
+
for (let i = 0; i < rest.length; i++) {
|
|
280
|
+
const ch = rest[i];
|
|
281
|
+
if (ch === "/" || ch === "\\") {
|
|
282
|
+
hostEnd = i;
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const hostPart = hostEnd === -1 ? rest : rest.slice(0, hostEnd);
|
|
287
|
+
rest = hostEnd === -1 ? "" : rest.slice(hostEnd);
|
|
288
|
+
const atIdx = hostPart.lastIndexOf("@");
|
|
289
|
+
if (atIdx !== -1) {
|
|
290
|
+
result.auth = decodeURIComponent(hostPart.slice(0, atIdx));
|
|
291
|
+
const hostWithPort = hostPart.slice(atIdx + 1);
|
|
292
|
+
parseHostPort(hostWithPort, result);
|
|
293
|
+
} else {
|
|
294
|
+
parseHostPort(hostPart, result);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
result.pathname = rest || (result.slashes ? "/" : null);
|
|
298
|
+
if (result.pathname !== null || result.search !== null) {
|
|
299
|
+
result.path = (result.pathname || "") + (result.search || "");
|
|
300
|
+
}
|
|
301
|
+
result.href = format(result);
|
|
302
|
+
return result;
|
|
317
303
|
}
|
|
318
304
|
function parseHostPort(hostPart, result) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
305
|
+
if (!hostPart) return;
|
|
306
|
+
const bracketIdx = hostPart.indexOf("[");
|
|
307
|
+
if (bracketIdx !== -1) {
|
|
308
|
+
const bracketEnd = hostPart.indexOf("]", bracketIdx);
|
|
309
|
+
if (bracketEnd !== -1) {
|
|
310
|
+
const portStr = hostPart.slice(bracketEnd + 1);
|
|
311
|
+
if (portStr.startsWith(":")) {
|
|
312
|
+
result.port = portStr.slice(1);
|
|
313
|
+
}
|
|
314
|
+
result.hostname = hostPart.slice(bracketIdx, bracketEnd + 1);
|
|
315
|
+
result.host = result.hostname + (result.port ? ":" + result.port : "");
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const colonIdx = hostPart.lastIndexOf(":");
|
|
320
|
+
if (colonIdx !== -1) {
|
|
321
|
+
const portCandidate = hostPart.slice(colonIdx + 1);
|
|
322
|
+
if (/^\d*$/.test(portCandidate)) {
|
|
323
|
+
result.port = portCandidate || null;
|
|
324
|
+
result.hostname = hostPart.slice(0, colonIdx).toLowerCase();
|
|
325
|
+
} else {
|
|
326
|
+
result.hostname = hostPart.toLowerCase();
|
|
327
|
+
}
|
|
328
|
+
} else {
|
|
329
|
+
result.hostname = hostPart.toLowerCase();
|
|
330
|
+
}
|
|
331
|
+
result.host = result.hostname + (result.port ? ":" + result.port : "");
|
|
346
332
|
}
|
|
347
333
|
function format(urlObject) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
334
|
+
if (typeof urlObject === "string") {
|
|
335
|
+
return urlObject;
|
|
336
|
+
}
|
|
337
|
+
if (urlObject instanceof URL) {
|
|
338
|
+
return urlObject.href;
|
|
339
|
+
}
|
|
340
|
+
const obj = urlObject;
|
|
341
|
+
let result = "";
|
|
342
|
+
if (obj.protocol) {
|
|
343
|
+
result += obj.protocol;
|
|
344
|
+
}
|
|
345
|
+
if (obj.slashes || obj.protocol && ![
|
|
346
|
+
"javascript:",
|
|
347
|
+
"data:",
|
|
348
|
+
"mailto:"
|
|
349
|
+
].includes(obj.protocol || "")) {
|
|
350
|
+
result += "//";
|
|
351
|
+
}
|
|
352
|
+
if (obj.auth) {
|
|
353
|
+
result += encodeURIComponent(obj.auth) + "@";
|
|
354
|
+
}
|
|
355
|
+
if (obj.host) {
|
|
356
|
+
result += obj.host;
|
|
357
|
+
} else {
|
|
358
|
+
if (obj.hostname) {
|
|
359
|
+
result += obj.hostname;
|
|
360
|
+
}
|
|
361
|
+
if (obj.port) {
|
|
362
|
+
result += ":" + obj.port;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (obj.pathname) {
|
|
366
|
+
result += obj.pathname;
|
|
367
|
+
}
|
|
368
|
+
if (obj.search) {
|
|
369
|
+
result += obj.search;
|
|
370
|
+
} else if (obj.query && typeof obj.query === "object") {
|
|
371
|
+
const qs = new URLSearchParams(obj.query).toString();
|
|
372
|
+
if (qs) result += "?" + qs;
|
|
373
|
+
}
|
|
374
|
+
if (obj.hash) {
|
|
375
|
+
result += obj.hash;
|
|
376
|
+
}
|
|
377
|
+
return result;
|
|
388
378
|
}
|
|
389
379
|
function resolve(from, to) {
|
|
390
|
-
|
|
380
|
+
return new URL(to, new URL(from, "resolve://")).href.replace(/^resolve:\/\//, "");
|
|
391
381
|
}
|
|
392
382
|
function fileURLToPath(url) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
return decodeURIComponent(pathname);
|
|
383
|
+
if (typeof url === "string") {
|
|
384
|
+
url = new URL(url);
|
|
385
|
+
}
|
|
386
|
+
if (!(url instanceof URL)) {
|
|
387
|
+
throw new TypeError("The \"url\" argument must be of type string or URL. Received type " + typeof url);
|
|
388
|
+
}
|
|
389
|
+
if (url.protocol !== "file:") {
|
|
390
|
+
throw new TypeError("The URL must be of scheme file");
|
|
391
|
+
}
|
|
392
|
+
if (url.hostname !== "" && url.hostname !== "localhost") {
|
|
393
|
+
throw new TypeError(`File URL host must be "localhost" or empty on linux`);
|
|
394
|
+
}
|
|
395
|
+
const pathname = url.pathname;
|
|
396
|
+
for (let i = 0; i < pathname.length; i++) {
|
|
397
|
+
if (pathname[i] === "%") {
|
|
398
|
+
const third = pathname.codePointAt(i + 2) | 32;
|
|
399
|
+
if (pathname[i + 1] === "2" && third === 102) {
|
|
400
|
+
throw new TypeError("File URL path must not include encoded / characters");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return decodeURIComponent(pathname);
|
|
417
405
|
}
|
|
418
406
|
function pathToFileURL(filepath) {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
return new URL("file://" + encodePathForURL(resolved));
|
|
407
|
+
let resolved = filepath;
|
|
408
|
+
if (filepath[0] !== "/") {
|
|
409
|
+
if (typeof globalThis.process?.cwd === "function") {
|
|
410
|
+
resolved = globalThis.process.cwd() + "/" + filepath;
|
|
411
|
+
} else {
|
|
412
|
+
try {
|
|
413
|
+
if (GLib?.get_current_dir) {
|
|
414
|
+
resolved = GLib.get_current_dir() + "/" + filepath;
|
|
415
|
+
}
|
|
416
|
+
} catch {}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return new URL("file://" + encodePathForURL(resolved));
|
|
433
420
|
}
|
|
434
421
|
function encodePathForURL(filepath) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
422
|
+
let result = "";
|
|
423
|
+
for (let i = 0; i < filepath.length; i++) {
|
|
424
|
+
const ch = filepath[i];
|
|
425
|
+
if (ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch >= "0" && ch <= "9" || ch === "/" || ch === "-" || ch === "_" || ch === "." || ch === "~" || ch === ":" || ch === "@" || ch === "!") {
|
|
426
|
+
result += ch;
|
|
427
|
+
} else {
|
|
428
|
+
result += encodeURIComponent(ch);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return result;
|
|
445
432
|
}
|
|
446
433
|
function domainToASCII(domain) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
434
|
+
try {
|
|
435
|
+
return new URL(`http://${domain}`).hostname;
|
|
436
|
+
} catch {
|
|
437
|
+
return "";
|
|
438
|
+
}
|
|
452
439
|
}
|
|
453
440
|
function domainToUnicode(domain) {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
441
|
+
try {
|
|
442
|
+
return new URL(`http://${domain}`).hostname;
|
|
443
|
+
} catch {
|
|
444
|
+
return "";
|
|
445
|
+
}
|
|
459
446
|
}
|
|
460
|
-
var
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
};
|
|
471
|
-
export {
|
|
472
|
-
URL,
|
|
473
|
-
URLSearchParams,
|
|
474
|
-
index_default as default,
|
|
475
|
-
domainToASCII,
|
|
476
|
-
domainToUnicode,
|
|
477
|
-
fileURLToPath,
|
|
478
|
-
format,
|
|
479
|
-
parse,
|
|
480
|
-
pathToFileURL,
|
|
481
|
-
resolve
|
|
447
|
+
var src_default = {
|
|
448
|
+
URL,
|
|
449
|
+
URLSearchParams,
|
|
450
|
+
parse,
|
|
451
|
+
format,
|
|
452
|
+
resolve,
|
|
453
|
+
fileURLToPath,
|
|
454
|
+
pathToFileURL,
|
|
455
|
+
domainToASCII,
|
|
456
|
+
domainToUnicode
|
|
482
457
|
};
|
|
458
|
+
|
|
459
|
+
//#endregion
|
|
460
|
+
export { URL, URLSearchParams, src_default as default, domainToASCII, domainToUnicode, fileURLToPath, format, parse, pathToFileURL, resolve };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/url",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
4
4
|
"description": "Node.js url module for Gjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"fs"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@girs/glib-2.0": "
|
|
33
|
+
"@girs/glib-2.0": "2.88.0-4.0.0-rc.9"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@gjsify/cli": "^0.3.
|
|
37
|
-
"@gjsify/unit": "^0.3.
|
|
36
|
+
"@gjsify/cli": "^0.3.14",
|
|
37
|
+
"@gjsify/unit": "^0.3.14",
|
|
38
38
|
"@types/node": "^25.6.0",
|
|
39
39
|
"typescript": "^6.0.3"
|
|
40
40
|
}
|