@adobe/helix-shared-config 1.7.23 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/package.json +10 -7
- package/src/config-wrapper.js +0 -6
- package/src/index.js +0 -12
- package/src/Condition.js +0 -573
- package/src/ConfigValidator.js +0 -95
- package/src/DataEmbedValidator.js +0 -51
- package/src/DynamicRedirect.js +0 -125
- package/src/HelixConfig.js +0 -133
- package/src/MarkupConfig.js +0 -35
- package/src/Origin.js +0 -159
- package/src/Performance.js +0 -80
- package/src/Redirect.js +0 -64
- package/src/RedirectConfig.js +0 -64
- package/src/RedirectRuleHandler.js +0 -46
- package/src/Static.js +0 -119
- package/src/Strain.js +0 -332
- package/src/Strains.js +0 -68
- package/src/schemas/conditions.schema.json +0 -140
- package/src/schemas/config.description.md +0 -7
- package/src/schemas/config.example.1.json +0 -26
- package/src/schemas/config.schema.json +0 -44
- package/src/schemas/data-embed-response.schema.json +0 -40
- package/src/schemas/giturl.schema.json +0 -62
- package/src/schemas/markup.schema.json +0 -22
- package/src/schemas/markupconfig.schema.json +0 -38
- package/src/schemas/markupmapping.description.md +0 -242
- package/src/schemas/markupmapping.schema.json +0 -122
- package/src/schemas/origin.description.md +0 -5
- package/src/schemas/origin.schema.json +0 -86
- package/src/schemas/performance.schema.json +0 -210
- package/src/schemas/proxystrain.description.md +0 -20
- package/src/schemas/proxystrain.schema.json +0 -87
- package/src/schemas/redirect.schema.json +0 -34
- package/src/schemas/redirectrule.schema.json +0 -46
- package/src/schemas/redirects.description.md +0 -1
- package/src/schemas/redirects.schema.json +0 -41
- package/src/schemas/row.schema.json +0 -23
- package/src/schemas/runtimestrain.schema.json +0 -144
- package/src/schemas/sheet.schema.json +0 -57
- package/src/schemas/staticgiturl.schema.json +0 -80
- package/src/schemas/strains.schema.json +0 -39
- package/src/schemas/vanity.schema.json +0 -38
- package/src/schemas/version-lock.description.md +0 -3
- package/src/schemas/version-lock.schema.json +0 -35
- package/src/schemas/workbook.schema.json +0 -49
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,44 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.0.2](https://github.com/adobe/helix-shared/compare/@adobe/helix-shared-config@2.0.1...@adobe/helix-shared-config@2.0.2) (2022-04-16)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **deps:** update dependency fs-extra to v10.1.0 ([#673](https://github.com/adobe/helix-shared/issues/673)) ([290378c](https://github.com/adobe/helix-shared/commit/290378cc47c42822bce1ad390bfb400b037c71f0))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [2.0.1](https://github.com/adobe/helix-shared/compare/@adobe/helix-shared-config@2.0.0...@adobe/helix-shared-config@2.0.1) (2022-04-16)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* **deps:** update external fixes ([24c8309](https://github.com/adobe/helix-shared/commit/24c830978f296cd3f4fea71983cd028ec1377d3a))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# [2.0.0](https://github.com/adobe/helix-shared/compare/@adobe/helix-shared-config@1.7.23...@adobe/helix-shared-config@2.0.0) (2022-04-11)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Bug Fixes
|
|
32
|
+
|
|
33
|
+
* **deps:** update dependency yaml to v2 and remove unused configs ([e2fd978](https://github.com/adobe/helix-shared/commit/e2fd978130076292c9049822b14718b8b6fa3269))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
### BREAKING CHANGES
|
|
37
|
+
|
|
38
|
+
* **deps:** redirects, markup and helix-config removed
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
6
44
|
## [1.7.23](https://github.com/adobe/helix-shared/compare/@adobe/helix-shared-config@1.7.22...@adobe/helix-shared-config@1.7.23) (2022-04-10)
|
|
7
45
|
|
|
8
46
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-shared-config",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Shared modules of the Helix Project - config",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -22,20 +22,23 @@
|
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
|
+
"mocha": {
|
|
26
|
+
"require": "test/setup-env.js"
|
|
27
|
+
},
|
|
25
28
|
"dependencies": {
|
|
26
29
|
"@adobe/helix-fetch": "^3.0.3",
|
|
27
|
-
"@adobe/helix-shared-git": "^
|
|
30
|
+
"@adobe/helix-shared-git": "^2.0.1",
|
|
28
31
|
"@adobe/helix-shared-prune": "^1.0.4",
|
|
29
|
-
"@adobe/helix-shared-utils": "^2.0.
|
|
32
|
+
"@adobe/helix-shared-utils": "^2.0.8",
|
|
30
33
|
"ajv": "8.11.0",
|
|
31
34
|
"ajv-formats": "2.1.1",
|
|
32
|
-
"cookie": "0.
|
|
33
|
-
"fs-extra": "10.0
|
|
35
|
+
"cookie": "0.5.0",
|
|
36
|
+
"fs-extra": "10.1.0",
|
|
34
37
|
"ignore": "5.2.0",
|
|
35
38
|
"lru-cache": "7.8.1",
|
|
36
39
|
"object-hash": "3.0.0",
|
|
37
40
|
"uri-js": "4.4.1",
|
|
38
|
-
"yaml": "
|
|
41
|
+
"yaml": "2.0.1"
|
|
39
42
|
},
|
|
40
43
|
"devDependencies": {
|
|
41
44
|
"@adobe/helix-shared-wrap": "^1.0.4",
|
|
@@ -46,5 +49,5 @@
|
|
|
46
49
|
"mocha": "9.2.2",
|
|
47
50
|
"nock": "13.2.4"
|
|
48
51
|
},
|
|
49
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "ebce015402bd0c0b392d810694ccf0b862aa57a5"
|
|
50
53
|
}
|
package/src/config-wrapper.js
CHANGED
|
@@ -11,18 +11,12 @@
|
|
|
11
11
|
*/
|
|
12
12
|
const { Request, Response } = require('@adobe/helix-fetch');
|
|
13
13
|
const { cleanupHeaderValue } = require('@adobe/helix-shared-utils');
|
|
14
|
-
const redirect = require('./RedirectConfig');
|
|
15
|
-
const helix = require('./HelixConfig');
|
|
16
14
|
const fstab = require('./MountConfig');
|
|
17
15
|
const index = require('./IndexConfig');
|
|
18
|
-
const markup = require('./MarkupConfig');
|
|
19
16
|
|
|
20
17
|
const loaders = {
|
|
21
|
-
redirect,
|
|
22
|
-
helix,
|
|
23
18
|
fstab,
|
|
24
19
|
index,
|
|
25
|
-
markup,
|
|
26
20
|
};
|
|
27
21
|
|
|
28
22
|
/**
|
package/src/index.js
CHANGED
|
@@ -9,31 +9,19 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
const HelixConfig = require('./HelixConfig.js');
|
|
13
12
|
const IndexConfig = require('./IndexConfig');
|
|
14
13
|
const MountConfig = require('./MountConfig');
|
|
15
|
-
const RedirectConfig = require('./RedirectConfig');
|
|
16
|
-
const Strain = require('./Strain.js');
|
|
17
|
-
const MarkupConfig = require('./MarkupConfig');
|
|
18
|
-
const Condition = require('./Condition.js');
|
|
19
14
|
const { optionalConfig, requiredConfig } = require('./config-wrapper');
|
|
20
|
-
const DataEmbedValidator = require('./DataEmbedValidator.js');
|
|
21
15
|
const ValidationError = require('./ValidationError.js');
|
|
22
16
|
const IgnoreConfig = require('./IgnoreConfig.js');
|
|
23
17
|
const SitemapConfig = require('./SitemapConfig.js');
|
|
24
18
|
|
|
25
19
|
module.exports = {
|
|
26
|
-
HelixConfig,
|
|
27
20
|
IndexConfig,
|
|
28
21
|
MountConfig,
|
|
29
|
-
RedirectConfig,
|
|
30
|
-
Strain,
|
|
31
|
-
MarkupConfig,
|
|
32
22
|
IgnoreConfig,
|
|
33
23
|
SitemapConfig,
|
|
34
|
-
Condition,
|
|
35
24
|
optionalConfig,
|
|
36
25
|
requiredConfig,
|
|
37
|
-
DataEmbedValidator,
|
|
38
26
|
ValidationError,
|
|
39
27
|
};
|
package/src/Condition.js
DELETED
|
@@ -1,573 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2021 Adobe. All rights reserved.
|
|
3
|
-
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
-
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
*
|
|
7
|
-
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
-
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
-
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
-
* governing permissions and limitations under the License.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/* eslint-disable max-classes-per-file */
|
|
14
|
-
const { parse } = require('url');
|
|
15
|
-
const YAML = require('yaml');
|
|
16
|
-
const pruneEmptyValues = require('@adobe/helix-shared-prune');
|
|
17
|
-
|
|
18
|
-
// To avoid forward referencing the transformer function
|
|
19
|
-
let transform;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Determines how to transform children configuration based on the affix type.
|
|
23
|
-
*/
|
|
24
|
-
const configMapper = {
|
|
25
|
-
prefix: (cfg) => transform(cfg),
|
|
26
|
-
infix: (cfg) => cfg.map((child) => transform(child)),
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Determines how to compose VCL based on the affix type.
|
|
31
|
-
*/
|
|
32
|
-
const vclComposer = {
|
|
33
|
-
prefix: (op) => (item) => `${op}(${item.toVCL()})`,
|
|
34
|
-
infix: (op) => (items) => `(${items.map((item) => item.toVCL()).join(op)})`,
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Determines how to output JSON based on the affix type.
|
|
39
|
-
*/
|
|
40
|
-
const jsonGenarator = {
|
|
41
|
-
prefix: (op) => (item) => {
|
|
42
|
-
const json = {};
|
|
43
|
-
json[op] = item.toJSON();
|
|
44
|
-
return json;
|
|
45
|
-
},
|
|
46
|
-
infix: (op) => (items) => {
|
|
47
|
-
const subs = [];
|
|
48
|
-
items.forEach((item) => {
|
|
49
|
-
subs.push(item.toJSON());
|
|
50
|
-
});
|
|
51
|
-
const json = {};
|
|
52
|
-
json[op] = subs;
|
|
53
|
-
return json;
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Boolean conditions
|
|
59
|
-
*/
|
|
60
|
-
const booleanMap = {
|
|
61
|
-
or: {
|
|
62
|
-
mapper: configMapper.infix,
|
|
63
|
-
jsonGen: jsonGenarator.infix('or'),
|
|
64
|
-
vcl: vclComposer.infix(' || '),
|
|
65
|
-
evaluate: (items, req) => items.reduce((prev, item) => prev || item.evaluate(req), false),
|
|
66
|
-
vcl_path: (items, paramName) => items.reduce((prev, item) => {
|
|
67
|
-
const clause = item.toVCLPath(paramName);
|
|
68
|
-
if (clause) {
|
|
69
|
-
prev.push(clause);
|
|
70
|
-
}
|
|
71
|
-
return prev;
|
|
72
|
-
}, []).join(''),
|
|
73
|
-
},
|
|
74
|
-
and: {
|
|
75
|
-
mapper: configMapper.infix,
|
|
76
|
-
jsonGen: jsonGenarator.infix('and'),
|
|
77
|
-
vcl: vclComposer.infix(' && '),
|
|
78
|
-
evaluate: (items, req) => items.reduce((prev, item) => {
|
|
79
|
-
if (!prev) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
const result = item.evaluate(req);
|
|
83
|
-
if (!result) {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
// preserve the term that has a baseURL
|
|
87
|
-
return prev.baseURL ? prev : result;
|
|
88
|
-
}, true),
|
|
89
|
-
vcl_path: (items, paramName, vcl) => {
|
|
90
|
-
const subpathItem = items.find((item) => item.getSubPath && item.getSubPath(paramName));
|
|
91
|
-
if (subpathItem) {
|
|
92
|
-
return `if ${vcl()} {
|
|
93
|
-
set req.http.${paramName} = "${subpathItem.getSubPath(paramName)}";
|
|
94
|
-
}
|
|
95
|
-
`;
|
|
96
|
-
}
|
|
97
|
-
return '';
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
not: {
|
|
101
|
-
mapper: configMapper.prefix,
|
|
102
|
-
jsonGen: jsonGenarator.prefix('not'),
|
|
103
|
-
vcl: vclComposer.prefix(' !'),
|
|
104
|
-
evaluate: (item, req) => !item.evaluate(req),
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
class BooleanCondition {
|
|
109
|
-
constructor(entry, cfg) {
|
|
110
|
-
this._entry = entry;
|
|
111
|
-
this._items = this._entry.mapper(cfg);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
toVCL() {
|
|
115
|
-
return this._entry.vcl(this._items);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Return a VCL conditional clause that will assign the calculated base path
|
|
120
|
-
* to a request parameter.
|
|
121
|
-
*
|
|
122
|
-
* @param {String} paramName request parameter name to assign the base path to
|
|
123
|
-
*/
|
|
124
|
-
toVCLPath(paramName) {
|
|
125
|
-
const vcl = this.toVCL.bind(this);
|
|
126
|
-
return this._entry.vcl_path ? this._entry.vcl_path(this._items, paramName, vcl) : '';
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
evaluate(req) {
|
|
130
|
-
return this._entry.evaluate(this._items, req);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
toJSON() {
|
|
134
|
-
return this._entry.jsonGen(this._items);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
sticky() {
|
|
138
|
-
const items = Array.isArray(this._items) ? this._items : [this._items];
|
|
139
|
-
return items.some((item) => item.sticky());
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Gets a list of all preflight headers used in this condition
|
|
144
|
-
* @returns String[]
|
|
145
|
-
*/
|
|
146
|
-
get preflightHeaders() {
|
|
147
|
-
return [...this._items.reduce((s, i) => {
|
|
148
|
-
const headers = i.preflightHeaders;
|
|
149
|
-
if (headers && Array.isArray(headers)) {
|
|
150
|
-
headers.forEach((h) => s.add(h));
|
|
151
|
-
}
|
|
152
|
-
return s;
|
|
153
|
-
}, new Set())];
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* PropertyCondition
|
|
159
|
-
*/
|
|
160
|
-
class PropertyCondition {
|
|
161
|
-
constructor(prop, op, value, name, label) {
|
|
162
|
-
if (op && prop.allowed_ops.indexOf(op) === -1) {
|
|
163
|
-
throw new Error(`Property ${name} does not support operation: ${op}`);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
this._prop = prop;
|
|
167
|
-
this._op = op;
|
|
168
|
-
this._value = value;
|
|
169
|
-
this._name = name;
|
|
170
|
-
this._label = label || name;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
toVCL() {
|
|
174
|
-
const { vcl } = this._prop;
|
|
175
|
-
const name = typeof vcl === 'function' ? vcl(this) : vcl;
|
|
176
|
-
const quote = this._prop.type === 'string' ? '"' : '';
|
|
177
|
-
let value = this._value;
|
|
178
|
-
let op = this._op;
|
|
179
|
-
|
|
180
|
-
if (quote === '"' && !op) {
|
|
181
|
-
// substring-start
|
|
182
|
-
value = `^${value}`;
|
|
183
|
-
op = '~';
|
|
184
|
-
}
|
|
185
|
-
if (!op || op === '=') {
|
|
186
|
-
// operand defaults to equal
|
|
187
|
-
op = '==';
|
|
188
|
-
}
|
|
189
|
-
return `${name} ${op} ${quote}${value}${quote}`;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// eslint-disable-next-line class-methods-use-this
|
|
193
|
-
getSubPath() {
|
|
194
|
-
return '';
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Return a VCL conditional clause that will assign the calculated base path
|
|
199
|
-
* to a request parameter.
|
|
200
|
-
*
|
|
201
|
-
* @param {String|Function} param request parameter name to insert or function to invoke
|
|
202
|
-
*/
|
|
203
|
-
toVCLPath(param) {
|
|
204
|
-
const subPath = this.getSubPath();
|
|
205
|
-
if (subPath) {
|
|
206
|
-
if (typeof param === 'function') {
|
|
207
|
-
return param(this.toVCL(), subPath);
|
|
208
|
-
}
|
|
209
|
-
return `if (${this.toVCL()}) {
|
|
210
|
-
set req.http.${param} = "${subPath}";
|
|
211
|
-
}
|
|
212
|
-
`;
|
|
213
|
-
}
|
|
214
|
-
return '';
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
toJSON() {
|
|
218
|
-
const json = {};
|
|
219
|
-
const name = `${this._label}${this._op}`;
|
|
220
|
-
json[name] = this._value;
|
|
221
|
-
return json;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
sticky() {
|
|
225
|
-
return !!this._prop.sticky;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
evaluate(req) {
|
|
229
|
-
if (!this._prop.evaluate) {
|
|
230
|
-
return true;
|
|
231
|
-
}
|
|
232
|
-
const actual = this._prop.evaluate(req, this);
|
|
233
|
-
if (!actual) {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const value = this._value;
|
|
238
|
-
const { type } = this._prop;
|
|
239
|
-
|
|
240
|
-
switch (this._op) {
|
|
241
|
-
case '=':
|
|
242
|
-
return actual === value;
|
|
243
|
-
case '~':
|
|
244
|
-
return !!actual.match(value);
|
|
245
|
-
case '<':
|
|
246
|
-
return actual < value;
|
|
247
|
-
case '>':
|
|
248
|
-
return actual > value;
|
|
249
|
-
default:
|
|
250
|
-
if (type === 'string') {
|
|
251
|
-
return this.prefixMatch(actual, value);
|
|
252
|
-
}
|
|
253
|
-
return actual === value;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// eslint-disable-next-line class-methods-use-this
|
|
258
|
-
prefixMatch(actual, prefix) {
|
|
259
|
-
return actual.startsWith(prefix);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
get name() {
|
|
263
|
-
return this._name;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
get type() {
|
|
267
|
-
return this._prop.type;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
class PreflightCondition extends PropertyCondition {
|
|
272
|
-
/**
|
|
273
|
-
* Gets a list of all preflight headers used in this condition
|
|
274
|
-
* @returns String[]
|
|
275
|
-
*/
|
|
276
|
-
get preflightHeaders() {
|
|
277
|
-
return [this._name];
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* URLCondition
|
|
283
|
-
*/
|
|
284
|
-
class URLCondition extends PropertyCondition {
|
|
285
|
-
constructor(prop, op, uri, value, name, label) {
|
|
286
|
-
super(prop, op, value, name, label);
|
|
287
|
-
|
|
288
|
-
this._uri = uri;
|
|
289
|
-
this._vclProp = uri.path.indexOf('.') !== -1 ? 'req.url.path' : 'req.http.X-FullDirname';
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
getSubPath() {
|
|
293
|
-
const { _op: op, _uri: { path } } = this;
|
|
294
|
-
return (!op && path !== '/') ? path : '';
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
toVCL() {
|
|
298
|
-
const { _op: op, _vclProp: name, _uri: { host, path } } = this;
|
|
299
|
-
const vcl = [];
|
|
300
|
-
|
|
301
|
-
if (host) {
|
|
302
|
-
vcl.push(`req.http.host == "${host}"`);
|
|
303
|
-
}
|
|
304
|
-
if (path !== '/') {
|
|
305
|
-
if (!op) {
|
|
306
|
-
// substring-start
|
|
307
|
-
vcl.push(`(${name} ~ "^${path}$" || ${name} ~ "^${path}/")`);
|
|
308
|
-
} else {
|
|
309
|
-
vcl.push(`${name} ${op === '=' ? '==' : op} "${path}"`);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
return vcl.join(' && ');
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
prefixMatch(actual, prefix) {
|
|
316
|
-
const dir = prefix.replace(/\/+$/, '');
|
|
317
|
-
if (actual === prefix || actual.startsWith(`${dir}/`)) {
|
|
318
|
-
const { path } = this._uri;
|
|
319
|
-
return path !== '/' ? { baseURL: path } : true;
|
|
320
|
-
}
|
|
321
|
-
return false;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Known properties
|
|
327
|
-
*/
|
|
328
|
-
const propertyMap = {
|
|
329
|
-
url: (op, value, name) => new URLCondition({
|
|
330
|
-
evaluate: (req) => `${req.protocol}://${req.headers.host}${req.path}`,
|
|
331
|
-
type: 'string',
|
|
332
|
-
allowed_ops: '=~',
|
|
333
|
-
}, op, parse(value), value, name),
|
|
334
|
-
'url.hostname': {
|
|
335
|
-
vcl: 'req.http.host',
|
|
336
|
-
evaluate: (req) => req.hostname,
|
|
337
|
-
type: 'string',
|
|
338
|
-
allowed_ops: '=~',
|
|
339
|
-
},
|
|
340
|
-
'url.path': (op, value, name) => new URLCondition({
|
|
341
|
-
vcl: 'req.url.path',
|
|
342
|
-
evaluate: (req) => req.path,
|
|
343
|
-
type: 'string',
|
|
344
|
-
allowed_ops: '=~',
|
|
345
|
-
}, op, { path: value }, value, name),
|
|
346
|
-
referer: {
|
|
347
|
-
vcl: 'req.http.referer',
|
|
348
|
-
evaluate: (req) => req.get('referer'),
|
|
349
|
-
type: 'string',
|
|
350
|
-
allowed_ops: '=~',
|
|
351
|
-
sticky: true,
|
|
352
|
-
},
|
|
353
|
-
client_city: {
|
|
354
|
-
vcl: 'client.geo.city',
|
|
355
|
-
type: 'string',
|
|
356
|
-
allowed_ops: '=~',
|
|
357
|
-
},
|
|
358
|
-
client_country_code: {
|
|
359
|
-
vcl: 'client.geo.country_code',
|
|
360
|
-
type: 'string',
|
|
361
|
-
allowed_ops: '=~',
|
|
362
|
-
},
|
|
363
|
-
user_agent: {
|
|
364
|
-
vcl: 'req.http.User-Agent',
|
|
365
|
-
evaluate: (req) => req.get('user-agent'),
|
|
366
|
-
type: 'string',
|
|
367
|
-
allowed_ops: '=~',
|
|
368
|
-
},
|
|
369
|
-
accept_language: {
|
|
370
|
-
vcl: 'req.http.Accept-Language',
|
|
371
|
-
evaluate: (req) => req.get('accept-language'),
|
|
372
|
-
type: 'string',
|
|
373
|
-
allowed_ops: '=~',
|
|
374
|
-
},
|
|
375
|
-
client_lat: {
|
|
376
|
-
vcl: 'client.geo.latitude',
|
|
377
|
-
type: 'number',
|
|
378
|
-
allowed_ops: '<=>',
|
|
379
|
-
},
|
|
380
|
-
client_lon: {
|
|
381
|
-
vcl: 'client.geo.longitude',
|
|
382
|
-
type: 'number',
|
|
383
|
-
allowed_ops: '<=>',
|
|
384
|
-
},
|
|
385
|
-
client_gmt_offset: {
|
|
386
|
-
vcl: 'client.geo.gmt_offset',
|
|
387
|
-
type: 'number',
|
|
388
|
-
allowed_ops: '<=>',
|
|
389
|
-
},
|
|
390
|
-
time_day: {
|
|
391
|
-
vcl: 'std.atoi(strftime({"%w"}, time.start))',
|
|
392
|
-
evaluate: () => new Date().getDay(),
|
|
393
|
-
type: 'number',
|
|
394
|
-
allowed_ops: '<=>',
|
|
395
|
-
},
|
|
396
|
-
time_date: {
|
|
397
|
-
vcl: 'std.atoi(strftime({"%d"}, time.start))',
|
|
398
|
-
evaluate: () => new Date().getDate(),
|
|
399
|
-
type: 'number',
|
|
400
|
-
allowed_ops: '<=>',
|
|
401
|
-
},
|
|
402
|
-
time_hours: {
|
|
403
|
-
vcl: 'std.atoi(strftime({"%H"}, time.start))',
|
|
404
|
-
evaluate: () => new Date().getHours(),
|
|
405
|
-
type: 'number',
|
|
406
|
-
allowed_ops: '<=>',
|
|
407
|
-
},
|
|
408
|
-
time_minutes: {
|
|
409
|
-
vcl: 'std.atoi(strftime({"%M"}, time.start))',
|
|
410
|
-
evaluate: () => new Date().getMinutes(),
|
|
411
|
-
type: 'number',
|
|
412
|
-
allowed_ops: '<=>',
|
|
413
|
-
},
|
|
414
|
-
time_month: {
|
|
415
|
-
vcl: 'std.atoi(strftime({"%m"}, time.start))',
|
|
416
|
-
evaluate: () => new Date().getMonth(),
|
|
417
|
-
type: 'number',
|
|
418
|
-
allowed_ops: '<=>',
|
|
419
|
-
},
|
|
420
|
-
time_year: {
|
|
421
|
-
vcl: 'std.atoi(strftime({"%Y"}, time.start))',
|
|
422
|
-
evaluate: () => new Date().getFullYear(),
|
|
423
|
-
type: 'number',
|
|
424
|
-
allowed_ops: '<=>',
|
|
425
|
-
},
|
|
426
|
-
url_param: {
|
|
427
|
-
vcl: (property) => {
|
|
428
|
-
const vcl = `subfield(req.url.qs, "${property.name}", "&")`;
|
|
429
|
-
if (property.type === 'number') {
|
|
430
|
-
return `std.atoi(${vcl})`;
|
|
431
|
-
}
|
|
432
|
-
return vcl;
|
|
433
|
-
},
|
|
434
|
-
evaluate: (req, property) => req.params[property.name],
|
|
435
|
-
allowed_ops: '~<=>',
|
|
436
|
-
sticky: true,
|
|
437
|
-
},
|
|
438
|
-
preflight: {
|
|
439
|
-
vcl: (property) => {
|
|
440
|
-
const vcl = `req.http.x-preflight-${property.name}`;
|
|
441
|
-
if (property.type === 'number') {
|
|
442
|
-
return `std.atoi(${vcl})`;
|
|
443
|
-
}
|
|
444
|
-
return vcl;
|
|
445
|
-
},
|
|
446
|
-
evaluate: (req, property) => req.preflight && req.preflight[property.name],
|
|
447
|
-
allowed_ops: '~<=>',
|
|
448
|
-
sticky: true,
|
|
449
|
-
},
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* StringCondition class
|
|
454
|
-
*/
|
|
455
|
-
class StringCondition {
|
|
456
|
-
constructor(s) {
|
|
457
|
-
this._s = s;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
toVCL() {
|
|
461
|
-
return this._s;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
toJSON() {
|
|
465
|
-
return this._s;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
// eslint-disable-next-line class-methods-use-this
|
|
469
|
-
sticky() {
|
|
470
|
-
return true;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
/**
|
|
475
|
-
* Condition class
|
|
476
|
-
*/
|
|
477
|
-
class Condition {
|
|
478
|
-
constructor(cfg) {
|
|
479
|
-
if (typeof cfg === 'string') {
|
|
480
|
-
this._top = new StringCondition(cfg);
|
|
481
|
-
} else {
|
|
482
|
-
this._top = cfg ? transform(cfg) : null;
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
toVCL() {
|
|
487
|
-
return this._top ? this._top.toVCL() : '';
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
toVCLPath(paramName = 'X-Base') {
|
|
491
|
-
if (this._top && this._top.toVCLPath) {
|
|
492
|
-
return this._top.toVCLPath(paramName);
|
|
493
|
-
}
|
|
494
|
-
return '';
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
match(req) {
|
|
498
|
-
if (this._top && this._top.evaluate) {
|
|
499
|
-
req.headers = req.headers || {};
|
|
500
|
-
req.params = req.params || {};
|
|
501
|
-
req.protocol = req.protocol || 'http';
|
|
502
|
-
req.path = req.path || '/';
|
|
503
|
-
|
|
504
|
-
return this._top.evaluate(req);
|
|
505
|
-
}
|
|
506
|
-
return true;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
sticky() {
|
|
510
|
-
if (this._top && this._top.sticky) {
|
|
511
|
-
return this._top.sticky();
|
|
512
|
-
}
|
|
513
|
-
return false;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
toJSON(opts) {
|
|
517
|
-
const json = this._top ? this._top.toJSON() : null;
|
|
518
|
-
if (json && opts && opts.minimal) {
|
|
519
|
-
return pruneEmptyValues(json);
|
|
520
|
-
}
|
|
521
|
-
return json;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
toYAMLNode() {
|
|
525
|
-
const json = this.toJSON({ minimal: true });
|
|
526
|
-
return json ? YAML.createNode(json) : null;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
/**
|
|
530
|
-
* Gets a list of all preflight headers used in this condition
|
|
531
|
-
* @returns String[]
|
|
532
|
-
*/
|
|
533
|
-
get preflightHeaders() {
|
|
534
|
-
return this._top.preflightHeaders;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
// Now define our transformer
|
|
539
|
-
transform = (cfg) => {
|
|
540
|
-
// We assume the first non-inherited key contains our property
|
|
541
|
-
let name = Object.keys(cfg)[0];
|
|
542
|
-
const value = cfg[name];
|
|
543
|
-
|
|
544
|
-
const entry = booleanMap[name];
|
|
545
|
-
if (entry) {
|
|
546
|
-
return new BooleanCondition(entry, value);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
const last = name.substr(-1);
|
|
550
|
-
let op = '';
|
|
551
|
-
if (last.match(/[<=>~]/)) {
|
|
552
|
-
name = name.slice(0, name.length - 1);
|
|
553
|
-
op = last;
|
|
554
|
-
}
|
|
555
|
-
let prop = propertyMap[name];
|
|
556
|
-
if (prop) {
|
|
557
|
-
if (typeof prop === 'function') {
|
|
558
|
-
return prop(op, value, name);
|
|
559
|
-
}
|
|
560
|
-
return new PropertyCondition(prop, op, value, name);
|
|
561
|
-
}
|
|
562
|
-
const match = name.match(/^(url_param|preflight)\.(.+)$/);
|
|
563
|
-
if (match && match[1] === 'url_param') {
|
|
564
|
-
prop = { type: op === '<' || op === '>' ? 'number' : 'string', ...propertyMap[match[1]] };
|
|
565
|
-
return new PropertyCondition(prop, op, value, match[2], name);
|
|
566
|
-
} else if (match && match[1] === 'preflight') {
|
|
567
|
-
prop = { type: op === '<' || op === '>' ? 'number' : 'string', ...propertyMap[match[1]] };
|
|
568
|
-
return new PreflightCondition(prop, op, value, match[2], name);
|
|
569
|
-
}
|
|
570
|
-
throw new Error(`Unknown property: ${name}`);
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
module.exports = Condition;
|