@adobe/helix-shared-config 1.7.21 → 2.0.0
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 +39 -0
- package/package.json +12 -9
- 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/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;
|
package/src/ConfigValidator.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2018 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
|
-
|
|
15
|
-
const Ajv = require('ajv').default;
|
|
16
|
-
const ajvFormats = require('ajv-formats');
|
|
17
|
-
const ValidationError = require('./ValidationError.js');
|
|
18
|
-
|
|
19
|
-
const schemas = [
|
|
20
|
-
/* eslint-disable global-require */
|
|
21
|
-
require('./schemas/config.schema.json'),
|
|
22
|
-
require('./schemas/version-lock.schema.json'),
|
|
23
|
-
require('./schemas/runtimestrain.schema.json'),
|
|
24
|
-
require('./schemas/proxystrain.schema.json'),
|
|
25
|
-
require('./schemas/strains.schema.json'),
|
|
26
|
-
require('./schemas/giturl.schema.json'),
|
|
27
|
-
require('./schemas/staticgiturl.schema.json'),
|
|
28
|
-
require('./schemas/origin.schema.json'),
|
|
29
|
-
require('./schemas/performance.schema.json'),
|
|
30
|
-
require('./schemas/redirectrule.schema.json'),
|
|
31
|
-
require('./schemas/conditions.schema.json'),
|
|
32
|
-
/* eslint-enable global-require */
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
class HelixConfigValidationError extends ValidationError {
|
|
36
|
-
constructor(msg, errors = []) {
|
|
37
|
-
super(msg, errors, HelixConfigValidationError.mapError, HelixConfigValidationError.prettyname);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
static prettyname(path, schema) {
|
|
41
|
-
if (path && path.startsWith('.strains')) {
|
|
42
|
-
return `${schema.title || 'Invalid Strain'} ${path.replace(/\.strains(\.|\[')(.*)/, '$2').replace(/'.*/, '')}`;
|
|
43
|
-
}
|
|
44
|
-
return ValidationError.prettyname(path, schema);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
static mapError({
|
|
48
|
-
keyword, dataPath, message, data, params, parentSchema,
|
|
49
|
-
}, prettyname) {
|
|
50
|
-
if (keyword === 'required' && dataPath === '') {
|
|
51
|
-
return 'A set of strains and a default strain are missing.';
|
|
52
|
-
}
|
|
53
|
-
if (keyword === 'required' && dataPath === '.strains') {
|
|
54
|
-
return 'A default strain is missing.';
|
|
55
|
-
}
|
|
56
|
-
if (keyword === 'oneOf' && dataPath.startsWith('.strains')) {
|
|
57
|
-
return `${prettyname(dataPath, parentSchema)} must be either a Runtime Strain or a Proxy Strain`;
|
|
58
|
-
}
|
|
59
|
-
return ValidationError.mapError(keyword, dataPath, message, data, params, parentSchema);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
class ConfigValidator {
|
|
64
|
-
constructor() {
|
|
65
|
-
this._ajv = new Ajv({
|
|
66
|
-
allErrors: true,
|
|
67
|
-
verbose: true,
|
|
68
|
-
useDefaults: true,
|
|
69
|
-
coerceTypes: true,
|
|
70
|
-
strict: false,
|
|
71
|
-
});
|
|
72
|
-
this._ajv.addSchema(schemas);
|
|
73
|
-
ajvFormats(this._ajv);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
validate(config = {}) {
|
|
77
|
-
this._ajv.errors = [];
|
|
78
|
-
return this._ajv.validate('https://ns.adobe.com/helix/shared/config', config);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
assetValid(config = {}) {
|
|
82
|
-
// handle simple case for no strains. since the ajv error is a bit cryptic.
|
|
83
|
-
if (!config.strains
|
|
84
|
-
|| ((config.strains.find && !config.strains.find((s) => s.name === 'default'))
|
|
85
|
-
&& !config.strains.default)) {
|
|
86
|
-
throw new HelixConfigValidationError('A list of strains and a strain with the name "default" is required.');
|
|
87
|
-
}
|
|
88
|
-
const valid = this.validate(config);
|
|
89
|
-
if (!valid) {
|
|
90
|
-
throw new HelixConfigValidationError(this._ajv.errorsText(), this._ajv.errors);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
module.exports = ConfigValidator;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2018 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
|
-
const Ajv = require('ajv').default;
|
|
14
|
-
const ajvFormats = require('ajv-formats');
|
|
15
|
-
|
|
16
|
-
const schemas = [
|
|
17
|
-
/* eslint-disable global-require */
|
|
18
|
-
require('./schemas/data-embed-response.schema.json'),
|
|
19
|
-
require('./schemas/row.schema.json'),
|
|
20
|
-
require('./schemas/sheet.schema.json'),
|
|
21
|
-
require('./schemas/workbook.schema.json'),
|
|
22
|
-
/* eslint-enable global-require */
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
class DataEmbedValidator {
|
|
26
|
-
constructor() {
|
|
27
|
-
this._ajv = new Ajv({
|
|
28
|
-
allErrors: true,
|
|
29
|
-
verbose: true,
|
|
30
|
-
useDefaults: false,
|
|
31
|
-
coerceTypes: false,
|
|
32
|
-
strict: false,
|
|
33
|
-
});
|
|
34
|
-
this._ajv.addSchema(schemas);
|
|
35
|
-
ajvFormats(this._ajv);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
validate(response = {}) {
|
|
39
|
-
this._ajv.errors = [];
|
|
40
|
-
return this._ajv.validate('https://ns.adobe.com/helix/data-embed/response', response);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
assertValid(response) {
|
|
44
|
-
const valid = this.validate(response);
|
|
45
|
-
if (!valid) {
|
|
46
|
-
throw new Error(this._ajv.errorsText());
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
module.exports = DataEmbedValidator;
|