forked from SamVerschueren/decode-uri-component
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
90 lines (71 loc) · 2.12 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
const token = '%[a-f0-9]{2}';
const singleMatcher = new RegExp('(' + token + ')|([^%]+?)', 'gi');
const multiMatcher = new RegExp('(' + token + ')+', 'gi');
function decodeComponents(components, split) {
try {
// Try to decode the entire string first
return [decodeURIComponent(components.join(''))];
} catch {
// Do nothing
}
if (components.length === 1) {
return components;
}
split = split || 1;
// Split the array in 2 parts
const left = components.slice(0, split);
const right = components.slice(split);
return Array.prototype.concat.call([], decodeComponents(left), decodeComponents(right));
}
function decode(input) {
try {
return decodeURIComponent(input);
} catch {
let tokens = input.match(singleMatcher) || [];
for (let i = 1; i < tokens.length; i++) {
input = decodeComponents(tokens, i).join('');
tokens = input.match(singleMatcher) || [];
}
return input;
}
}
function customDecodeURIComponent(input) {
// Keep track of all the replacements and prefill the map with the `BOM`
const replaceMap = {
'%FE%FF': '\uFFFD\uFFFD',
'%FF%FE': '\uFFFD\uFFFD',
};
let match = multiMatcher.exec(input);
while (match) {
try {
// Decode as big chunks as possible
replaceMap[match[0]] = decodeURIComponent(match[0]);
} catch {
const result = decode(match[0]);
if (result !== match[0]) {
replaceMap[match[0]] = result;
}
}
match = multiMatcher.exec(input);
}
// Add `%C2` at the end of the map to make sure it does not replace the combinator before everything else
replaceMap['%C2'] = '\uFFFD';
const entries = Object.keys(replaceMap);
for (const key of entries) {
// Replace all decoded components
input = input.replace(new RegExp(key, 'g'), replaceMap[key]);
}
return input;
}
export default function decodeUriComponent(encodedURI) {
if (typeof encodedURI !== 'string') {
throw new TypeError('Expected `encodedURI` to be of type `string`, got `' + typeof encodedURI + '`');
}
try {
// Try the built in decoder first
return decodeURIComponent(encodedURI);
} catch {
// Fallback to a more advanced decoder
return customDecodeURIComponent(encodedURI);
}
}