Skip to content

Latest commit

 

History

History
126 lines (108 loc) · 3.27 KB

File metadata and controls

126 lines (108 loc) · 3.27 KB
 
Sep 9, 2022
Sep 9, 2022
1
"use strict";
2
Sep 5, 2022
Sep 5, 2022
3
const fastDecode = require("fast-decode-uri-component");
Sep 5, 2022
Sep 5, 2022
4
Sep 6, 2022
Sep 6, 2022
5
const plusRegex = /\+/g;
Sep 8, 2022
Sep 8, 2022
6
const Empty = function () {};
7
Empty.prototype = Object.create(null);
Sep 6, 2022
Sep 6, 2022
8
Sep 3, 2022
Sep 3, 2022
9
/**
10
* @callback parse
11
* @param {string} input
12
*/
13
function parse(input) {
Sep 8, 2022
Sep 8, 2022
14
// Optimization: Use new Empty() instead of Object.create(null) for performance
15
// v8 has a better optimization for initializing functions compared to Object
16
const result = new Empty();
Sep 5, 2022
Sep 5, 2022
17
Sep 5, 2022
Sep 5, 2022
18
if (typeof input !== "string") {
Sep 5, 2022
Sep 5, 2022
19
return result;
Sep 5, 2022
Sep 5, 2022
20
}
Sep 3, 2022
Sep 3, 2022
21
Jul 9, 2024
Jul 9, 2024
22
const inputLength = input.length;
Sep 3, 2022
Sep 3, 2022
23
let key = "";
24
let value = "";
Sep 5, 2022
Sep 5, 2022
25
let startingIndex = -1;
26
let equalityIndex = -1;
Sep 6, 2022
Sep 6, 2022
27
let shouldDecodeKey = false;
28
let shouldDecodeValue = false;
29
let keyHasPlus = false;
30
let valueHasPlus = false;
Sep 6, 2022
Sep 6, 2022
31
let hasBothKeyValuePair = false;
Sep 10, 2022
Sep 10, 2022
32
let c = 0;
Sep 3, 2022
Sep 3, 2022
33
34
// Have a boundary of input.length + 1 to access last pair inside the loop.
Sep 6, 2022
Sep 6, 2022
35
for (let i = 0; i < inputLength + 1; i++) {
Sep 10, 2022
Sep 10, 2022
36
c = i !== inputLength ? input.charCodeAt(i) : 38;
Sep 3, 2022
Sep 3, 2022
37
Sep 5, 2022
Sep 5, 2022
38
// Handle '&' and end of line to pass the current values to result
Sep 10, 2022
Sep 10, 2022
39
if (c === 38) {
Sep 6, 2022
Sep 6, 2022
40
hasBothKeyValuePair = equalityIndex > startingIndex;
Sep 10, 2022
Sep 10, 2022
41
42
// Optimization: Reuse equality index to store the end of key
43
if (!hasBothKeyValuePair) {
44
equalityIndex = i;
45
}
46
47
key = input.slice(startingIndex + 1, equalityIndex);
Sep 6, 2022
Sep 6, 2022
48
Sep 5, 2022
Sep 5, 2022
49
// Add key/value pair only if the range size is greater than 1; a.k.a. contains at least "="
Sep 8, 2022
Sep 8, 2022
50
if (hasBothKeyValuePair || key.length > 0) {
Sep 5, 2022
Sep 5, 2022
51
// Optimization: Replace '+' with space
Sep 6, 2022
Sep 6, 2022
52
if (keyHasPlus) {
Sep 6, 2022
Sep 6, 2022
53
key = key.replace(plusRegex, " ");
Sep 6, 2022
Sep 6, 2022
54
}
55
Sep 3, 2022
Sep 3, 2022
56
// Optimization: Do not decode if it's not necessary.
Sep 6, 2022
Sep 6, 2022
57
if (shouldDecodeKey) {
Sep 5, 2022
Sep 5, 2022
58
key = fastDecode(key) || key;
Sep 6, 2022
Sep 6, 2022
59
}
60
Sep 6, 2022
Sep 6, 2022
61
if (hasBothKeyValuePair) {
Sep 8, 2022
Sep 8, 2022
62
value = input.slice(equalityIndex + 1, i);
63
Sep 6, 2022
Sep 6, 2022
64
if (valueHasPlus) {
Sep 6, 2022
Sep 6, 2022
65
value = value.replace(plusRegex, " ");
Sep 6, 2022
Sep 6, 2022
66
}
67
68
if (shouldDecodeValue) {
69
value = fastDecode(value) || value;
70
}
Sep 3, 2022
Sep 3, 2022
71
}
Sep 8, 2022
Sep 8, 2022
72
const currentValue = result[key];
Sep 3, 2022
Sep 3, 2022
73
Sep 8, 2022
Sep 8, 2022
74
if (currentValue === undefined) {
Sep 3, 2022
Sep 3, 2022
75
result[key] = value;
76
} else {
Sep 6, 2022
Sep 6, 2022
77
// Optimization: value.pop is faster than Array.isArray(value)
Sep 3, 2022
Sep 3, 2022
78
if (currentValue.pop) {
79
currentValue.push(value);
80
} else {
81
result[key] = [currentValue, value];
82
}
83
}
Sep 3, 2022
Sep 3, 2022
84
}
85
Sep 3, 2022
Sep 3, 2022
86
// Reset reading key value pairs
Sep 5, 2022
Sep 5, 2022
87
value = "";
Sep 5, 2022
Sep 5, 2022
88
startingIndex = i;
89
equalityIndex = i;
Sep 6, 2022
Sep 6, 2022
90
shouldDecodeKey = false;
91
shouldDecodeValue = false;
92
keyHasPlus = false;
93
valueHasPlus = false;
Sep 3, 2022
Sep 3, 2022
94
}
Sep 5, 2022
Sep 5, 2022
95
// Check '='
Sep 3, 2022
Sep 3, 2022
96
else if (c === 61) {
Sep 8, 2022
Sep 8, 2022
97
if (equalityIndex <= startingIndex) {
98
equalityIndex = i;
99
}
Sep 5, 2022
Sep 5, 2022
100
// If '=' character occurs again, we should decode the input.
Sep 8, 2022
Sep 8, 2022
101
else {
Sep 6, 2022
Sep 6, 2022
102
shouldDecodeValue = true;
Sep 5, 2022
Sep 5, 2022
103
}
Sep 3, 2022
Sep 3, 2022
104
}
Sep 6, 2022
Sep 6, 2022
105
// Check '+', and remember to replace it with empty space.
Sep 3, 2022
Sep 3, 2022
106
else if (c === 43) {
Sep 8, 2022
Sep 8, 2022
107
if (equalityIndex > startingIndex) {
Sep 6, 2022
Sep 6, 2022
108
valueHasPlus = true;
Sep 8, 2022
Sep 8, 2022
109
} else {
110
keyHasPlus = true;
Sep 6, 2022
Sep 6, 2022
111
}
Sep 5, 2022
Sep 5, 2022
112
}
113
// Check '%' character for encoding
114
else if (c === 37) {
Sep 8, 2022
Sep 8, 2022
115
if (equalityIndex > startingIndex) {
Sep 6, 2022
Sep 6, 2022
116
shouldDecodeValue = true;
Sep 8, 2022
Sep 8, 2022
117
} else {
118
shouldDecodeKey = true;
Sep 6, 2022
Sep 6, 2022
119
}
Sep 3, 2022
Sep 3, 2022
120
}
121
}
122
123
return result;
124
}
125
126
module.exports = parse;