-
-
Notifications
You must be signed in to change notification settings - Fork 62
/
uri-template.js
52 lines (47 loc) · 1.96 KB
/
uri-template.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
// URI Template: https://datatracker.ietf.org/doc/html/rfc6570
const regex = /{([+#./;?&])?([^}]+?)}/g
const varspecRegex = /(.+?)(\*|:[1-9]\d{0,3})?$/
const table = {
undefined: { first: '', sep: ',' },
'+': { first: '', sep: ',', allowReserved: true },
'.': { first: '.', sep: '.' },
'/': { first: '/', sep: '/' },
';': { first: ';', sep: ';', named: true, ifemp: '' },
'?': { first: '?', sep: '&', named: true, ifemp: '=' },
'&': { first: '&', sep: '&', named: true, ifemp: '=' },
'#': { first: '&', sep: '&', allowReserved: true },
}
// 2.4.1 Prefix Values, "Note that this numbering is in characters, not octets"
const prefix = (maxLength, str) => {
let result = ''
for (const char of str) {
const newResult = char
if (newResult.length > maxLength) return result
else result = newResult
}
return result
}
export const replace = (str, map) => str.replace(regex, (_, operator, variableList) => {
const { first, sep, named, ifemp, allowReserved } = table[operator]
// TODO: this isn't spec compliant
const encode = allowReserved ? encodeURI : encodeURIComponent
const values = variableList.split(',').map(varspec => {
const match = varspec.match(varspecRegex)
if (!match) return
const [, name, modifier] = match
let value = map.get(name)
if (modifier?.startsWith(':')) {
const maxLength = parseInt(modifier.slice(1))
value = prefix(maxLength, value)
}
return [name, value ? encode(value) : null]
})
if (!values.filter(([, value]) => value).length) return ''
return first + values
.map(([name, value]) => value
? (named ? name + (value ? '=' + value : ifemp) : value) : '')
.filter(x => x).join(sep)
})
export const getVariables = str => new Set(Array.from(str.matchAll(regex),
([,, variableList]) => variableList.split(',')
.map(varspec => varspec.match(varspecRegex)?.[1])).flat())