@serveryyswys/node.operit 0.0.0-stage → 0.1.2
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/BUILTINS.json +233 -0
- package/DESIGN.md +513 -0
- package/LICENSE +674 -0
- package/README.md +301 -2
- package/dist/assert/strict.d.ts +2 -0
- package/dist/assert/strict.js +7 -0
- package/dist/assert.d.ts +3 -0
- package/dist/assert.js +483 -0
- package/dist/buffer.d.ts +60 -0
- package/dist/buffer.js +524 -0
- package/dist/child_process.d.ts +56 -0
- package/dist/child_process.js +371 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +19 -0
- package/dist/crypto.d.ts +76 -0
- package/dist/crypto.js +312 -0
- package/dist/dns/promises.d.ts +34 -0
- package/dist/dns/promises.js +190 -0
- package/dist/dns.d.ts +88 -0
- package/dist/dns.js +259 -0
- package/dist/events.d.ts +40 -0
- package/dist/events.js +237 -0
- package/dist/fs/promises.d.ts +159 -0
- package/dist/fs/promises.js +129 -0
- package/dist/fs.d.ts +221 -0
- package/dist/fs.js +944 -0
- package/dist/http.d.ts +92 -0
- package/dist/http.js +319 -0
- package/dist/https.d.ts +296 -0
- package/dist/https.js +50 -0
- package/dist/index.d.ts +2422 -0
- package/dist/index.js +57 -0
- package/dist/lib/bridge.d.ts +60 -0
- package/dist/lib/bridge.js +205 -0
- package/dist/lib/bytes.d.ts +20 -0
- package/dist/lib/bytes.js +239 -0
- package/dist/lib/child-process-types.d.ts +45 -0
- package/dist/lib/child-process-types.js +2 -0
- package/dist/lib/cwd.d.ts +2 -0
- package/dist/lib/cwd.js +32 -0
- package/dist/lib/deep-equal.d.ts +3 -0
- package/dist/lib/deep-equal.js +223 -0
- package/dist/lib/deflate.d.ts +2 -0
- package/dist/lib/deflate.js +234 -0
- package/dist/lib/dns-driver.d.ts +14 -0
- package/dist/lib/dns-driver.js +85 -0
- package/dist/lib/dns-types.d.ts +22 -0
- package/dist/lib/dns-types.js +2 -0
- package/dist/lib/errors.d.ts +48 -0
- package/dist/lib/errors.js +424 -0
- package/dist/lib/fs-driver.d.ts +70 -0
- package/dist/lib/fs-driver.js +364 -0
- package/dist/lib/fs-env.d.ts +30 -0
- package/dist/lib/fs-env.js +157 -0
- package/dist/lib/fs-types.d.ts +19 -0
- package/dist/lib/fs-types.js +2 -0
- package/dist/lib/hashes.d.ts +27 -0
- package/dist/lib/hashes.js +432 -0
- package/dist/lib/http-driver.d.ts +30 -0
- package/dist/lib/http-driver.js +72 -0
- package/dist/lib/http-types.d.ts +18 -0
- package/dist/lib/http-types.js +2 -0
- package/dist/lib/inflate.d.ts +6 -0
- package/dist/lib/inflate.js +284 -0
- package/dist/lib/path-types.d.ts +37 -0
- package/dist/lib/path-types.js +2 -0
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +106 -0
- package/dist/lib/perf-hooks-types.d.ts +18 -0
- package/dist/lib/perf-hooks-types.js +2 -0
- package/dist/lib/process-driver.d.ts +31 -0
- package/dist/lib/process-driver.js +102 -0
- package/dist/lib/punycode.d.ts +8 -0
- package/dist/lib/punycode.js +179 -0
- package/dist/lib/stream-types.d.ts +29 -0
- package/dist/lib/stream-types.js +2 -0
- package/dist/lib/timers-types.d.ts +18 -0
- package/dist/lib/timers-types.js +2 -0
- package/dist/lib/url-search-params.d.ts +26 -0
- package/dist/lib/url-search-params.js +281 -0
- package/dist/lib/url-types.d.ts +44 -0
- package/dist/lib/url-types.js +2 -0
- package/dist/lib/url-whatwg.d.ts +78 -0
- package/dist/lib/url-whatwg.js +857 -0
- package/dist/lib/zlib-types.d.ts +12 -0
- package/dist/lib/zlib-types.js +2 -0
- package/dist/module.d.ts +8 -0
- package/dist/module.js +72 -0
- package/dist/os.d.ts +80 -0
- package/dist/os.js +247 -0
- package/dist/path/posix.d.ts +2 -0
- package/dist/path/posix.js +7 -0
- package/dist/path/win32.d.ts +2 -0
- package/dist/path/win32.js +10 -0
- package/dist/path.d.ts +3 -0
- package/dist/path.js +1222 -0
- package/dist/perf_hooks.d.ts +36 -0
- package/dist/perf_hooks.js +144 -0
- package/dist/process.d.ts +69 -0
- package/dist/process.js +230 -0
- package/dist/querystring.d.ts +15 -0
- package/dist/querystring.js +209 -0
- package/dist/stream/promises.d.ts +5 -0
- package/dist/stream/promises.js +10 -0
- package/dist/stream.d.ts +84 -0
- package/dist/stream.js +875 -0
- package/dist/string_decoder.d.ts +15 -0
- package/dist/string_decoder.js +237 -0
- package/dist/timers/promises.d.ts +19 -0
- package/dist/timers/promises.js +74 -0
- package/dist/timers.d.ts +21 -0
- package/dist/timers.js +41 -0
- package/dist/tty.d.ts +9 -0
- package/dist/tty.js +25 -0
- package/dist/unsupported.d.ts +12 -0
- package/dist/unsupported.js +17 -0
- package/dist/url.d.ts +28 -0
- package/dist/url.js +486 -0
- package/dist/util.d.ts +74 -0
- package/dist/util.js +515 -0
- package/dist/zlib.d.ts +88 -0
- package/dist/zlib.js +371 -0
- package/package.json +29 -4
package/dist/url.js
ADDED
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
/**
|
|
36
|
+
* Node url 模块的移植。
|
|
37
|
+
*
|
|
38
|
+
* 本轮覆盖:
|
|
39
|
+
* - URLSearchParams(完整)
|
|
40
|
+
* - 旧版 parse / format / resolve
|
|
41
|
+
* - pathToFileURL / fileURLToPath
|
|
42
|
+
* - domainToASCII / domainToUnicode
|
|
43
|
+
*
|
|
44
|
+
* **未覆盖:WHATWG 的 URL 类与 urlToHttpOptions**(见 BUILTINS.json 的说明)。
|
|
45
|
+
* 那是一个完整的 RFC 3986 状态机,单独一轮做;在它到位之前,
|
|
46
|
+
* 需要 `new URL(...)` 的代码应当直接用旧版 parse 或自行拼接。
|
|
47
|
+
*
|
|
48
|
+
* 旧版 parse 有几条反直觉的规则,都是实测 Node 得出来的,实现里都注明了:
|
|
49
|
+
* - 按「协议是不是 slashed 协议」分派:http:example.com 不当主机,a:b 当主机;
|
|
50
|
+
* - file: 输出 href 时无条件带 '//'(file:host -> file://host),其它 slashed 协议要有主机才带;
|
|
51
|
+
* - parse(..., true) 在没有查询串时给的是空对象(无原型),不是 null。
|
|
52
|
+
*
|
|
53
|
+
* 平台:本库面向 Android,pathToFileURL / fileURLToPath 实现的是 **POSIX** 规则
|
|
54
|
+
* (与 Node 在 Linux 上的行为一致)。Node 在 Windows 上会给出 C:\ 风格的结果,
|
|
55
|
+
* 那是平台差异,不是分歧。
|
|
56
|
+
*/
|
|
57
|
+
const punycode = __importStar(require("./lib/punycode"));
|
|
58
|
+
const url_search_params_1 = require("./lib/url-search-params");
|
|
59
|
+
const url_whatwg_1 = require("./lib/url-whatwg");
|
|
60
|
+
const bytes_1 = require("./lib/bytes");
|
|
61
|
+
// ------------------------------------------------------------------ 旧版 parse
|
|
62
|
+
/** Node 的 autoEscape:把不在保留集里的字符按 UTF-8 百分号编码。 */
|
|
63
|
+
const URL_SAFE = /^[A-Za-z0-9\-._~!$&'()*+,;=:@/?#[\]%]$/;
|
|
64
|
+
/**
|
|
65
|
+
* Node 旧版解析按"协议是不是 slashed 协议"分派:
|
|
66
|
+
* - slashed 协议(http/https/...)后面没有 // 就**不当主机**(http:example.com 的 pathname 是 example.com);
|
|
67
|
+
* - 其它协议(a:b、mailto:...)后面整段当主机解析。
|
|
68
|
+
* 补 '/' 的默认 pathname 也只对 slashed 协议生效。
|
|
69
|
+
*/
|
|
70
|
+
function isSlashedProtocol(protocol) {
|
|
71
|
+
if (protocol === null) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const bare = protocol.charAt(protocol.length - 1) === ':'
|
|
75
|
+
? protocol.slice(0, protocol.length - 1)
|
|
76
|
+
: protocol;
|
|
77
|
+
return SLASHED_PROTOCOLS.has(bare);
|
|
78
|
+
}
|
|
79
|
+
function autoEscape(value) {
|
|
80
|
+
let out = '';
|
|
81
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
82
|
+
const character = value.charAt(i);
|
|
83
|
+
if (URL_SAFE.test(character)) {
|
|
84
|
+
out += character;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const bytes = (0, bytes_1.utf8Encode)(character);
|
|
88
|
+
for (let j = 0; j < bytes.length; j += 1) {
|
|
89
|
+
out += (0, url_search_params_1.hexByte)(bytes[j]);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
function splitHostPort(hostPart) {
|
|
96
|
+
if (hostPart.charAt(0) === '[') {
|
|
97
|
+
const close = hostPart.indexOf(']');
|
|
98
|
+
if (close >= 0) {
|
|
99
|
+
const inside = hostPart.slice(1, close);
|
|
100
|
+
const after = hostPart.slice(close + 1);
|
|
101
|
+
if (after.charAt(0) === ':') {
|
|
102
|
+
const port = after.slice(1);
|
|
103
|
+
return { hostname: inside, port: port === '' ? null : port, isIPv6: true };
|
|
104
|
+
}
|
|
105
|
+
return { hostname: inside, port: null, isIPv6: true };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const colon = hostPart.lastIndexOf(':');
|
|
109
|
+
if (colon < 0) {
|
|
110
|
+
return { hostname: hostPart, port: null, isIPv6: false };
|
|
111
|
+
}
|
|
112
|
+
const port = hostPart.slice(colon + 1);
|
|
113
|
+
// 空端口(http://host:/x)要丢掉,与 Node 一致
|
|
114
|
+
return { hostname: hostPart.slice(0, colon), port: port === '' ? null : port, isIPv6: false };
|
|
115
|
+
}
|
|
116
|
+
function parseUrl(input, parseQueryString, slashesDenoteHost) {
|
|
117
|
+
const result = {
|
|
118
|
+
protocol: null,
|
|
119
|
+
slashes: null,
|
|
120
|
+
auth: null,
|
|
121
|
+
host: null,
|
|
122
|
+
port: null,
|
|
123
|
+
hostname: null,
|
|
124
|
+
hash: null,
|
|
125
|
+
search: null,
|
|
126
|
+
query: null,
|
|
127
|
+
pathname: null,
|
|
128
|
+
path: null,
|
|
129
|
+
href: ''
|
|
130
|
+
};
|
|
131
|
+
const slashesHost = slashesDenoteHost === true;
|
|
132
|
+
let rest = input;
|
|
133
|
+
const protocolMatch = /^([a-z0-9.+-]+:)/i.exec(rest);
|
|
134
|
+
if (protocolMatch !== null) {
|
|
135
|
+
result.protocol = protocolMatch[1].toLowerCase();
|
|
136
|
+
rest = rest.slice(protocolMatch[1].length);
|
|
137
|
+
}
|
|
138
|
+
let hasHost = false;
|
|
139
|
+
if (rest.slice(0, 2) === '//' && (result.protocol !== null || slashesHost)) {
|
|
140
|
+
result.slashes = true;
|
|
141
|
+
rest = rest.slice(2);
|
|
142
|
+
hasHost = true;
|
|
143
|
+
}
|
|
144
|
+
else if (result.protocol !== null && !isSlashedProtocol(result.protocol)) {
|
|
145
|
+
// 非 slashed 协议即使没有 // 也按主机解析:a:b 的 host 是 'b',
|
|
146
|
+
// mailto:someone@example.com 的 host 是 'example.com'(auth 是 someone)
|
|
147
|
+
hasHost = true;
|
|
148
|
+
}
|
|
149
|
+
if (hasHost) {
|
|
150
|
+
let end = rest.length;
|
|
151
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
152
|
+
const character = rest.charAt(i);
|
|
153
|
+
if (character === '/' || character === '?' || character === '#') {
|
|
154
|
+
end = i;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
let hostPart = rest.slice(0, end);
|
|
159
|
+
rest = rest.slice(end);
|
|
160
|
+
const at = hostPart.lastIndexOf('@');
|
|
161
|
+
if (at >= 0) {
|
|
162
|
+
result.auth = safeDecode(hostPart.slice(0, at));
|
|
163
|
+
hostPart = hostPart.slice(at + 1);
|
|
164
|
+
}
|
|
165
|
+
hostPart = hostPart.toLowerCase();
|
|
166
|
+
const split = splitHostPort(hostPart);
|
|
167
|
+
const asciiHostname = split.hostname === '' ? '' : punycode.toASCII(split.hostname);
|
|
168
|
+
result.hostname = asciiHostname;
|
|
169
|
+
result.port = split.port;
|
|
170
|
+
// host 是「主机 + 非空端口」;IPv6 要带回方括号
|
|
171
|
+
const display = split.isIPv6 ? '[' + asciiHostname + ']' : asciiHostname;
|
|
172
|
+
result.host = split.port === null ? display : display + ':' + split.port;
|
|
173
|
+
}
|
|
174
|
+
// 拆 hash
|
|
175
|
+
const hashAt = rest.indexOf('#');
|
|
176
|
+
if (hashAt >= 0) {
|
|
177
|
+
// hash 也要转义(Node 会用 autoEscape 处理片段)
|
|
178
|
+
result.hash = '#' + autoEscape(rest.slice(hashAt + 1));
|
|
179
|
+
rest = rest.slice(0, hashAt);
|
|
180
|
+
}
|
|
181
|
+
// 拆 search
|
|
182
|
+
const searchAt = rest.indexOf('?');
|
|
183
|
+
if (searchAt >= 0) {
|
|
184
|
+
result.search = '?' + autoEscape(rest.slice(searchAt + 1));
|
|
185
|
+
rest = rest.slice(0, searchAt);
|
|
186
|
+
}
|
|
187
|
+
if (rest !== '') {
|
|
188
|
+
result.pathname = autoEscape(rest);
|
|
189
|
+
}
|
|
190
|
+
else if (hasHost && result.host !== '' && isSlashedProtocol(result.protocol)) {
|
|
191
|
+
// 补 '/' 需要:主机非空、且协议是 slashed 协议。
|
|
192
|
+
// 所以 http:// 的 pathname 是 null,foo://bar 的也是 null。
|
|
193
|
+
result.pathname = '/';
|
|
194
|
+
}
|
|
195
|
+
result.path = result.pathname === null && result.search === null
|
|
196
|
+
? null
|
|
197
|
+
: (result.pathname === null ? '' : result.pathname) + (result.search === null ? '' : result.search);
|
|
198
|
+
if (parseQueryString === true) {
|
|
199
|
+
// 即使没有查询串,Node 也会给一个空的(无原型)对象,而不是 null
|
|
200
|
+
result.query = buildQueryObject(result.search === null ? '' : result.search.slice(1));
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
result.query = result.search === null ? null : result.search.slice(1);
|
|
204
|
+
}
|
|
205
|
+
result.href = buildHref(result);
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
function safeDecode(value) {
|
|
209
|
+
try {
|
|
210
|
+
return decodeURIComponent(value);
|
|
211
|
+
}
|
|
212
|
+
catch (failure) {
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function buildQueryObject(search) {
|
|
217
|
+
const object = Object.create(null);
|
|
218
|
+
const params = new url_search_params_1.URLSearchParams(search);
|
|
219
|
+
for (const pair of params.entries()) {
|
|
220
|
+
const existing = object[pair[0]];
|
|
221
|
+
if (existing === undefined) {
|
|
222
|
+
object[pair[0]] = pair[1];
|
|
223
|
+
}
|
|
224
|
+
else if (Array.isArray(existing)) {
|
|
225
|
+
existing.push(pair[1]);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
object[pair[0]] = [existing, pair[1]];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return object;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* 是否输出 '//'。实测 Node 的规则:
|
|
235
|
+
* - slashes 为真 -> 输出;
|
|
236
|
+
* - file: 协议**无条件**输出(url.format({protocol:'file:',pathname:'host'}) 得到 file://host);
|
|
237
|
+
* - 其它 slashed 协议要有主机才输出(http:example.com 不带 //,http://h 带);
|
|
238
|
+
* - 没有协议时不输出({hostname:'h',pathname:'/p'} 得到 h/p)。
|
|
239
|
+
*/
|
|
240
|
+
function shouldUseSlashes(protocol, slashes, hasHost) {
|
|
241
|
+
if (slashes === true) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
if (protocol === null || protocol === '') {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
const bare = protocol.charAt(protocol.length - 1) === ':'
|
|
248
|
+
? protocol.slice(0, protocol.length - 1)
|
|
249
|
+
: protocol;
|
|
250
|
+
if (bare === 'file') {
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
return SLASHED_PROTOCOLS.has(bare) && hasHost;
|
|
254
|
+
}
|
|
255
|
+
function buildHref(parsed) {
|
|
256
|
+
let out = parsed.protocol === null ? '' : parsed.protocol;
|
|
257
|
+
if (shouldUseSlashes(parsed.protocol, parsed.slashes, parsed.host !== null && parsed.host !== '')) {
|
|
258
|
+
out += '//';
|
|
259
|
+
}
|
|
260
|
+
if (parsed.auth !== null && parsed.auth !== '') {
|
|
261
|
+
out += parsed.auth + '@';
|
|
262
|
+
}
|
|
263
|
+
if (parsed.host !== null) {
|
|
264
|
+
out += parsed.host;
|
|
265
|
+
}
|
|
266
|
+
if (parsed.path !== null) {
|
|
267
|
+
out += parsed.path;
|
|
268
|
+
}
|
|
269
|
+
if (parsed.hash !== null) {
|
|
270
|
+
out += parsed.hash;
|
|
271
|
+
}
|
|
272
|
+
return out;
|
|
273
|
+
}
|
|
274
|
+
// ------------------------------------------------------------------ format / resolve
|
|
275
|
+
const SLASHED_PROTOCOLS = new Set(['http', 'https', 'ftp', 'gopher', 'file', 'ws', 'wss']);
|
|
276
|
+
function stringifyQuery(query) {
|
|
277
|
+
const parts = [];
|
|
278
|
+
const keys = Object.keys(query);
|
|
279
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
280
|
+
const value = query[keys[i]];
|
|
281
|
+
if (Array.isArray(value)) {
|
|
282
|
+
for (let j = 0; j < value.length; j += 1) {
|
|
283
|
+
parts.push((0, url_search_params_1.formSerialize)(keys[i]) + '=' + (0, url_search_params_1.formSerialize)(String(value[j])));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
parts.push((0, url_search_params_1.formSerialize)(keys[i]) + '=' + (0, url_search_params_1.formSerialize)(String(value)));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return parts.join('&');
|
|
291
|
+
}
|
|
292
|
+
function formatUrl(source) {
|
|
293
|
+
const object = (source === undefined || source === null ? {} : source);
|
|
294
|
+
let auth = object.auth === undefined || object.auth === null ? '' : String(object.auth);
|
|
295
|
+
if (auth !== '') {
|
|
296
|
+
// Node:auth 里的 ':' 保留,其余按组件编码
|
|
297
|
+
auth = autoEscape(auth).replace(/%3A/gi, ':') + '@';
|
|
298
|
+
}
|
|
299
|
+
let protocol = object.protocol === undefined || object.protocol === null ? '' : String(object.protocol);
|
|
300
|
+
const pathname = object.pathname === undefined || object.pathname === null ? '' : String(object.pathname);
|
|
301
|
+
let hash = object.hash === undefined || object.hash === null ? '' : String(object.hash);
|
|
302
|
+
let host = false;
|
|
303
|
+
if (object.host !== undefined && object.host !== null && String(object.host) !== '') {
|
|
304
|
+
host = auth + String(object.host);
|
|
305
|
+
}
|
|
306
|
+
else if (object.hostname !== undefined && object.hostname !== null && String(object.hostname) !== '') {
|
|
307
|
+
const hostname = String(object.hostname);
|
|
308
|
+
const bracketed = hostname.indexOf(':') >= 0 && hostname.charAt(0) !== '[' ? '[' + hostname + ']' : hostname;
|
|
309
|
+
host = auth + bracketed;
|
|
310
|
+
if (object.port !== undefined && object.port !== null && String(object.port) !== '') {
|
|
311
|
+
host += ':' + String(object.port);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
let search = object.search === undefined || object.search === null ? '' : String(object.search);
|
|
315
|
+
if (search === '' && object.query !== null && object.query !== undefined && typeof object.query === 'object') {
|
|
316
|
+
const serialized = stringifyQuery(object.query);
|
|
317
|
+
search = serialized === '' ? '' : '?' + serialized;
|
|
318
|
+
}
|
|
319
|
+
if (protocol !== '' && protocol.charAt(protocol.length - 1) !== ':') {
|
|
320
|
+
protocol += ':';
|
|
321
|
+
}
|
|
322
|
+
const bare = protocol.slice(0, protocol.length - 1);
|
|
323
|
+
let outHost = host === false ? '' : host;
|
|
324
|
+
if (shouldUseSlashes(bare === '' ? null : bare, object.slashes === true ? true : null, host !== false)) {
|
|
325
|
+
outHost = '//' + outHost;
|
|
326
|
+
}
|
|
327
|
+
if (hash !== '' && hash.charAt(0) !== '#') {
|
|
328
|
+
hash = '#' + hash;
|
|
329
|
+
}
|
|
330
|
+
if (search !== '' && search.charAt(0) !== '?') {
|
|
331
|
+
search = '?' + search;
|
|
332
|
+
}
|
|
333
|
+
return protocol + outHost + pathname + search + hash;
|
|
334
|
+
}
|
|
335
|
+
/** 旧版解析出来的 path 段(用于 resolve 的路径合并)。 */
|
|
336
|
+
function resolvePath(fromPathname, toPathname) {
|
|
337
|
+
if (toPathname === '') {
|
|
338
|
+
return fromPathname;
|
|
339
|
+
}
|
|
340
|
+
if (toPathname.charAt(0) === '/') {
|
|
341
|
+
return toPathname;
|
|
342
|
+
}
|
|
343
|
+
const base = fromPathname.slice(0, fromPathname.lastIndexOf('/') + 1);
|
|
344
|
+
const joined = base + toPathname;
|
|
345
|
+
const segments = joined.split('/');
|
|
346
|
+
const out = [];
|
|
347
|
+
for (let i = 0; i < segments.length; i += 1) {
|
|
348
|
+
const segment = segments[i];
|
|
349
|
+
if (segment === '.') {
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
if (segment === '..') {
|
|
353
|
+
if (out.length > 1) {
|
|
354
|
+
out.pop();
|
|
355
|
+
}
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
out.push(segment);
|
|
359
|
+
}
|
|
360
|
+
return out.join('/');
|
|
361
|
+
}
|
|
362
|
+
function resolveUrl(from, to) {
|
|
363
|
+
const toText = String(to);
|
|
364
|
+
// '//host/path' 是协议相对引用:要按主机解析,再继承 base 的协议
|
|
365
|
+
const target = parseUrl(toText, false, toText.slice(0, 2) === '//');
|
|
366
|
+
const base = parseUrl(String(from));
|
|
367
|
+
if (target.protocol !== null || target.host !== null) {
|
|
368
|
+
const replacement = {
|
|
369
|
+
protocol: target.protocol === null ? base.protocol : target.protocol,
|
|
370
|
+
slashes: target.slashes,
|
|
371
|
+
auth: target.auth,
|
|
372
|
+
host: target.host,
|
|
373
|
+
port: target.port,
|
|
374
|
+
hostname: target.hostname,
|
|
375
|
+
hash: target.hash,
|
|
376
|
+
search: target.search,
|
|
377
|
+
query: target.query,
|
|
378
|
+
pathname: target.pathname,
|
|
379
|
+
path: null,
|
|
380
|
+
href: ''
|
|
381
|
+
};
|
|
382
|
+
if (replacement.pathname === null && replacement.host !== null && replacement.host !== '') {
|
|
383
|
+
replacement.pathname = '/';
|
|
384
|
+
}
|
|
385
|
+
replacement.path = (replacement.pathname === null ? '' : replacement.pathname) +
|
|
386
|
+
(replacement.search === null ? '' : replacement.search);
|
|
387
|
+
replacement.href = buildHref(replacement);
|
|
388
|
+
return replacement.href;
|
|
389
|
+
}
|
|
390
|
+
const merged = {
|
|
391
|
+
protocol: base.protocol,
|
|
392
|
+
slashes: base.slashes,
|
|
393
|
+
auth: base.auth,
|
|
394
|
+
host: base.host,
|
|
395
|
+
port: base.port,
|
|
396
|
+
hostname: base.hostname,
|
|
397
|
+
hash: target.hash,
|
|
398
|
+
search: target.search,
|
|
399
|
+
query: target.query,
|
|
400
|
+
pathname: target.pathname,
|
|
401
|
+
path: null,
|
|
402
|
+
href: ''
|
|
403
|
+
};
|
|
404
|
+
if (merged.pathname === null) {
|
|
405
|
+
merged.pathname = base.pathname;
|
|
406
|
+
if (merged.search === null) {
|
|
407
|
+
merged.search = base.search;
|
|
408
|
+
merged.query = base.query;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
merged.pathname = resolvePath(base.pathname === null ? '' : base.pathname, merged.pathname);
|
|
413
|
+
}
|
|
414
|
+
merged.path = (merged.pathname === null ? '' : merged.pathname) + (merged.search === null ? '' : merged.search);
|
|
415
|
+
if (merged.path === '' && merged.host !== null) {
|
|
416
|
+
merged.path = '/';
|
|
417
|
+
}
|
|
418
|
+
merged.href = buildHref(merged);
|
|
419
|
+
return merged.href;
|
|
420
|
+
}
|
|
421
|
+
// ------------------------------------------------------------------ file URL
|
|
422
|
+
function pathToFileURL(filepath) {
|
|
423
|
+
const target = String(filepath);
|
|
424
|
+
const absolute = target.charAt(0) === '/';
|
|
425
|
+
const normalized = absolute ? target : '/' + target;
|
|
426
|
+
const encoded = normalized.split('/').map(function (segment) {
|
|
427
|
+
return encodeURIComponent(segment).replace(/%2F/gi, '/');
|
|
428
|
+
}).join('/');
|
|
429
|
+
return new url_whatwg_1.URL('file://' + encoded);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* 把 URL 实例转成 http.request 的选项对象。
|
|
433
|
+
* 语义照 Node:IPv6 主机去掉方括号、path 是 pathname + search、auth 从 username/password 还原。
|
|
434
|
+
*/
|
|
435
|
+
function urlToHttpOptions(url) {
|
|
436
|
+
const instance = url;
|
|
437
|
+
const username = instance.username;
|
|
438
|
+
const password = instance.password;
|
|
439
|
+
const hostname = instance.hostname;
|
|
440
|
+
const pathname = instance.pathname;
|
|
441
|
+
const options = {
|
|
442
|
+
protocol: instance.protocol,
|
|
443
|
+
hostname: hostname.charAt(0) === '[' ? hostname.slice(1, hostname.length - 1) : hostname,
|
|
444
|
+
hash: instance.hash,
|
|
445
|
+
search: instance.search,
|
|
446
|
+
pathname: pathname,
|
|
447
|
+
path: pathname + instance.search,
|
|
448
|
+
href: instance.href,
|
|
449
|
+
port: instance.port === '' ? undefined : Number(instance.port),
|
|
450
|
+
// 注意:Node 的 urlToHttpOptions **不包含** host 字段(虽然它内部有 url.host 可用)
|
|
451
|
+
auth: username !== '' || password !== '' ? decodeURIComponent(username) + ':' + decodeURIComponent(password) : undefined
|
|
452
|
+
};
|
|
453
|
+
return options;
|
|
454
|
+
}
|
|
455
|
+
function fileURLToPath(path) {
|
|
456
|
+
const source = typeof path === 'string' ? path : String(path.href);
|
|
457
|
+
const withoutScheme = source.slice('file://'.length);
|
|
458
|
+
const slash = withoutScheme.indexOf('/');
|
|
459
|
+
const host = slash < 0 ? withoutScheme : withoutScheme.slice(0, slash);
|
|
460
|
+
if (host !== '' && host !== 'localhost') {
|
|
461
|
+
throw new Error('File URL host must be "localhost" or empty on the current platform');
|
|
462
|
+
}
|
|
463
|
+
const pathPart = slash < 0 ? '' : withoutScheme.slice(slash);
|
|
464
|
+
return decodeURIComponent(pathPart);
|
|
465
|
+
}
|
|
466
|
+
// ------------------------------------------------------------------ 域名转换
|
|
467
|
+
function domainToASCII(domain) {
|
|
468
|
+
return punycode.toASCII(String(domain).toLowerCase());
|
|
469
|
+
}
|
|
470
|
+
function domainToUnicode(domain) {
|
|
471
|
+
return punycode.toUnicode(String(domain));
|
|
472
|
+
}
|
|
473
|
+
// ------------------------------------------------------------------ 导出
|
|
474
|
+
const urlModule = {
|
|
475
|
+
URLSearchParams: url_search_params_1.URLSearchParams,
|
|
476
|
+
parse: parseUrl,
|
|
477
|
+
format: formatUrl,
|
|
478
|
+
resolve: resolveUrl,
|
|
479
|
+
pathToFileURL: pathToFileURL,
|
|
480
|
+
fileURLToPath: fileURLToPath,
|
|
481
|
+
domainToASCII: domainToASCII,
|
|
482
|
+
domainToUnicode: domainToUnicode,
|
|
483
|
+
URL: url_whatwg_1.URL,
|
|
484
|
+
urlToHttpOptions: urlToHttpOptions
|
|
485
|
+
};
|
|
486
|
+
module.exports = urlModule;
|
package/dist/util.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
interface InspectOptions {
|
|
2
|
+
depth?: number | null;
|
|
3
|
+
colors?: boolean;
|
|
4
|
+
showHidden?: boolean;
|
|
5
|
+
compact?: boolean | number;
|
|
6
|
+
breakLength?: number;
|
|
7
|
+
sorted?: boolean;
|
|
8
|
+
maxArrayLength?: number;
|
|
9
|
+
maxStringLength?: number | null;
|
|
10
|
+
getters?: boolean;
|
|
11
|
+
showProxy?: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare function inspect(value: unknown, options?: InspectOptions | boolean | number): string;
|
|
14
|
+
declare function formatWithOptions(options: InspectOptions, template?: unknown, ...rest: unknown[]): string;
|
|
15
|
+
declare function format(template?: unknown, ...rest: unknown[]): string;
|
|
16
|
+
declare function inherits(constructor: Function, superConstructor: Function): void;
|
|
17
|
+
declare function promisify(original: Function): Function;
|
|
18
|
+
declare function callbackify(original: Function): Function;
|
|
19
|
+
declare function deprecate(fn: Function, message: string): Function;
|
|
20
|
+
declare function debuglog(section: string): Function & {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
};
|
|
23
|
+
declare function getSystemErrorName(errno: number): string;
|
|
24
|
+
declare function stripVTControlCharacters(value: string): string;
|
|
25
|
+
declare function isDeepStrictEqual(left: unknown, right: unknown): boolean;
|
|
26
|
+
declare class TextEncoder {
|
|
27
|
+
readonly encoding = "utf-8";
|
|
28
|
+
encode(input?: string): Uint8Array;
|
|
29
|
+
encodeInto(source: string, destination: Uint8Array): {
|
|
30
|
+
read: number;
|
|
31
|
+
written: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
declare class TextDecoder {
|
|
35
|
+
readonly encoding: string;
|
|
36
|
+
readonly fatal: boolean;
|
|
37
|
+
readonly ignoreBOM: boolean;
|
|
38
|
+
constructor(label?: string, options?: {
|
|
39
|
+
fatal?: boolean;
|
|
40
|
+
ignoreBOM?: boolean;
|
|
41
|
+
});
|
|
42
|
+
decode(input?: Uint8Array): string;
|
|
43
|
+
}
|
|
44
|
+
declare const util: {
|
|
45
|
+
format: typeof format;
|
|
46
|
+
formatWithOptions: typeof formatWithOptions;
|
|
47
|
+
inspect: typeof inspect;
|
|
48
|
+
inherits: typeof inherits;
|
|
49
|
+
promisify: typeof promisify;
|
|
50
|
+
callbackify: typeof callbackify;
|
|
51
|
+
deprecate: typeof deprecate;
|
|
52
|
+
debuglog: typeof debuglog;
|
|
53
|
+
getSystemErrorName: typeof getSystemErrorName;
|
|
54
|
+
stripVTControlCharacters: typeof stripVTControlCharacters;
|
|
55
|
+
isDeepStrictEqual: typeof isDeepStrictEqual;
|
|
56
|
+
types: {
|
|
57
|
+
isDate: (value: unknown) => boolean;
|
|
58
|
+
isRegExp: (value: unknown) => boolean;
|
|
59
|
+
isArray: (value: unknown) => boolean;
|
|
60
|
+
isTypedArray: (value: unknown) => boolean;
|
|
61
|
+
isUint8Array: (value: unknown) => boolean;
|
|
62
|
+
isArrayBuffer: (value: unknown) => boolean;
|
|
63
|
+
isPromise: (value: unknown) => boolean;
|
|
64
|
+
isNativeError: (value: unknown) => boolean;
|
|
65
|
+
isMap: (value: unknown) => boolean;
|
|
66
|
+
isSet: (value: unknown) => boolean;
|
|
67
|
+
isBigInt64Array: (value: unknown) => boolean;
|
|
68
|
+
isAsyncFunction: (value: unknown) => boolean;
|
|
69
|
+
isGeneratorFunction: (value: unknown) => boolean;
|
|
70
|
+
};
|
|
71
|
+
TextEncoder: typeof TextEncoder;
|
|
72
|
+
TextDecoder: typeof TextDecoder;
|
|
73
|
+
};
|
|
74
|
+
export = util;
|