-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
156 lines (121 loc) · 3.09 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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
* Module dependencies
*/
var base64 = require('urlsafe-base64');
var LRU = require('lru-cache');
var url = require('url');
/**
* Create a global cache for non-context functions
*/
var globalCache = new LRU(1000);
/**
* Create a url context
*
* @param {String} API_URL
* @return {Object}
*/
exports = module.exports = function(API_URL) {
var cache = new LRU(1000);
var parts = API_URL ? url.parse(API_URL) : false;
if (parts) parts.href = parts.href.replace(/\/$/, '');
return {
encode: encode.bind(null, cache, parts),
encodeParams: encodeParams.bind(null, cache, parts),
decode: decode.bind(null, cache, parts),
decodeParams: decodeParams.bind(null, cache, parts)
};
};
exports['default'] = exports;
/**
* Expose the raw encode function
*/
exports.encode = encode.bind(null, globalCache);
/**
* Expose the raw encode params function
*/
exports.encodeParams = encodeParams.bind(null, globalCache);
/**
* Expose the raw decode function
*/
exports.decode = decode.bind(null, globalCache);
/**
* Expose the raw decode params function
*/
exports.encodeParams = decodeParams.bind(null, globalCache);
/**
* Encode an href object
*/
function encode(cache, API_URL, obj) {
if (!obj) return null;
if (!obj.href) return obj;
var href = API_URL ?
pack(obj.href, API_URL) :
obj.href;
var cached = cache.get(href);
if (cached) return cached;
var encoded = base64.encode(new Buffer(href)).toString();
cache.set(href, encoded);
return encoded;
}
/**
* Encode a set of params
*/
function encodeParams(cache, API_URL, params) {
var obj = {}, v;
for (var k in params) {
if (!params.hasOwnProperty(k)) continue;
v = obj[k] = encode(cache, API_URL, params[k]);
if (!v) return;
}
return obj;
}
/**
* Decode an encoded uri component
*/
function decode(cache, API_URL, str) {
var cached = cache.get(str);
if (typeof cached !== 'undefined') return cached;
if (typeof str !== 'string') return null;
var decoded = base64.decode(str).toString().replace(/\0/g, '');
var out = validate(decoded) ?
{href: unpack(decoded, API_URL)} :
str;
// cache the decoded value since this ends up being pretty expensive
cache.set(str, out);
return out;
}
/**
* Decode a set of params
*/
function decodeParams(cache, API_URL, params) {
var obj = {}, v;
for (var k in params) {
if (!params.hasOwnProperty(k)) continue;
obj[k] = decode(cache, API_URL, params[k]);
}
return obj;
}
var IS_URL = /^(~|http|\/)/;
var INVALID_URL_CHARS = /[^a-z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\.\-\_\~\%]/i;
/**
* Validate url values
*/
function validate(str) {
return IS_URL.test(str) && !INVALID_URL_CHARS.test(str);
}
/**
* replace the API_URL with ~
*/
function pack(href, API_URL) {
var parts = url.parse(href);
var pn = API_URL.pathname || '/';
if (parts.host !== API_URL.host || parts.pathname.indexOf(pn) !== 0) return href;
if (pn === '/') pn = '';
return parts.pathname.replace(pn, '~') + (parts.search || '');
}
/**
* replace ~ with API_URL
*/
function unpack(href, API_URL) {
return href.replace(/^~/, API_URL.href);
}