This repository has been archived by the owner on May 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 65
/
context.js
98 lines (92 loc) · 2.88 KB
/
context.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
/**
* Validate a context kind.
* @param {string} kind
* @returns true if the kind is valid.
*/
function validKind(kind) {
return typeof kind === 'string' && kind !== 'kind' && kind.match(/^(\w|\.|-)+$/);
}
/**
* Validate a context key.
* @param {string} key
* @returns true if the key is valid.
*/
function validKey(key) {
return key !== undefined && key !== null && key !== '' && typeof key === 'string';
}
/**
* Perform a check of basic context requirements.
* @param {Object} context
* @param {boolean} allowLegacyKey If true, then a legacy user can have an
* empty or non-string key. A legacy user is a context without a kind.
* @returns true if the context meets basic requirements.
*/
function checkContext(context, allowLegacyKey) {
if (context) {
if (allowLegacyKey && (context.kind === undefined || context.kind === null)) {
return context.key !== undefined && context.key !== null;
}
const key = context.key;
const kind = context.kind === undefined ? 'user' : context.kind;
const kindValid = validKind(kind);
const keyValid = kind === 'multi' || validKey(key);
if (kind === 'multi') {
const kinds = Object.keys(context).filter(key => key !== 'kind');
return keyValid && kinds.every(key => validKind(key)) && kinds.every(key => validKey(context[key].key));
}
return keyValid && kindValid;
}
return false;
}
/**
* The partial URL encoding is needed because : is a valid character in context keys.
*
* Partial encoding is the replacement of all colon (:) characters with the URL
* encoded equivalent (%3A) and all percent (%) characters with the URL encoded
* equivalent (%25).
* @param {string} key The key to encode.
* @returns {string} Partially URL encoded key.
*/
function encodeKey(key) {
if (key.includes('%') || key.includes(':')) {
return key.replace(/%/g, '%25').replace(/:/g, '%3A');
}
return key;
}
/**
* For a given context get a list of context kinds.
* @param {Object} context
* @returns A list of kinds in the context.
*/
function getContextKinds(context) {
if (context) {
if (context.kind === null || context.kind === undefined) {
return ['user'];
}
if (context.kind !== 'multi') {
return [context.kind];
}
return Object.keys(context).filter(kind => kind !== 'kind');
}
return [];
}
function getCanonicalKey(context) {
if (context) {
if ((context.kind === undefined || context.kind === null || context.kind === 'user') && context.key) {
return context.key;
} else if (context.kind !== 'multi' && context.key) {
return `${context.kind}:${encodeKey(context.key)}`;
} else if (context.kind === 'multi') {
return Object.keys(context)
.sort()
.filter(key => key !== 'kind')
.map(key => `${key}:${encodeKey(context[key].key)}`)
.join(':');
}
}
}
module.exports = {
checkContext,
getContextKinds,
getCanonicalKey,
};