@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.
Files changed (123) hide show
  1. package/BUILTINS.json +233 -0
  2. package/DESIGN.md +513 -0
  3. package/LICENSE +674 -0
  4. package/README.md +301 -2
  5. package/dist/assert/strict.d.ts +2 -0
  6. package/dist/assert/strict.js +7 -0
  7. package/dist/assert.d.ts +3 -0
  8. package/dist/assert.js +483 -0
  9. package/dist/buffer.d.ts +60 -0
  10. package/dist/buffer.js +524 -0
  11. package/dist/child_process.d.ts +56 -0
  12. package/dist/child_process.js +371 -0
  13. package/dist/constants.d.ts +2 -0
  14. package/dist/constants.js +19 -0
  15. package/dist/crypto.d.ts +76 -0
  16. package/dist/crypto.js +312 -0
  17. package/dist/dns/promises.d.ts +34 -0
  18. package/dist/dns/promises.js +190 -0
  19. package/dist/dns.d.ts +88 -0
  20. package/dist/dns.js +259 -0
  21. package/dist/events.d.ts +40 -0
  22. package/dist/events.js +237 -0
  23. package/dist/fs/promises.d.ts +159 -0
  24. package/dist/fs/promises.js +129 -0
  25. package/dist/fs.d.ts +221 -0
  26. package/dist/fs.js +944 -0
  27. package/dist/http.d.ts +92 -0
  28. package/dist/http.js +319 -0
  29. package/dist/https.d.ts +296 -0
  30. package/dist/https.js +50 -0
  31. package/dist/index.d.ts +2422 -0
  32. package/dist/index.js +57 -0
  33. package/dist/lib/bridge.d.ts +60 -0
  34. package/dist/lib/bridge.js +205 -0
  35. package/dist/lib/bytes.d.ts +20 -0
  36. package/dist/lib/bytes.js +239 -0
  37. package/dist/lib/child-process-types.d.ts +45 -0
  38. package/dist/lib/child-process-types.js +2 -0
  39. package/dist/lib/cwd.d.ts +2 -0
  40. package/dist/lib/cwd.js +32 -0
  41. package/dist/lib/deep-equal.d.ts +3 -0
  42. package/dist/lib/deep-equal.js +223 -0
  43. package/dist/lib/deflate.d.ts +2 -0
  44. package/dist/lib/deflate.js +234 -0
  45. package/dist/lib/dns-driver.d.ts +14 -0
  46. package/dist/lib/dns-driver.js +85 -0
  47. package/dist/lib/dns-types.d.ts +22 -0
  48. package/dist/lib/dns-types.js +2 -0
  49. package/dist/lib/errors.d.ts +48 -0
  50. package/dist/lib/errors.js +424 -0
  51. package/dist/lib/fs-driver.d.ts +70 -0
  52. package/dist/lib/fs-driver.js +364 -0
  53. package/dist/lib/fs-env.d.ts +30 -0
  54. package/dist/lib/fs-env.js +157 -0
  55. package/dist/lib/fs-types.d.ts +19 -0
  56. package/dist/lib/fs-types.js +2 -0
  57. package/dist/lib/hashes.d.ts +27 -0
  58. package/dist/lib/hashes.js +432 -0
  59. package/dist/lib/http-driver.d.ts +30 -0
  60. package/dist/lib/http-driver.js +72 -0
  61. package/dist/lib/http-types.d.ts +18 -0
  62. package/dist/lib/http-types.js +2 -0
  63. package/dist/lib/inflate.d.ts +6 -0
  64. package/dist/lib/inflate.js +284 -0
  65. package/dist/lib/path-types.d.ts +37 -0
  66. package/dist/lib/path-types.js +2 -0
  67. package/dist/lib/paths.d.ts +8 -0
  68. package/dist/lib/paths.js +106 -0
  69. package/dist/lib/perf-hooks-types.d.ts +18 -0
  70. package/dist/lib/perf-hooks-types.js +2 -0
  71. package/dist/lib/process-driver.d.ts +31 -0
  72. package/dist/lib/process-driver.js +102 -0
  73. package/dist/lib/punycode.d.ts +8 -0
  74. package/dist/lib/punycode.js +179 -0
  75. package/dist/lib/stream-types.d.ts +29 -0
  76. package/dist/lib/stream-types.js +2 -0
  77. package/dist/lib/timers-types.d.ts +18 -0
  78. package/dist/lib/timers-types.js +2 -0
  79. package/dist/lib/url-search-params.d.ts +26 -0
  80. package/dist/lib/url-search-params.js +281 -0
  81. package/dist/lib/url-types.d.ts +44 -0
  82. package/dist/lib/url-types.js +2 -0
  83. package/dist/lib/url-whatwg.d.ts +78 -0
  84. package/dist/lib/url-whatwg.js +857 -0
  85. package/dist/lib/zlib-types.d.ts +12 -0
  86. package/dist/lib/zlib-types.js +2 -0
  87. package/dist/module.d.ts +8 -0
  88. package/dist/module.js +72 -0
  89. package/dist/os.d.ts +80 -0
  90. package/dist/os.js +247 -0
  91. package/dist/path/posix.d.ts +2 -0
  92. package/dist/path/posix.js +7 -0
  93. package/dist/path/win32.d.ts +2 -0
  94. package/dist/path/win32.js +10 -0
  95. package/dist/path.d.ts +3 -0
  96. package/dist/path.js +1222 -0
  97. package/dist/perf_hooks.d.ts +36 -0
  98. package/dist/perf_hooks.js +144 -0
  99. package/dist/process.d.ts +69 -0
  100. package/dist/process.js +230 -0
  101. package/dist/querystring.d.ts +15 -0
  102. package/dist/querystring.js +209 -0
  103. package/dist/stream/promises.d.ts +5 -0
  104. package/dist/stream/promises.js +10 -0
  105. package/dist/stream.d.ts +84 -0
  106. package/dist/stream.js +875 -0
  107. package/dist/string_decoder.d.ts +15 -0
  108. package/dist/string_decoder.js +237 -0
  109. package/dist/timers/promises.d.ts +19 -0
  110. package/dist/timers/promises.js +74 -0
  111. package/dist/timers.d.ts +21 -0
  112. package/dist/timers.js +41 -0
  113. package/dist/tty.d.ts +9 -0
  114. package/dist/tty.js +25 -0
  115. package/dist/unsupported.d.ts +12 -0
  116. package/dist/unsupported.js +17 -0
  117. package/dist/url.d.ts +28 -0
  118. package/dist/url.js +486 -0
  119. package/dist/util.d.ts +74 -0
  120. package/dist/util.js +515 -0
  121. package/dist/zlib.d.ts +88 -0
  122. package/dist/zlib.js +371 -0
  123. package/package.json +29 -4
@@ -0,0 +1,857 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.URL = void 0;
37
+ exports.fragmentEncodeSet = fragmentEncodeSet;
38
+ exports.queryEncodeSet = queryEncodeSet;
39
+ exports.specialQueryEncodeSet = specialQueryEncodeSet;
40
+ exports.pathEncodeSet = pathEncodeSet;
41
+ exports.userinfoEncodeSet = userinfoEncodeSet;
42
+ exports.parseUrlRecord = parseUrlRecord;
43
+ /**
44
+ * WHATWG URL(RFC 3986 + URL 标准的解析与序列化)。
45
+ *
46
+ * 覆盖:特殊协议(http/https/ws/wss/ftp/file)与自定义协议、authority(userinfo / host / port)、
47
+ * IPv4 / IPv6 / 域名的 punycode、按组件的百分号编码、点段规范化、相对引用解析、
48
+ * 全部 getter 与 setter、url.searchParams 的活视图、URL.canParse / URL.parse。
49
+ *
50
+ * 与 Node 的已知差异见 BUILTINS.json 的 url 条目:IPv4 的十六进制/八进制写法、
51
+ * 非 ASCII 域名的 UTS-46 映射(只做 punycode,不做映射与归一化)、blob: 的 origin。
52
+ */
53
+ const url_search_params_1 = require("./url-search-params");
54
+ const punycode = __importStar(require("./punycode"));
55
+ const bytes_1 = require("./bytes");
56
+ // ------------------------------------------------------------------ 编码集
57
+ function isC0Control(code) {
58
+ return code <= 0x1f || code > 0x7e;
59
+ }
60
+ /** fragment 组:C0 组 + 空格 " < > ` */
61
+ function fragmentEncodeSet(code) {
62
+ return isC0Control(code) || code === 0x20 || code === 0x22 || code === 0x3c || code === 0x3e || code === 0x60;
63
+ }
64
+ /** query 组:C0 组 + 空格 " # < > */
65
+ function queryEncodeSet(code) {
66
+ return isC0Control(code) || code === 0x20 || code === 0x22 || code === 0x23 || code === 0x3c || code === 0x3e;
67
+ }
68
+ /** special-query 组:query 组 + ' */
69
+ function specialQueryEncodeSet(code) {
70
+ return queryEncodeSet(code) || code === 0x27;
71
+ }
72
+ /** path 组:query 组 + ? ` { } */
73
+ function pathEncodeSet(code) {
74
+ return queryEncodeSet(code) || code === 0x3f || code === 0x60 || code === 0x7b || code === 0x7d;
75
+ }
76
+ /** userinfo 组:path 组 + / : ; = @ [ \ ] ^ | */
77
+ function userinfoEncodeSet(code) {
78
+ return pathEncodeSet(code) || code === 0x2f || code === 0x3a || code === 0x3b || code === 0x3d ||
79
+ code === 0x40 || (code >= 0x5b && code <= 0x5e) || code === 0x7c;
80
+ }
81
+ const HEX = '0123456789ABCDEF';
82
+ function hex2(value) {
83
+ return '%' + HEX.charAt((value >> 4) & 15) + HEX.charAt(value & 15);
84
+ }
85
+ function pctEncode(input, inSet) {
86
+ const bytes = (0, bytes_1.utf8Encode)(input);
87
+ let out = '';
88
+ for (let i = 0; i < bytes.length; i += 1) {
89
+ const byte = bytes[i];
90
+ out += inSet(byte) ? hex2(byte) : String.fromCharCode(byte);
91
+ }
92
+ return out;
93
+ }
94
+ // ------------------------------------------------------------------ 特殊协议
95
+ const SPECIAL_PORTS = {
96
+ ftp: 21,
97
+ file: -1,
98
+ http: 80,
99
+ https: 443,
100
+ ws: 80,
101
+ wss: 443
102
+ };
103
+ function isSpecialScheme(scheme) {
104
+ return Object.prototype.hasOwnProperty.call(SPECIAL_PORTS, scheme);
105
+ }
106
+ function defaultPortOf(scheme) {
107
+ const value = SPECIAL_PORTS[scheme];
108
+ return value === undefined ? -1 : value;
109
+ }
110
+ function emptyRecord() {
111
+ return {
112
+ scheme: '',
113
+ username: '',
114
+ password: '',
115
+ host: null,
116
+ port: null,
117
+ path: [],
118
+ query: null,
119
+ fragment: null
120
+ };
121
+ }
122
+ function pathSerializerOf(record, excludeFragment) {
123
+ let out = record.scheme + ':';
124
+ if (record.host !== null) {
125
+ out += '//';
126
+ if (record.username !== '' || record.password !== '') {
127
+ out += record.username;
128
+ if (record.password !== '') {
129
+ out += ':' + record.password;
130
+ }
131
+ out += '@';
132
+ }
133
+ out += record.host;
134
+ if (record.port !== null) {
135
+ out += ':' + record.port;
136
+ }
137
+ }
138
+ if (typeof record.path === 'string') {
139
+ out += record.path;
140
+ }
141
+ else {
142
+ for (let i = 0; i < record.path.length; i += 1) {
143
+ out += '/' + record.path[i];
144
+ }
145
+ }
146
+ if (record.query !== null) {
147
+ out += '?' + record.query;
148
+ }
149
+ if (!excludeFragment && record.fragment !== null) {
150
+ out += '#' + record.fragment;
151
+ }
152
+ return out;
153
+ }
154
+ function serializeRecord(record) {
155
+ return pathSerializerOf(record, false);
156
+ }
157
+ function authorityOf(record) {
158
+ if (record.host === null) {
159
+ return '';
160
+ }
161
+ let out = '';
162
+ if (record.username !== '' || record.password !== '') {
163
+ out += record.username;
164
+ if (record.password !== '') {
165
+ out += ':' + record.password;
166
+ }
167
+ out += '@';
168
+ }
169
+ out += record.host;
170
+ if (record.port !== null) {
171
+ out += ':' + record.port;
172
+ }
173
+ return out;
174
+ }
175
+ function pathTextOf(record) {
176
+ if (typeof record.path === 'string') {
177
+ return record.path;
178
+ }
179
+ let out = '';
180
+ for (let i = 0; i < record.path.length; i += 1) {
181
+ out += '/' + record.path[i];
182
+ }
183
+ return out;
184
+ }
185
+ // ------------------------------------------------------------------ 主机解析
186
+ /** 把一段 ':' 分隔的组转成数字;最后一段允许是 IPv4 写法(占两组)。 */
187
+ function convertGroups(list, allowIPv4, out) {
188
+ for (let i = 0; i < list.length; i += 1) {
189
+ const piece = list[i];
190
+ if (piece === '') {
191
+ return false;
192
+ }
193
+ if (piece.indexOf('.') >= 0) {
194
+ if (!allowIPv4 || i !== list.length - 1) {
195
+ return false;
196
+ }
197
+ const ipv4 = parseIPv4(piece);
198
+ if (ipv4 === null) {
199
+ return false;
200
+ }
201
+ const parts = ipv4.split('.');
202
+ out.push(Number(parts[0]) * 256 + Number(parts[1]));
203
+ out.push(Number(parts[2]) * 256 + Number(parts[3]));
204
+ continue;
205
+ }
206
+ if (!/^[0-9A-Fa-f]{1,4}$/.test(piece)) {
207
+ return false;
208
+ }
209
+ out.push(parseInt(piece, 16));
210
+ }
211
+ return true;
212
+ }
213
+ /** 解析 IPv6,返回规范化的 8 组(不含方括号)。中间的 :: 按最长零串压缩。 */
214
+ function parseIPv6(input) {
215
+ const first = input.indexOf('::');
216
+ if (first >= 0 && input.indexOf('::', first + 1) >= 0) {
217
+ return null;
218
+ }
219
+ const headText = first >= 0 ? input.slice(0, first) : input;
220
+ const tailText = first >= 0 ? input.slice(first + 2) : '';
221
+ const head = [];
222
+ const tail = [];
223
+ if (headText !== '') {
224
+ if (!convertGroups(headText.split(':'), first < 0, head)) {
225
+ return null;
226
+ }
227
+ }
228
+ if (tailText !== '') {
229
+ if (!convertGroups(tailText.split(':'), true, tail)) {
230
+ return null;
231
+ }
232
+ }
233
+ let address;
234
+ if (first >= 0) {
235
+ const zeros = 8 - head.length - tail.length;
236
+ if (zeros < 1) {
237
+ return null;
238
+ }
239
+ address = head.concat(new Array(zeros).fill(0), tail);
240
+ }
241
+ else {
242
+ if (head.length !== 8) {
243
+ return null;
244
+ }
245
+ address = head;
246
+ }
247
+ // 序列化:找最长的零串压缩
248
+ let bestStart = -1;
249
+ let bestLength = 0;
250
+ let runStart = -1;
251
+ for (let i = 0; i <= 8; i += 1) {
252
+ if (i < 8 && address[i] === 0) {
253
+ if (runStart < 0) {
254
+ runStart = i;
255
+ }
256
+ }
257
+ else if (runStart >= 0) {
258
+ const length = i - runStart;
259
+ if (length > bestLength) {
260
+ bestLength = length;
261
+ bestStart = runStart;
262
+ }
263
+ runStart = -1;
264
+ }
265
+ }
266
+ const compress = bestLength > 1 ? bestStart : -1;
267
+ let output = '';
268
+ let ignoring = false;
269
+ for (let i = 0; i < 8; i += 1) {
270
+ if (ignoring && address[i] === 0) {
271
+ continue;
272
+ }
273
+ if (i === compress) {
274
+ output += i === 0 ? '::' : ':';
275
+ ignoring = true;
276
+ continue;
277
+ }
278
+ ignoring = false;
279
+ output += address[i].toString(16);
280
+ if (i !== 7) {
281
+ output += ':';
282
+ }
283
+ }
284
+ return output;
285
+ }
286
+ function parseIPv4Number(input) {
287
+ if (input === '') {
288
+ return null;
289
+ }
290
+ let radix = 10;
291
+ if (input.length >= 2 && (input.charAt(0) === '0' && (input.charAt(1) === 'x' || input.charAt(1) === 'X'))) {
292
+ radix = 16;
293
+ input = input.slice(2);
294
+ }
295
+ else if (input.length >= 2 && input.charAt(0) === '0') {
296
+ radix = 8;
297
+ input = input.slice(1);
298
+ }
299
+ if (input === '') {
300
+ return 0;
301
+ }
302
+ const pattern = radix === 16 ? /^[0-9A-Fa-f]+$/ : (radix === 8 ? /^[0-7]+$/ : /^[0-9]+$/);
303
+ if (!pattern.test(input)) {
304
+ return null;
305
+ }
306
+ return parseInt(input, radix);
307
+ }
308
+ function parseIPv4(input) {
309
+ const parts = input.split('.');
310
+ if (parts.length > 1 && parts[parts.length - 1] === '') {
311
+ parts.pop();
312
+ }
313
+ if (parts.length > 4) {
314
+ return null;
315
+ }
316
+ const numbers = [];
317
+ for (let i = 0; i < parts.length; i += 1) {
318
+ const value = parseIPv4Number(parts[i]);
319
+ if (value === null) {
320
+ return null;
321
+ }
322
+ numbers.push(value);
323
+ }
324
+ for (let i = 0; i < numbers.length - 1; i += 1) {
325
+ if (numbers[i] > 255) {
326
+ return null;
327
+ }
328
+ }
329
+ if (numbers[numbers.length - 1] >= Math.pow(256, 5 - numbers.length)) {
330
+ return null;
331
+ }
332
+ let ipv4 = numbers.pop();
333
+ for (let i = 0; i < numbers.length; i += 1) {
334
+ ipv4 += numbers[i] * Math.pow(256, 3 - i);
335
+ }
336
+ const result = [];
337
+ for (let i = 0; i < 4; i += 1) {
338
+ result.unshift(ipv4 % 256);
339
+ ipv4 = Math.floor(ipv4 / 256);
340
+ }
341
+ return result.join('.');
342
+ }
343
+ /** endsInANumber 规则:主机以数字结尾时要按 IPv4 解析。 */
344
+ function endsInANumber(domain) {
345
+ const parts = domain.split('.');
346
+ if (parts[parts.length - 1] === '') {
347
+ return false;
348
+ }
349
+ const last = parts[parts.length - 1];
350
+ if (/^[0-9]+$/.test(last)) {
351
+ return true;
352
+ }
353
+ return parseIPv4Number(last) !== null;
354
+ }
355
+ function parseHost(input, special) {
356
+ if (input.charAt(0) === '[') {
357
+ if (input.charAt(input.length - 1) !== ']') {
358
+ return null;
359
+ }
360
+ const inner = parseIPv6(input.slice(1, input.length - 1));
361
+ return inner === null ? null : '[' + inner + ']';
362
+ }
363
+ if (!special) {
364
+ // 不透明主机:只做 C0 组编码
365
+ return pctEncode(input, isC0Control);
366
+ }
367
+ let domain = input;
368
+ try {
369
+ domain = decodeURIComponent(domain);
370
+ }
371
+ catch (failure) {
372
+ return null;
373
+ }
374
+ if (domain === '') {
375
+ return null;
376
+ }
377
+ // 结尾的点保留(Node 也保留:http://example.com./ 的 host 就是 example.com.)
378
+ domain = domain.toLowerCase();
379
+ if (endsInANumber(domain)) {
380
+ const ipv4 = parseIPv4(domain);
381
+ return ipv4 === null ? null : ipv4;
382
+ }
383
+ return punycode.toASCII(domain);
384
+ }
385
+ // ------------------------------------------------------------------ 解析
386
+ function stripControls(input) {
387
+ let start = 0;
388
+ let end = input.length;
389
+ while (start < end && input.charCodeAt(start) <= 0x20) {
390
+ start += 1;
391
+ }
392
+ while (end > start && input.charCodeAt(end - 1) <= 0x20) {
393
+ end -= 1;
394
+ }
395
+ return input.slice(start, end).replace(/[\t\n\r]/g, '');
396
+ }
397
+ function parsePort(input, scheme) {
398
+ if (input === null || input === '') {
399
+ return null;
400
+ }
401
+ if (!/^[0-9]+$/.test(input)) {
402
+ return undefined;
403
+ }
404
+ const value = parseInt(input, 10);
405
+ if (value > 65535) {
406
+ return undefined;
407
+ }
408
+ return value === defaultPortOf(scheme) ? null : value;
409
+ }
410
+ /** 把路径段序列按点段规则规范化。 */
411
+ function normalizePathSegments(segments, keepEmpty) {
412
+ const out = [];
413
+ for (let i = 0; i < segments.length; i += 1) {
414
+ const segment = segments[i];
415
+ if (segment === '.' || (segment === '%2e' || segment === '%2E')) {
416
+ if (i === segments.length - 1) {
417
+ out.push('');
418
+ }
419
+ continue;
420
+ }
421
+ if (segment === '..' || segment === '.%2e' || segment === '%2e.' || segment === '%2e%2e') {
422
+ if (out.length > 0) {
423
+ out.pop();
424
+ }
425
+ if (i === segments.length - 1) {
426
+ out.push('');
427
+ }
428
+ continue;
429
+ }
430
+ out.push(segment);
431
+ }
432
+ if (keepEmpty && out.length === 0) {
433
+ out.push('');
434
+ }
435
+ return out;
436
+ }
437
+ function parseAbsolute(input, schemeHint) {
438
+ const record = emptyRecord();
439
+ let rest = input;
440
+ let scheme = schemeHint;
441
+ const schemeMatch = /^([a-zA-Z][a-zA-Z0-9+\-.]*):/.exec(rest);
442
+ if (schemeMatch !== null) {
443
+ scheme = schemeMatch[1].toLowerCase();
444
+ rest = rest.slice(schemeMatch[0].length);
445
+ }
446
+ if (scheme === null) {
447
+ return null;
448
+ }
449
+ record.scheme = scheme;
450
+ const special = isSpecialScheme(scheme);
451
+ // authority
452
+ let hasAuthority = false;
453
+ if (special && scheme === 'file') {
454
+ // file: 只有前两个斜杠是 authority 标记;再多斜杠表示空主机、路径从这里开始
455
+ hasAuthority = true;
456
+ if (rest.slice(0, 2) === '//') {
457
+ rest = rest.slice(2);
458
+ }
459
+ }
460
+ else if (special) {
461
+ // 其它特殊协议:冒号后可以有任意多个 / 或反斜杠,全部跳过,
462
+ // 所以 http:///path 的主机是 path(与 Node 一致)
463
+ hasAuthority = true;
464
+ let cut = 0;
465
+ while (cut < rest.length && (rest.charAt(cut) === '/' || rest.charAt(cut) === '\\')) {
466
+ cut += 1;
467
+ }
468
+ rest = rest.slice(cut);
469
+ }
470
+ else if (rest.slice(0, 2) === '//') {
471
+ rest = rest.slice(2);
472
+ hasAuthority = true;
473
+ }
474
+ if (hasAuthority) {
475
+ // authority 到第一个 / ? # 为止(特殊协议里 \ 也当分隔符)
476
+ let end = rest.length;
477
+ for (let i = 0; i < rest.length; i += 1) {
478
+ const ch = rest.charAt(i);
479
+ if (ch === '/' || ch === '?' || ch === '#' || (special && ch === '\\')) {
480
+ end = i;
481
+ break;
482
+ }
483
+ }
484
+ let authority = rest.slice(0, end);
485
+ rest = rest.slice(end);
486
+ if (special) {
487
+ authority = authority.replace(/\\/g, '/');
488
+ // 特殊协议里 authority 不应再有斜杠
489
+ const slash = authority.indexOf('/');
490
+ if (slash >= 0) {
491
+ rest = authority.slice(slash) + rest;
492
+ authority = authority.slice(0, slash);
493
+ }
494
+ }
495
+ const at = authority.lastIndexOf('@');
496
+ if (at >= 0) {
497
+ let userinfo = authority.slice(0, at);
498
+ authority = authority.slice(at + 1);
499
+ const colon = userinfo.indexOf(':');
500
+ if (colon >= 0) {
501
+ record.username = pctEncode(userinfo.slice(0, colon), userinfoEncodeSet);
502
+ record.password = pctEncode(userinfo.slice(colon + 1), userinfoEncodeSet);
503
+ }
504
+ else {
505
+ record.username = pctEncode(userinfo, userinfoEncodeSet);
506
+ }
507
+ }
508
+ let portText = null;
509
+ if (authority.charAt(0) === '[') {
510
+ const close = authority.indexOf(']');
511
+ if (close < 0) {
512
+ return null;
513
+ }
514
+ if (authority.charAt(close + 1) === ':') {
515
+ portText = authority.slice(close + 2);
516
+ }
517
+ authority = authority.slice(0, close + 1);
518
+ }
519
+ else {
520
+ const colon = authority.lastIndexOf(':');
521
+ if (colon >= 0) {
522
+ portText = authority.slice(colon + 1);
523
+ authority = authority.slice(0, colon);
524
+ }
525
+ }
526
+ // file:///path 的主机是空串(合法),file://localhost/ 也归一成空主机;
527
+ // 其它特殊协议不允许空主机
528
+ let host;
529
+ if (scheme === 'file' && (authority === '' || authority.toLowerCase() === 'localhost')) {
530
+ host = '';
531
+ }
532
+ else {
533
+ host = parseHost(authority, special);
534
+ }
535
+ if (host === null) {
536
+ return null;
537
+ }
538
+ record.host = host;
539
+ const port = parsePort(portText, scheme);
540
+ if (port === undefined) {
541
+ return null;
542
+ }
543
+ record.port = port;
544
+ if (scheme === 'file' && (record.username !== '' || record.password !== '' || record.port !== null)) {
545
+ return null;
546
+ }
547
+ }
548
+ // fragment
549
+ const hashAt = rest.indexOf('#');
550
+ if (hashAt >= 0) {
551
+ record.fragment = pctEncode(rest.slice(hashAt + 1), fragmentEncodeSet);
552
+ rest = rest.slice(0, hashAt);
553
+ }
554
+ // query
555
+ const queryAt = rest.indexOf('?');
556
+ if (queryAt >= 0) {
557
+ const raw = rest.slice(queryAt + 1);
558
+ record.query = pctEncode(raw, special ? specialQueryEncodeSet : queryEncodeSet);
559
+ rest = rest.slice(0, queryAt);
560
+ }
561
+ if (!hasAuthority) {
562
+ // 不透明路径
563
+ record.path = pctEncode(rest, isC0Control);
564
+ return record;
565
+ }
566
+ const segments = [];
567
+ const pieces = rest.split('/');
568
+ for (let i = 1; i < pieces.length; i += 1) {
569
+ segments.push(pctEncode(pieces[i], pathEncodeSet));
570
+ }
571
+ if (segments.length === 0) {
572
+ segments.push('');
573
+ }
574
+ record.path = normalizePathSegments(segments, true);
575
+ return record;
576
+ }
577
+ /** 把相对引用先拼成绝对串,再走绝对解析(与规范的 state 展开等价,只是写法更直白)。 */
578
+ function resolveRelative(input, base) {
579
+ if (typeof base.path === 'string') {
580
+ return null;
581
+ }
582
+ const authority = base.host === null ? null : '//' + authorityOf(base);
583
+ if (authority === null) {
584
+ return null;
585
+ }
586
+ const basePath = pathTextOf(base);
587
+ if (input.slice(0, 2) === '//') {
588
+ return base.scheme + ':' + input;
589
+ }
590
+ if (input.charAt(0) === '/') {
591
+ return base.scheme + ':' + authority + input;
592
+ }
593
+ if (input.charAt(0) === '?') {
594
+ return base.scheme + ':' + authority + basePath + input;
595
+ }
596
+ if (input.charAt(0) === '#') {
597
+ return serializeRecord(base) + input;
598
+ }
599
+ if (input === '') {
600
+ return base.scheme + ':' + authority + basePath + (base.query === null ? '' : '?' + base.query);
601
+ }
602
+ const cut = basePath.lastIndexOf('/');
603
+ const merged = (cut < 0 ? '' : basePath.slice(0, cut + 1)) + input;
604
+ return base.scheme + ':' + authority + merged;
605
+ }
606
+ function parseUrlRecord(input, base) {
607
+ const trimmed = stripControls(input);
608
+ const hasScheme = /^[a-zA-Z][a-zA-Z0-9+\-.]*:/.test(trimmed);
609
+ if (hasScheme || base === undefined || base === null) {
610
+ return parseAbsolute(trimmed, null);
611
+ }
612
+ const absolute = resolveRelative(trimmed, base);
613
+ if (absolute === null) {
614
+ return null;
615
+ }
616
+ return parseAbsolute(absolute, null);
617
+ }
618
+ // ------------------------------------------------------------------ URL 类
619
+ function isInvalid(record) {
620
+ return record === null;
621
+ }
622
+ class URL {
623
+ constructor(input, base) {
624
+ const text = String(input);
625
+ let baseRecord = null;
626
+ if (base !== undefined && base !== null) {
627
+ const baseText = base instanceof URL ? base.href : String(base);
628
+ baseRecord = parseAbsolute(stripControls(baseText), null);
629
+ if (isInvalid(baseRecord)) {
630
+ throw new TypeError('Invalid base URL');
631
+ }
632
+ }
633
+ const record = parseUrlRecord(text, baseRecord);
634
+ if (record === null) {
635
+ throw new TypeError('Invalid URL: ' + text);
636
+ }
637
+ this.record = record;
638
+ this.searchParams = this.buildSearchParams();
639
+ }
640
+ buildSearchParams() {
641
+ const self = this;
642
+ const params = new url_search_params_1.URLSearchParams(this.record.query === null ? '' : this.record.query);
643
+ Object.defineProperty(params, '__onjOnChange', {
644
+ value: function () {
645
+ self.applyParams();
646
+ },
647
+ writable: true,
648
+ enumerable: false
649
+ });
650
+ return params;
651
+ }
652
+ /**
653
+ * 把 searchParams 写回 query。只在参数**真的被改动**时调用。
654
+ *
655
+ * 两处不能想当然:
656
+ * - 不能用 URLSearchParams.toString():那是表单序列化(空格 -> +),
657
+ * 而 URL 的 query 用 URL 的 query 编码集(空格 -> %20);
658
+ * - 没被改动过时必须保持 query 原样,否则 new URL('http://x/?b').search
659
+ * 会从 '?b' 变成 '?b='。
660
+ */
661
+ applyParams() {
662
+ const list = this.searchParams.list;
663
+ if (list.length === 0) {
664
+ this.record.query = null;
665
+ return;
666
+ }
667
+ const set = isSpecialScheme(this.record.scheme) ? specialQueryEncodeSet : queryEncodeSet;
668
+ const parts = [];
669
+ for (let i = 0; i < list.length; i += 1) {
670
+ parts.push(pctEncode(list[i][0], set) + '=' + pctEncode(list[i][1], set));
671
+ }
672
+ this.record.query = parts.join('&');
673
+ }
674
+ /** 不透明路径(没有 authority)时用字符串路径。 */
675
+ isOpaque() {
676
+ return typeof this.record.path === 'string';
677
+ }
678
+ get href() {
679
+ return serializeRecord(this.record);
680
+ }
681
+ set href(value) {
682
+ const record = parseAbsolute(stripControls(String(value)), null);
683
+ if (record === null) {
684
+ throw new TypeError('Invalid URL: ' + String(value));
685
+ }
686
+ this.record = record;
687
+ this.searchParams = this.buildSearchParams();
688
+ }
689
+ get origin() {
690
+ const scheme = this.record.scheme;
691
+ if (scheme === 'ftp' || scheme === 'http' || scheme === 'https' || scheme === 'ws' || scheme === 'wss') {
692
+ let out = scheme + '://' + (this.record.host === null ? '' : this.record.host);
693
+ if (this.record.port !== null) {
694
+ out += ':' + this.record.port;
695
+ }
696
+ return out;
697
+ }
698
+ return 'null';
699
+ }
700
+ get protocol() {
701
+ return this.record.scheme + ':';
702
+ }
703
+ set protocol(value) {
704
+ const match = /^([a-zA-Z][a-zA-Z0-9+\-.]*):?$/.exec(String(value));
705
+ if (match === null) {
706
+ return;
707
+ }
708
+ const next = match[1].toLowerCase();
709
+ if (isSpecialScheme(next) !== isSpecialScheme(this.record.scheme)) {
710
+ return;
711
+ }
712
+ if (this.record.port !== null && this.record.port === defaultPortOf(next)) {
713
+ this.record.port = null;
714
+ }
715
+ this.record.scheme = next;
716
+ }
717
+ get username() {
718
+ return this.record.username;
719
+ }
720
+ set username(value) {
721
+ if (this.isOpaque() || this.record.host === null) {
722
+ return;
723
+ }
724
+ this.record.username = pctEncode(String(value), userinfoEncodeSet);
725
+ }
726
+ get password() {
727
+ return this.record.password;
728
+ }
729
+ set password(value) {
730
+ if (this.isOpaque() || this.record.host === null) {
731
+ return;
732
+ }
733
+ this.record.password = pctEncode(String(value), userinfoEncodeSet);
734
+ }
735
+ get host() {
736
+ if (this.record.host === null) {
737
+ return '';
738
+ }
739
+ return this.record.port === null ? this.record.host : this.record.host + ':' + this.record.port;
740
+ }
741
+ set host(value) {
742
+ if (this.isOpaque()) {
743
+ return;
744
+ }
745
+ const text = stripControls(String(value));
746
+ const record = parseAbsolute('http://' + text + '/', null);
747
+ if (record === null || record.host === null) {
748
+ return;
749
+ }
750
+ this.record.host = record.host;
751
+ this.record.port = record.port;
752
+ }
753
+ get hostname() {
754
+ return this.record.host === null ? '' : this.record.host;
755
+ }
756
+ set hostname(value) {
757
+ if (this.isOpaque()) {
758
+ return;
759
+ }
760
+ const text = stripControls(String(value));
761
+ const record = parseAbsolute('http://' + text + '/', null);
762
+ if (record === null || record.host === null) {
763
+ return;
764
+ }
765
+ this.record.host = record.host;
766
+ }
767
+ get port() {
768
+ return this.record.port === null ? '' : String(this.record.port);
769
+ }
770
+ set port(value) {
771
+ if (this.isOpaque()) {
772
+ return;
773
+ }
774
+ const text = stripControls(String(value));
775
+ if (text === '') {
776
+ this.record.port = null;
777
+ return;
778
+ }
779
+ const port = parsePort(text, this.record.scheme);
780
+ if (port === undefined) {
781
+ return;
782
+ }
783
+ this.record.port = port;
784
+ }
785
+ get pathname() {
786
+ return pathTextOf(this.record);
787
+ }
788
+ set pathname(value) {
789
+ if (this.isOpaque()) {
790
+ return;
791
+ }
792
+ const text = stripControls(String(value));
793
+ const pieces = text.split('/');
794
+ const start = pieces.length > 0 && pieces[0] === '' ? 1 : 0;
795
+ const segments = [];
796
+ for (let i = start; i < pieces.length; i += 1) {
797
+ segments.push(pctEncode(pieces[i], pathEncodeSet));
798
+ }
799
+ if (segments.length === 0) {
800
+ segments.push('');
801
+ }
802
+ this.record.path = normalizePathSegments(segments, true);
803
+ }
804
+ get search() {
805
+ // 注意:query 为 '' 时("有 ? 但后面什么都没有")search 是 '',
806
+ // 但 href 里仍保留那个 '?' —— 这两者不一致是 Node 的实际行为。
807
+ return this.record.query === null || this.record.query === '' ? '' : '?' + this.record.query;
808
+ }
809
+ set search(value) {
810
+ const text = stripControls(String(value));
811
+ if (text === '' || text === '?') {
812
+ this.record.query = null;
813
+ this.searchParams = this.buildSearchParams();
814
+ return;
815
+ }
816
+ const trimmed = text.charAt(0) === '?' ? text.slice(1) : text;
817
+ const special = isSpecialScheme(this.record.scheme);
818
+ this.record.query = pctEncode(trimmed, special ? specialQueryEncodeSet : queryEncodeSet);
819
+ this.searchParams = this.buildSearchParams();
820
+ }
821
+ get hash() {
822
+ return this.record.fragment === null || this.record.fragment === '' ? '' : '#' + this.record.fragment;
823
+ }
824
+ set hash(value) {
825
+ const text = stripControls(String(value));
826
+ if (text === '' || text === '#') {
827
+ this.record.fragment = null;
828
+ return;
829
+ }
830
+ const trimmed = text.charAt(0) === '#' ? text.slice(1) : text;
831
+ this.record.fragment = pctEncode(trimmed, fragmentEncodeSet);
832
+ }
833
+ toString() {
834
+ return this.href;
835
+ }
836
+ toJSON() {
837
+ return this.href;
838
+ }
839
+ static canParse(input, base) {
840
+ try {
841
+ const url = base === undefined || base === null ? new URL(input) : new URL(input, base);
842
+ return url.href.length > 0;
843
+ }
844
+ catch (failure) {
845
+ return false;
846
+ }
847
+ }
848
+ static parse(input, base) {
849
+ try {
850
+ return base === undefined || base === null ? new URL(input) : new URL(input, base);
851
+ }
852
+ catch (failure) {
853
+ return null;
854
+ }
855
+ }
856
+ }
857
+ exports.URL = URL;