fast-uri 3.0.6 → 3.1.1
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/.github/workflows/ci.yml +53 -5
- package/.github/workflows/lock-threads.yml +19 -0
- package/.github/workflows/package-manager-ci.yml +6 -2
- package/LICENSE +1 -1
- package/README.md +48 -28
- package/benchmark/benchmark.mjs +159 -0
- package/benchmark/equal.mjs +51 -0
- package/benchmark/non-simple-domain.mjs +22 -0
- package/benchmark/package.json +17 -0
- package/benchmark/string-array-to-hex-stripped.mjs +24 -0
- package/benchmark/ws-is-secure.mjs +65 -0
- package/index.js +100 -65
- package/lib/schemes.js +160 -81
- package/lib/utils.js +304 -126
- package/package.json +8 -8
- package/test/ajv.test.js +7 -3
- package/test/equal.test.js +7 -2
- package/test/fixtures/uri-js-parse.json +501 -0
- package/test/fixtures/uri-js-serialize.json +120 -0
- package/test/parse.test.js +31 -31
- package/test/resolve.test.js +52 -49
- package/test/rfc-3986.test.js +90 -0
- package/test/security-normalization.test.js +39 -0
- package/test/serialize.test.js +55 -47
- package/test/uri-js-compatibility.test.js +33 -0
- package/test/uri-js.test.js +230 -230
- package/test/util.test.js +23 -8
- package/tsconfig.json +9 -0
- package/types/index.d.ts +7 -0
- package/.github/.stale.yml +0 -21
- package/.github/tests_checker.yml +0 -8
- package/benchmark.js +0 -105
- package/lib/scopedChars.js +0 -30
- package/test/.gitkeep +0 -0
- package/test/compatibility.test.js +0 -131
package/lib/utils.js
CHANGED
|
@@ -1,61 +1,108 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/** @type {(value: string) => boolean} */
|
|
4
|
+
const isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
/** @type {(value: string) => boolean} */
|
|
7
|
+
const isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u)
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
}
|
|
9
|
+
/** @type {(value: string) => boolean} */
|
|
10
|
+
const isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu)
|
|
11
|
+
|
|
12
|
+
/** @type {(value: string) => boolean} */
|
|
13
|
+
const isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu)
|
|
14
|
+
|
|
15
|
+
/** @type {(value: string) => boolean} */
|
|
16
|
+
const isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu)
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* @param {string
|
|
20
|
-
* @
|
|
21
|
-
* @returns {string|undefined}
|
|
19
|
+
* @param {Array<string>} input
|
|
20
|
+
* @returns {string}
|
|
22
21
|
*/
|
|
23
|
-
function stringArrayToHexStripped (input
|
|
22
|
+
function stringArrayToHexStripped (input) {
|
|
24
23
|
let acc = ''
|
|
25
|
-
let
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
let code = 0
|
|
25
|
+
let i = 0
|
|
26
|
+
|
|
27
|
+
for (i = 0; i < input.length; i++) {
|
|
28
|
+
code = input[i].charCodeAt(0)
|
|
29
|
+
if (code === 48) {
|
|
30
|
+
continue
|
|
31
|
+
}
|
|
32
|
+
if (!((code >= 48 && code <= 57) || (code >= 65 && code <= 70) || (code >= 97 && code <= 102))) {
|
|
33
|
+
return ''
|
|
34
|
+
}
|
|
35
|
+
acc += input[i]
|
|
36
|
+
break
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (i += 1; i < input.length; i++) {
|
|
40
|
+
code = input[i].charCodeAt(0)
|
|
41
|
+
if (!((code >= 48 && code <= 57) || (code >= 65 && code <= 70) || (code >= 97 && code <= 102))) {
|
|
42
|
+
return ''
|
|
43
|
+
}
|
|
44
|
+
acc += input[i]
|
|
30
45
|
}
|
|
31
|
-
if (keepZero && acc.length === 0) acc = '0'
|
|
32
46
|
return acc
|
|
33
47
|
}
|
|
34
48
|
|
|
49
|
+
/**
|
|
50
|
+
* @typedef {Object} GetIPV6Result
|
|
51
|
+
* @property {boolean} error - Indicates if there was an error parsing the IPv6 address.
|
|
52
|
+
* @property {string} address - The parsed IPv6 address.
|
|
53
|
+
* @property {string} [zone] - The zone identifier, if present.
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {string} value
|
|
58
|
+
* @returns {boolean}
|
|
59
|
+
*/
|
|
60
|
+
const nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u)
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {Array<string>} buffer
|
|
64
|
+
* @returns {boolean}
|
|
65
|
+
*/
|
|
66
|
+
function consumeIsZone (buffer) {
|
|
67
|
+
buffer.length = 0
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {Array<string>} buffer
|
|
73
|
+
* @param {Array<string>} address
|
|
74
|
+
* @param {GetIPV6Result} output
|
|
75
|
+
* @returns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
function consumeHextets (buffer, address, output) {
|
|
78
|
+
if (buffer.length) {
|
|
79
|
+
const hex = stringArrayToHexStripped(buffer)
|
|
80
|
+
if (hex !== '') {
|
|
81
|
+
address.push(hex)
|
|
82
|
+
} else {
|
|
83
|
+
output.error = true
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
buffer.length = 0
|
|
87
|
+
}
|
|
88
|
+
return true
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {string} input
|
|
93
|
+
* @returns {GetIPV6Result}
|
|
94
|
+
*/
|
|
35
95
|
function getIPV6 (input) {
|
|
36
96
|
let tokenCount = 0
|
|
37
97
|
const output = { error: false, address: '', zone: '' }
|
|
98
|
+
/** @type {Array<string>} */
|
|
38
99
|
const address = []
|
|
100
|
+
/** @type {Array<string>} */
|
|
39
101
|
const buffer = []
|
|
40
|
-
let isZone = false
|
|
41
102
|
let endipv6Encountered = false
|
|
42
103
|
let endIpv6 = false
|
|
43
104
|
|
|
44
|
-
|
|
45
|
-
if (buffer.length) {
|
|
46
|
-
if (isZone === false) {
|
|
47
|
-
const hex = stringArrayToHexStripped(buffer)
|
|
48
|
-
if (hex !== undefined) {
|
|
49
|
-
address.push(hex)
|
|
50
|
-
} else {
|
|
51
|
-
output.error = true
|
|
52
|
-
return false
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
buffer.length = 0
|
|
56
|
-
}
|
|
57
|
-
return true
|
|
58
|
-
}
|
|
105
|
+
let consume = consumeHextets
|
|
59
106
|
|
|
60
107
|
for (let i = 0; i < input.length; i++) {
|
|
61
108
|
const cursor = input[i]
|
|
@@ -64,29 +111,28 @@ function getIPV6 (input) {
|
|
|
64
111
|
if (endipv6Encountered === true) {
|
|
65
112
|
endIpv6 = true
|
|
66
113
|
}
|
|
67
|
-
if (!consume()) { break }
|
|
68
|
-
tokenCount
|
|
69
|
-
address.push(':')
|
|
70
|
-
if (tokenCount > 7) {
|
|
114
|
+
if (!consume(buffer, address, output)) { break }
|
|
115
|
+
if (++tokenCount > 7) {
|
|
71
116
|
// not valid
|
|
72
117
|
output.error = true
|
|
73
118
|
break
|
|
74
119
|
}
|
|
75
|
-
if (i
|
|
120
|
+
if (i > 0 && input[i - 1] === ':') {
|
|
76
121
|
endipv6Encountered = true
|
|
77
122
|
}
|
|
123
|
+
address.push(':')
|
|
78
124
|
continue
|
|
79
125
|
} else if (cursor === '%') {
|
|
80
|
-
if (!consume()) { break }
|
|
126
|
+
if (!consume(buffer, address, output)) { break }
|
|
81
127
|
// switch to zone detection
|
|
82
|
-
|
|
128
|
+
consume = consumeIsZone
|
|
83
129
|
} else {
|
|
84
130
|
buffer.push(cursor)
|
|
85
131
|
continue
|
|
86
132
|
}
|
|
87
133
|
}
|
|
88
134
|
if (buffer.length) {
|
|
89
|
-
if (
|
|
135
|
+
if (consume === consumeIsZone) {
|
|
90
136
|
output.zone = buffer.join('')
|
|
91
137
|
} else if (endIpv6) {
|
|
92
138
|
address.push(buffer.join(''))
|
|
@@ -98,6 +144,17 @@ function getIPV6 (input) {
|
|
|
98
144
|
return output
|
|
99
145
|
}
|
|
100
146
|
|
|
147
|
+
/**
|
|
148
|
+
* @typedef {Object} NormalizeIPv6Result
|
|
149
|
+
* @property {string} host - The normalized host.
|
|
150
|
+
* @property {string} [escapedHost] - The escaped host.
|
|
151
|
+
* @property {boolean} isIPV6 - Indicates if the host is an IPv6 address.
|
|
152
|
+
*/
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @param {string} host
|
|
156
|
+
* @returns {NormalizeIPv6Result}
|
|
157
|
+
*/
|
|
101
158
|
function normalizeIPv6 (host) {
|
|
102
159
|
if (findToken(host, ':') < 2) { return { host, isIPV6: false } }
|
|
103
160
|
const ipv6 = getIPV6(host)
|
|
@@ -109,35 +166,17 @@ function normalizeIPv6 (host) {
|
|
|
109
166
|
newHost += '%' + ipv6.zone
|
|
110
167
|
escapedHost += '%25' + ipv6.zone
|
|
111
168
|
}
|
|
112
|
-
return { host: newHost,
|
|
169
|
+
return { host: newHost, isIPV6: true, escapedHost }
|
|
113
170
|
} else {
|
|
114
171
|
return { host, isIPV6: false }
|
|
115
172
|
}
|
|
116
173
|
}
|
|
117
174
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const c = str[i]
|
|
124
|
-
if (c === '0' && skip) {
|
|
125
|
-
if ((i + 1 <= l && str[i + 1] === token) || i + 1 === l) {
|
|
126
|
-
out += c
|
|
127
|
-
skip = false
|
|
128
|
-
}
|
|
129
|
-
} else {
|
|
130
|
-
if (c === token) {
|
|
131
|
-
skip = true
|
|
132
|
-
} else {
|
|
133
|
-
skip = false
|
|
134
|
-
}
|
|
135
|
-
out += c
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return out
|
|
139
|
-
}
|
|
140
|
-
|
|
175
|
+
/**
|
|
176
|
+
* @param {string} str
|
|
177
|
+
* @param {string} token
|
|
178
|
+
* @returns {number}
|
|
179
|
+
*/
|
|
141
180
|
function findToken (str, token) {
|
|
142
181
|
let ind = 0
|
|
143
182
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -146,99 +185,238 @@ function findToken (str, token) {
|
|
|
146
185
|
return ind
|
|
147
186
|
}
|
|
148
187
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
188
|
+
/**
|
|
189
|
+
* @param {string} path
|
|
190
|
+
* @returns {string}
|
|
191
|
+
*
|
|
192
|
+
* @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
|
|
193
|
+
*/
|
|
194
|
+
function removeDotSegments (path) {
|
|
195
|
+
let input = path
|
|
155
196
|
const output = []
|
|
197
|
+
let nextSlash = -1
|
|
198
|
+
let len = 0
|
|
156
199
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
} else if (input === '.' || input === '..') {
|
|
166
|
-
input = ''
|
|
167
|
-
} else {
|
|
168
|
-
const im = input.match(RDS5)
|
|
169
|
-
if (im) {
|
|
170
|
-
const s = im[0]
|
|
171
|
-
input = input.slice(s.length)
|
|
172
|
-
output.push(s)
|
|
200
|
+
// eslint-disable-next-line no-cond-assign
|
|
201
|
+
while (len = input.length) {
|
|
202
|
+
if (len === 1) {
|
|
203
|
+
if (input === '.') {
|
|
204
|
+
break
|
|
205
|
+
} else if (input === '/') {
|
|
206
|
+
output.push('/')
|
|
207
|
+
break
|
|
173
208
|
} else {
|
|
174
|
-
|
|
209
|
+
output.push(input)
|
|
210
|
+
break
|
|
211
|
+
}
|
|
212
|
+
} else if (len === 2) {
|
|
213
|
+
if (input[0] === '.') {
|
|
214
|
+
if (input[1] === '.') {
|
|
215
|
+
break
|
|
216
|
+
} else if (input[1] === '/') {
|
|
217
|
+
input = input.slice(2)
|
|
218
|
+
continue
|
|
219
|
+
}
|
|
220
|
+
} else if (input[0] === '/') {
|
|
221
|
+
if (input[1] === '.' || input[1] === '/') {
|
|
222
|
+
output.push('/')
|
|
223
|
+
break
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
} else if (len === 3) {
|
|
227
|
+
if (input === '/..') {
|
|
228
|
+
if (output.length !== 0) {
|
|
229
|
+
output.pop()
|
|
230
|
+
}
|
|
231
|
+
output.push('/')
|
|
232
|
+
break
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (input[0] === '.') {
|
|
236
|
+
if (input[1] === '.') {
|
|
237
|
+
if (input[2] === '/') {
|
|
238
|
+
input = input.slice(3)
|
|
239
|
+
continue
|
|
240
|
+
}
|
|
241
|
+
} else if (input[1] === '/') {
|
|
242
|
+
input = input.slice(2)
|
|
243
|
+
continue
|
|
175
244
|
}
|
|
245
|
+
} else if (input[0] === '/') {
|
|
246
|
+
if (input[1] === '.') {
|
|
247
|
+
if (input[2] === '/') {
|
|
248
|
+
input = input.slice(2)
|
|
249
|
+
continue
|
|
250
|
+
} else if (input[2] === '.') {
|
|
251
|
+
if (input[3] === '/') {
|
|
252
|
+
input = input.slice(3)
|
|
253
|
+
if (output.length !== 0) {
|
|
254
|
+
output.pop()
|
|
255
|
+
}
|
|
256
|
+
continue
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Rule 2E: Move normal path segment to output
|
|
263
|
+
if ((nextSlash = input.indexOf('/', 1)) === -1) {
|
|
264
|
+
output.push(input)
|
|
265
|
+
break
|
|
266
|
+
} else {
|
|
267
|
+
output.push(input.slice(0, nextSlash))
|
|
268
|
+
input = input.slice(nextSlash)
|
|
176
269
|
}
|
|
177
270
|
}
|
|
271
|
+
|
|
178
272
|
return output.join('')
|
|
179
273
|
}
|
|
180
274
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
275
|
+
/**
|
|
276
|
+
* Normalizes percent escapes and optionally decodes only unreserved ASCII bytes.
|
|
277
|
+
* Reserved delimiters such as `%2F` and `%2E` stay escaped.
|
|
278
|
+
*
|
|
279
|
+
* @param {string} input
|
|
280
|
+
* @param {boolean} [decodeUnreserved=false]
|
|
281
|
+
* @returns {string}
|
|
282
|
+
*/
|
|
283
|
+
function normalizePercentEncoding (input, decodeUnreserved = false) {
|
|
284
|
+
if (input.indexOf('%') === -1) {
|
|
285
|
+
return input
|
|
191
286
|
}
|
|
192
|
-
|
|
193
|
-
|
|
287
|
+
|
|
288
|
+
let output = ''
|
|
289
|
+
|
|
290
|
+
for (let i = 0; i < input.length; i++) {
|
|
291
|
+
if (input[i] === '%' && i + 2 < input.length) {
|
|
292
|
+
const hex = input.slice(i + 1, i + 3)
|
|
293
|
+
if (isHexPair(hex)) {
|
|
294
|
+
const normalizedHex = hex.toUpperCase()
|
|
295
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16))
|
|
296
|
+
|
|
297
|
+
if (decodeUnreserved && isUnreserved(decoded)) {
|
|
298
|
+
output += decoded
|
|
299
|
+
} else {
|
|
300
|
+
output += '%' + normalizedHex
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
i += 2
|
|
304
|
+
continue
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
output += input[i]
|
|
194
309
|
}
|
|
195
|
-
|
|
196
|
-
|
|
310
|
+
|
|
311
|
+
return output
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Normalizes path data without turning reserved escapes into live path syntax.
|
|
316
|
+
* Valid escapes are uppercased, raw unsafe characters are escaped, and only
|
|
317
|
+
* unreserved bytes that are not `.` are decoded.
|
|
318
|
+
*
|
|
319
|
+
* @param {string} input
|
|
320
|
+
* @returns {string}
|
|
321
|
+
*/
|
|
322
|
+
function normalizePathEncoding (input) {
|
|
323
|
+
let output = ''
|
|
324
|
+
|
|
325
|
+
for (let i = 0; i < input.length; i++) {
|
|
326
|
+
if (input[i] === '%' && i + 2 < input.length) {
|
|
327
|
+
const hex = input.slice(i + 1, i + 3)
|
|
328
|
+
if (isHexPair(hex)) {
|
|
329
|
+
const normalizedHex = hex.toUpperCase()
|
|
330
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16))
|
|
331
|
+
|
|
332
|
+
if (decoded !== '.' && isUnreserved(decoded)) {
|
|
333
|
+
output += decoded
|
|
334
|
+
} else {
|
|
335
|
+
output += '%' + normalizedHex
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
i += 2
|
|
339
|
+
continue
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (isPathCharacter(input[i])) {
|
|
344
|
+
output += input[i]
|
|
345
|
+
} else {
|
|
346
|
+
output += escape(input[i])
|
|
347
|
+
}
|
|
197
348
|
}
|
|
198
|
-
|
|
199
|
-
|
|
349
|
+
|
|
350
|
+
return output
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Escapes a component while preserving existing valid percent escapes.
|
|
355
|
+
*
|
|
356
|
+
* @param {string} input
|
|
357
|
+
* @returns {string}
|
|
358
|
+
*/
|
|
359
|
+
function escapePreservingEscapes (input) {
|
|
360
|
+
let output = ''
|
|
361
|
+
|
|
362
|
+
for (let i = 0; i < input.length; i++) {
|
|
363
|
+
if (input[i] === '%' && i + 2 < input.length) {
|
|
364
|
+
const hex = input.slice(i + 1, i + 3)
|
|
365
|
+
if (isHexPair(hex)) {
|
|
366
|
+
output += '%' + hex.toUpperCase()
|
|
367
|
+
i += 2
|
|
368
|
+
continue
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
output += escape(input[i])
|
|
200
373
|
}
|
|
201
|
-
|
|
374
|
+
|
|
375
|
+
return output
|
|
202
376
|
}
|
|
203
377
|
|
|
204
|
-
|
|
378
|
+
/**
|
|
379
|
+
* @param {import('../types/index').URIComponent} component
|
|
380
|
+
* @returns {string|undefined}
|
|
381
|
+
*/
|
|
382
|
+
function recomposeAuthority (component) {
|
|
205
383
|
const uriTokens = []
|
|
206
384
|
|
|
207
|
-
if (
|
|
208
|
-
uriTokens.push(
|
|
385
|
+
if (component.userinfo !== undefined) {
|
|
386
|
+
uriTokens.push(component.userinfo)
|
|
209
387
|
uriTokens.push('@')
|
|
210
388
|
}
|
|
211
389
|
|
|
212
|
-
if (
|
|
213
|
-
let host = unescape(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (ipV4res.isIPV4) {
|
|
217
|
-
host = ipV4res.host
|
|
218
|
-
} else {
|
|
219
|
-
const ipV6res = normalizeIPv6(ipV4res.host)
|
|
390
|
+
if (component.host !== undefined) {
|
|
391
|
+
let host = unescape(component.host)
|
|
392
|
+
if (!isIPv4(host)) {
|
|
393
|
+
const ipV6res = normalizeIPv6(host)
|
|
220
394
|
if (ipV6res.isIPV6 === true) {
|
|
221
395
|
host = `[${ipV6res.escapedHost}]`
|
|
222
396
|
} else {
|
|
223
|
-
host =
|
|
397
|
+
host = component.host
|
|
224
398
|
}
|
|
225
399
|
}
|
|
226
400
|
uriTokens.push(host)
|
|
227
401
|
}
|
|
228
402
|
|
|
229
|
-
if (typeof
|
|
403
|
+
if (typeof component.port === 'number' || typeof component.port === 'string') {
|
|
230
404
|
uriTokens.push(':')
|
|
231
|
-
uriTokens.push(String(
|
|
405
|
+
uriTokens.push(String(component.port))
|
|
232
406
|
}
|
|
233
407
|
|
|
234
408
|
return uriTokens.length ? uriTokens.join('') : undefined
|
|
235
409
|
};
|
|
236
410
|
|
|
237
411
|
module.exports = {
|
|
412
|
+
nonSimpleDomain,
|
|
238
413
|
recomposeAuthority,
|
|
239
|
-
|
|
414
|
+
normalizePercentEncoding,
|
|
415
|
+
normalizePathEncoding,
|
|
416
|
+
escapePreservingEscapes,
|
|
240
417
|
removeDotSegments,
|
|
241
|
-
|
|
418
|
+
isIPv4,
|
|
419
|
+
isUUID,
|
|
242
420
|
normalizeIPv6,
|
|
243
421
|
stringArrayToHexStripped
|
|
244
422
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-uri",
|
|
3
3
|
"description": "Dependency-free RFC 3986 URI toolbox",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.1.1",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"types": "types/index.d.ts",
|
|
@@ -46,23 +46,23 @@
|
|
|
46
46
|
}
|
|
47
47
|
],
|
|
48
48
|
"scripts": {
|
|
49
|
-
"bench": "node benchmark.js",
|
|
50
49
|
"lint": "eslint",
|
|
51
50
|
"lint:fix": "eslint --fix",
|
|
52
51
|
"test": "npm run test:unit && npm run test:typescript",
|
|
52
|
+
"test:browser:chromium": "playwright-test ./test/* --runner tape --browser=chromium",
|
|
53
|
+
"test:browser:firefox": "playwright-test ./test/* --runner tape --browser=firefox",
|
|
54
|
+
"test:browser:webkit": "playwright-test ./test/* --runner tape --browser=webkit",
|
|
55
|
+
"test:browser": "npm run test:browser:chromium && npm run test:browser:firefox && npm run test:browser:webkit",
|
|
53
56
|
"test:unit": "tape test/**/*.js",
|
|
54
57
|
"test:unit:dev": "npm run test:unit -- --coverage-report=html",
|
|
55
58
|
"test:typescript": "tsd"
|
|
56
59
|
},
|
|
57
60
|
"devDependencies": {
|
|
58
|
-
"@fastify/pre-commit": "^2.1.0",
|
|
59
61
|
"ajv": "^8.16.0",
|
|
60
|
-
"benchmark": "^2.1.4",
|
|
61
|
-
"coveralls": "^3.1.1",
|
|
62
62
|
"eslint": "^9.17.0",
|
|
63
|
-
"neostandard": "^0.
|
|
63
|
+
"neostandard": "^0.13.0",
|
|
64
|
+
"playwright-test": "^14.1.12",
|
|
64
65
|
"tape": "^5.8.1",
|
|
65
|
-
"tsd": "^0.
|
|
66
|
-
"uri-js": "^4.4.1"
|
|
66
|
+
"tsd": "^0.33.0"
|
|
67
67
|
}
|
|
68
68
|
}
|
package/test/ajv.test.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const test = require('tape')
|
|
4
|
+
const fastURI = require('..')
|
|
5
|
+
|
|
1
6
|
const AJV = require('ajv')
|
|
2
|
-
|
|
7
|
+
|
|
3
8
|
const ajv = new AJV({
|
|
4
|
-
uriResolver:
|
|
9
|
+
uriResolver: fastURI // comment this line to see it works with uri-js
|
|
5
10
|
})
|
|
6
|
-
const test = require('tape')
|
|
7
11
|
|
|
8
12
|
test('ajv', t => {
|
|
9
13
|
t.plan(1)
|
package/test/equal.test.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const test = require('tape')
|
|
4
|
-
const
|
|
4
|
+
const fastURI = require('..')
|
|
5
5
|
|
|
6
|
-
const fn =
|
|
6
|
+
const fn = fastURI.equal
|
|
7
7
|
const runTest = (t, suite) => {
|
|
8
8
|
suite.forEach(s => {
|
|
9
9
|
const operator = s.result ? '==' : '!='
|
|
@@ -65,6 +65,11 @@ test('URN Equals', (t) => {
|
|
|
65
65
|
// t.equal(URI.equal('urn:foo:a123%2C456', 'URN:FOO:a123%2c456'), true)
|
|
66
66
|
|
|
67
67
|
runTest(t, suite)
|
|
68
|
+
|
|
69
|
+
t.throws(() => {
|
|
70
|
+
fn('urn:', 'urn:FOO:a123,456')
|
|
71
|
+
}, 'URN without nid cannot be serialized')
|
|
72
|
+
|
|
68
73
|
t.end()
|
|
69
74
|
})
|
|
70
75
|
|