bare-url 2.5.1 → 2.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,27 +1,31 @@
1
- const binding = require('../binding')
2
-
3
1
  const kind = Symbol.for('bare.url.search-params.kind')
4
2
 
5
- class URLSearchParams {
6
- static _urls = new WeakMap()
3
+ // The URL each instance writes back to, if any. Kept module private so that the
4
+ // setter it drives cannot be pointed at an arbitrary object.
5
+ const urls = new WeakMap()
7
6
 
7
+ class URLSearchParams {
8
8
  static get [kind]() {
9
9
  return 0 // Compatibility version
10
10
  }
11
11
 
12
12
  // https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
13
13
  constructor(init, url = null) {
14
- this._params = new Map()
14
+ this._params = null
15
15
 
16
- if (url) URLSearchParams._urls.set(this, url)
16
+ if (url) urls.set(this, url)
17
17
 
18
18
  if (typeof init === 'string') {
19
19
  this._parse(init)
20
- } else if (init) {
21
- for (const [name, value] of typeof init[Symbol.iterator] === 'function'
22
- ? init
23
- : Object.entries(init)) {
24
- this.append(name, value)
20
+ } else {
21
+ this._params = new Map()
22
+
23
+ if (init) {
24
+ for (const [name, value] of typeof init[Symbol.iterator] === 'function'
25
+ ? init
26
+ : Object.entries(init)) {
27
+ this.append(name, value)
28
+ }
25
29
  }
26
30
  }
27
31
  }
@@ -138,7 +142,7 @@ class URLSearchParams {
138
142
 
139
143
  // https://url.spec.whatwg.org/#concept-urlsearchparams-update
140
144
  _update() {
141
- const url = URLSearchParams._urls.get(this)
145
+ const url = urls.get(this)
142
146
 
143
147
  if (url === undefined) return
144
148
 
@@ -147,41 +151,51 @@ class URLSearchParams {
147
151
 
148
152
  // https://url.spec.whatwg.org/#concept-urlencoded-parser
149
153
  _parse(input) {
150
- if (input[0] === '?') input = input.substring(1)
154
+ const params = new Map()
151
155
 
152
- this._params = new Map()
156
+ this._params = params
153
157
 
154
- for (let sequence of input.split('&')) {
155
- if (sequence.length === 0) continue
158
+ const len = input.length
156
159
 
157
- sequence = sequence.replace(/\+/g, ' ')
160
+ let start = input.charCodeAt(0) === 0x3f /* ? */ ? 1 : 0
158
161
 
159
- let i = sequence.indexOf('=')
160
- if (i === -1) i = sequence.length
162
+ while (start < len) {
163
+ let end = input.indexOf('&', start)
164
+ if (end === -1) end = len
161
165
 
162
- const name = decodeURIComponent(sequence.substring(0, i))
163
- const value = decodeURIComponent(sequence.substring(i + 1, sequence.length))
166
+ if (end !== start) {
167
+ let split = input.indexOf('=', start)
168
+ if (split === -1 || split > end) split = end
164
169
 
165
- let list = this._params.get(name)
170
+ const name = decode(input.slice(start, split))
171
+ const value = split === end ? '' : decode(input.slice(split + 1, end))
172
+
173
+ const list = params.get(name)
166
174
 
167
- if (list === undefined) {
168
- list = []
169
- this._params.set(name, list)
175
+ if (list === undefined) params.set(name, [value])
176
+ else list.push(value)
170
177
  }
171
178
 
172
- list.push(value)
179
+ start = end + 1
173
180
  }
174
181
  }
175
182
 
176
183
  // https://url.spec.whatwg.org/#concept-urlencoded-serializer
177
184
  _serialize() {
178
- const pairs = []
185
+ let result = ''
186
+ let separator = ''
179
187
 
180
188
  for (const [name, values] of this._params) {
181
- for (const value of values) pairs.push(String(name), String(value))
189
+ // The name is shared by all of its values, so it is only encoded once.
190
+ const encoded = encode(String(name))
191
+
192
+ for (const value of values) {
193
+ result += separator + encoded + '=' + encode(String(value))
194
+ separator = '&'
195
+ }
182
196
  }
183
197
 
184
- return binding.serializeSearchParams(pairs)
198
+ return result
185
199
  }
186
200
  }
187
201
 
@@ -192,3 +206,71 @@ exports.isURLSearchParams = function isURLSearchParams(value) {
192
206
 
193
207
  return typeof value === 'object' && value !== null && value[kind] === URLSearchParams[kind]
194
208
  }
209
+
210
+ // https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer
211
+ //
212
+ // Everything except ASCII alphanumerics and `*-._` is percent-encoded, and a
213
+ // space becomes `+` rather than `%20`. Names and values usually consist entirely
214
+ // of characters that are left alone, so a component is tested as a whole before
215
+ // any of it is rewritten.
216
+ const unencoded = /^[\w*.-]*$/
217
+
218
+ // As above, but allowing spaces, which need nothing more than turning into `+`.
219
+ // Spaces are by far the most common reason for a component to need rewriting at
220
+ // all, so recognizing them here spares those components a trip through
221
+ // encodeURIComponent().
222
+ const spaced = /^[\w*. -]*$/
223
+
224
+ // The characters that encodeURIComponent() leaves alone but the urlencoded byte
225
+ // serializer does not. Two patterns are needed because a global regular
226
+ // expression cannot be shared between test() and replace(), as test() advances
227
+ // its lastIndex.
228
+ const extra = /[!'()~]/
229
+ const extraAll = /[!'()~]/g
230
+
231
+ const escapes = {
232
+ '!': '%21',
233
+ "'": '%27',
234
+ '(': '%28',
235
+ ')': '%29',
236
+ '~': '%7E'
237
+ }
238
+
239
+ // A surrogate pair, or a surrogate that is not part of one and so encodes no
240
+ // scalar value. Pairs are matched first so that only the capture group can hold
241
+ // a lone surrogate; a lookbehind would say this more directly but isn't
242
+ // supported by every engine.
243
+ const lone = /[\ud800-\udbff][\udc00-\udfff]|([\ud800-\udbff]|[\udc00-\udfff])/g
244
+
245
+ function encode(component) {
246
+ if (unencoded.test(component)) return component
247
+
248
+ if (spaced.test(component)) return component.replaceAll(' ', '+')
249
+
250
+ let encoded
251
+
252
+ try {
253
+ encoded = encodeURIComponent(component)
254
+ } catch {
255
+ // encodeURIComponent() rejects lone surrogates, whereas the UTF-8 encoder the
256
+ // serializer is defined in terms of replaces them with U+FFFD.
257
+ encoded = encodeURIComponent(
258
+ component.replace(lone, (match, single) => (single === undefined ? match : '\ufffd'))
259
+ )
260
+ }
261
+
262
+ if (encoded.includes('%20')) encoded = encoded.replaceAll('%20', '+')
263
+
264
+ if (extra.test(encoded)) encoded = encoded.replace(extraAll, (match) => escapes[match])
265
+
266
+ return encoded
267
+ }
268
+
269
+ // https://url.spec.whatwg.org/#percent-decode-after-encoding
270
+ function decode(component) {
271
+ if (component.indexOf('+') !== -1) component = component.replaceAll('+', ' ')
272
+
273
+ if (component.indexOf('%') === -1) return component
274
+
275
+ return decodeURIComponent(component)
276
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-url",
3
- "version": "2.5.1",
3
+ "version": "2.5.3",
4
4
  "description": "WHATWG URL implementation for JavaScript",
5
5
  "exports": {
6
6
  "./package": "./package.json",
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file