@featurevisor/sdk 0.0.3
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 +30 -0
- package/LICENSE +21 -0
- package/README.md +53 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/lib/bucket.d.ts +2 -0
- package/lib/bucket.js +10 -0
- package/lib/bucket.js.map +1 -0
- package/lib/bucket.spec.d.ts +1 -0
- package/lib/client.d.ts +49 -0
- package/lib/client.js +205 -0
- package/lib/client.js.map +1 -0
- package/lib/conditions.d.ts +3 -0
- package/lib/conditions.js +69 -0
- package/lib/conditions.js.map +1 -0
- package/lib/conditions.spec.d.ts +1 -0
- package/lib/datafileReader.d.ts +16 -0
- package/lib/datafileReader.js +49 -0
- package/lib/datafileReader.js.map +1 -0
- package/lib/feature.d.ts +8 -0
- package/lib/feature.js +117 -0
- package/lib/feature.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -0
- package/lib/index.spec.d.ts +0 -0
- package/lib/segments.d.ts +4 -0
- package/lib/segments.js +35 -0
- package/lib/segments.js.map +1 -0
- package/lib/segments.spec.d.ts +1 -0
- package/package.json +49 -0
- package/src/bucket.spec.ts +18 -0
- package/src/bucket.ts +13 -0
- package/src/client.ts +338 -0
- package/src/conditions.spec.ts +533 -0
- package/src/conditions.ts +73 -0
- package/src/datafileReader.ts +73 -0
- package/src/feature.ts +213 -0
- package/src/index.spec.ts +5 -0
- package/src/index.ts +2 -0
- package/src/segments.spec.ts +196 -0
- package/src/segments.ts +49 -0
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.esm.json +7 -0
- package/webpack.config.js +13 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import { allConditionsAreMatched } from "./conditions";
|
|
2
|
+
import { Condition } from "@featurevisor/types";
|
|
3
|
+
|
|
4
|
+
describe("sdk: Conditions", function () {
|
|
5
|
+
it("should be a function", function () {
|
|
6
|
+
expect(typeof allConditionsAreMatched).toEqual("function");
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
describe("operators", function () {
|
|
10
|
+
it("should match with operator: equals", function () {
|
|
11
|
+
const conditions: Condition[] = [
|
|
12
|
+
{
|
|
13
|
+
attribute: "browser_type",
|
|
14
|
+
operator: "equals",
|
|
15
|
+
value: "chrome",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
// match
|
|
20
|
+
expect(allConditionsAreMatched(conditions, { browser_type: "chrome" })).toEqual(true);
|
|
21
|
+
|
|
22
|
+
// not match
|
|
23
|
+
expect(allConditionsAreMatched(conditions, { browser_type: "firefox" })).toEqual(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should match with operator: notEquals", function () {
|
|
27
|
+
const conditions: Condition[] = [
|
|
28
|
+
{
|
|
29
|
+
attribute: "browser_type",
|
|
30
|
+
operator: "notEquals",
|
|
31
|
+
value: "chrome",
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// match
|
|
36
|
+
expect(allConditionsAreMatched(conditions, { browser_type: "firefox" })).toEqual(true);
|
|
37
|
+
|
|
38
|
+
// not match
|
|
39
|
+
expect(allConditionsAreMatched(conditions, { browser_type: "chrome" })).toEqual(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should match with operator: greaterThan", function () {
|
|
43
|
+
const conditions: Condition[] = [
|
|
44
|
+
{
|
|
45
|
+
attribute: "age",
|
|
46
|
+
operator: "greaterThan",
|
|
47
|
+
value: 18,
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
// match
|
|
52
|
+
expect(allConditionsAreMatched(conditions, { age: 19 })).toEqual(true);
|
|
53
|
+
|
|
54
|
+
// not match
|
|
55
|
+
expect(allConditionsAreMatched(conditions, { age: 17 })).toEqual(false);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should match with operator: lessThan", function () {
|
|
59
|
+
const conditions: Condition[] = [
|
|
60
|
+
{
|
|
61
|
+
attribute: "age",
|
|
62
|
+
operator: "lessThan",
|
|
63
|
+
value: 18,
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
// match
|
|
68
|
+
expect(allConditionsAreMatched(conditions, { age: 17 })).toEqual(true);
|
|
69
|
+
|
|
70
|
+
// not match
|
|
71
|
+
expect(allConditionsAreMatched(conditions, { age: 19 })).toEqual(false);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("simple condition", function () {
|
|
76
|
+
it("should match with exact single condition", function () {
|
|
77
|
+
const conditions: Condition[] = [
|
|
78
|
+
{
|
|
79
|
+
attribute: "browser_type",
|
|
80
|
+
operator: "equals",
|
|
81
|
+
value: "chrome",
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
// match
|
|
86
|
+
expect(
|
|
87
|
+
allConditionsAreMatched(conditions[0], {
|
|
88
|
+
browser_type: "chrome",
|
|
89
|
+
}),
|
|
90
|
+
).toEqual(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should match with exact condition", function () {
|
|
94
|
+
const conditions: Condition[] = [
|
|
95
|
+
{
|
|
96
|
+
attribute: "browser_type",
|
|
97
|
+
operator: "equals",
|
|
98
|
+
value: "chrome",
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
// match
|
|
103
|
+
expect(
|
|
104
|
+
allConditionsAreMatched(conditions, {
|
|
105
|
+
browser_type: "chrome",
|
|
106
|
+
}),
|
|
107
|
+
).toEqual(true);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should not match with empty conditions", function () {
|
|
111
|
+
const conditions: Condition[] = [];
|
|
112
|
+
|
|
113
|
+
// match
|
|
114
|
+
expect(
|
|
115
|
+
allConditionsAreMatched(conditions, {
|
|
116
|
+
browser_type: "chrome",
|
|
117
|
+
}),
|
|
118
|
+
).toEqual(true);
|
|
119
|
+
|
|
120
|
+
// not match
|
|
121
|
+
expect(
|
|
122
|
+
allConditionsAreMatched(conditions, {
|
|
123
|
+
browser_type: "firefox",
|
|
124
|
+
}),
|
|
125
|
+
).toEqual(true);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should match with extra conditions that are not needed", function () {
|
|
129
|
+
const conditions: Condition[] = [
|
|
130
|
+
{
|
|
131
|
+
attribute: "browser_type",
|
|
132
|
+
operator: "equals",
|
|
133
|
+
value: "chrome",
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
// match
|
|
138
|
+
expect(
|
|
139
|
+
allConditionsAreMatched(conditions, {
|
|
140
|
+
browser_type: "chrome",
|
|
141
|
+
browser_version: "1.0",
|
|
142
|
+
}),
|
|
143
|
+
).toEqual(true);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should match with multiple conditions", function () {
|
|
147
|
+
const conditions: Condition[] = [
|
|
148
|
+
{
|
|
149
|
+
attribute: "browser_type",
|
|
150
|
+
operator: "equals",
|
|
151
|
+
value: "chrome",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
attribute: "browser_version",
|
|
155
|
+
operator: "equals",
|
|
156
|
+
value: "1.0",
|
|
157
|
+
},
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
// match
|
|
161
|
+
expect(
|
|
162
|
+
allConditionsAreMatched(conditions, {
|
|
163
|
+
browser_type: "chrome",
|
|
164
|
+
browser_version: "1.0",
|
|
165
|
+
foo: "bar",
|
|
166
|
+
}),
|
|
167
|
+
).toEqual(true);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe("AND condition", function () {
|
|
172
|
+
it("should match with one AND condition", function () {
|
|
173
|
+
const conditions: Condition[] = [
|
|
174
|
+
{
|
|
175
|
+
and: [
|
|
176
|
+
{
|
|
177
|
+
attribute: "browser_type",
|
|
178
|
+
operator: "equals",
|
|
179
|
+
value: "chrome",
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
// match
|
|
186
|
+
expect(
|
|
187
|
+
allConditionsAreMatched(conditions, {
|
|
188
|
+
browser_type: "chrome",
|
|
189
|
+
}),
|
|
190
|
+
).toEqual(true);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("should match with multiple conditions inside AND", function () {
|
|
194
|
+
const conditions: Condition[] = [
|
|
195
|
+
{
|
|
196
|
+
and: [
|
|
197
|
+
{
|
|
198
|
+
attribute: "browser_type",
|
|
199
|
+
operator: "equals",
|
|
200
|
+
value: "chrome",
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
attribute: "browser_version",
|
|
204
|
+
operator: "equals",
|
|
205
|
+
value: "1.0",
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
// match
|
|
212
|
+
expect(
|
|
213
|
+
allConditionsAreMatched(conditions, {
|
|
214
|
+
browser_type: "chrome",
|
|
215
|
+
browser_version: "1.0",
|
|
216
|
+
}),
|
|
217
|
+
).toEqual(true);
|
|
218
|
+
|
|
219
|
+
// not match
|
|
220
|
+
expect(
|
|
221
|
+
allConditionsAreMatched(conditions, {
|
|
222
|
+
browser_type: "chrome",
|
|
223
|
+
}),
|
|
224
|
+
).toEqual(false);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe("OR condition", function () {
|
|
229
|
+
it("should match with one OR condition", function () {
|
|
230
|
+
const conditions: Condition[] = [
|
|
231
|
+
{
|
|
232
|
+
or: [
|
|
233
|
+
{
|
|
234
|
+
attribute: "browser_type",
|
|
235
|
+
operator: "equals",
|
|
236
|
+
value: "chrome",
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
];
|
|
241
|
+
|
|
242
|
+
// match
|
|
243
|
+
expect(
|
|
244
|
+
allConditionsAreMatched(conditions, {
|
|
245
|
+
browser_type: "chrome",
|
|
246
|
+
}),
|
|
247
|
+
).toEqual(true);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("should match with multiple conditions inside OR", function () {
|
|
251
|
+
const conditions: Condition[] = [
|
|
252
|
+
{
|
|
253
|
+
or: [
|
|
254
|
+
{
|
|
255
|
+
attribute: "browser_type",
|
|
256
|
+
operator: "equals",
|
|
257
|
+
value: "chrome",
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
attribute: "browser_version",
|
|
261
|
+
operator: "equals",
|
|
262
|
+
value: "1.0",
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
},
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
// match
|
|
269
|
+
expect(
|
|
270
|
+
allConditionsAreMatched(conditions, {
|
|
271
|
+
browser_version: "1.0",
|
|
272
|
+
}),
|
|
273
|
+
).toEqual(true);
|
|
274
|
+
|
|
275
|
+
// not match
|
|
276
|
+
expect(
|
|
277
|
+
allConditionsAreMatched(conditions, {
|
|
278
|
+
browser_type: "firefox",
|
|
279
|
+
}),
|
|
280
|
+
).toEqual(false);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe("nested conditions", function () {
|
|
285
|
+
it("should match with OR inside AND", function () {
|
|
286
|
+
const conditions: Condition[] = [
|
|
287
|
+
{
|
|
288
|
+
and: [
|
|
289
|
+
{
|
|
290
|
+
attribute: "browser_type",
|
|
291
|
+
operator: "equals",
|
|
292
|
+
value: "chrome",
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
or: [
|
|
296
|
+
{
|
|
297
|
+
attribute: "browser_version",
|
|
298
|
+
operator: "equals",
|
|
299
|
+
value: "1.0",
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
attribute: "browser_version",
|
|
303
|
+
operator: "equals",
|
|
304
|
+
value: "2.0",
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
},
|
|
310
|
+
];
|
|
311
|
+
|
|
312
|
+
// match
|
|
313
|
+
expect(
|
|
314
|
+
allConditionsAreMatched(conditions, {
|
|
315
|
+
browser_type: "chrome",
|
|
316
|
+
browser_version: "1.0",
|
|
317
|
+
}),
|
|
318
|
+
).toEqual(true);
|
|
319
|
+
|
|
320
|
+
expect(
|
|
321
|
+
allConditionsAreMatched(conditions, {
|
|
322
|
+
browser_type: "chrome",
|
|
323
|
+
browser_version: "2.0",
|
|
324
|
+
}),
|
|
325
|
+
).toEqual(true);
|
|
326
|
+
|
|
327
|
+
// not match
|
|
328
|
+
expect(
|
|
329
|
+
allConditionsAreMatched(conditions, {
|
|
330
|
+
browser_type: "chrome",
|
|
331
|
+
browser_version: "3.0",
|
|
332
|
+
}),
|
|
333
|
+
).toEqual(false);
|
|
334
|
+
|
|
335
|
+
expect(
|
|
336
|
+
allConditionsAreMatched(conditions, {
|
|
337
|
+
browser_version: "2.0",
|
|
338
|
+
}),
|
|
339
|
+
).toEqual(false);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it("should match with plain conditions, followed by OR inside AND", function () {
|
|
343
|
+
const conditions: Condition[] = [
|
|
344
|
+
{
|
|
345
|
+
attribute: "country",
|
|
346
|
+
operator: "equals",
|
|
347
|
+
value: "nl",
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
and: [
|
|
351
|
+
{
|
|
352
|
+
attribute: "browser_type",
|
|
353
|
+
operator: "equals",
|
|
354
|
+
value: "chrome",
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
or: [
|
|
358
|
+
{
|
|
359
|
+
attribute: "browser_version",
|
|
360
|
+
operator: "equals",
|
|
361
|
+
value: "1.0",
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
attribute: "browser_version",
|
|
365
|
+
operator: "equals",
|
|
366
|
+
value: "2.0",
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
];
|
|
373
|
+
|
|
374
|
+
// match
|
|
375
|
+
expect(
|
|
376
|
+
allConditionsAreMatched(conditions, {
|
|
377
|
+
country: "nl",
|
|
378
|
+
browser_type: "chrome",
|
|
379
|
+
browser_version: "1.0",
|
|
380
|
+
}),
|
|
381
|
+
).toEqual(true);
|
|
382
|
+
|
|
383
|
+
expect(
|
|
384
|
+
allConditionsAreMatched(conditions, {
|
|
385
|
+
country: "nl",
|
|
386
|
+
browser_type: "chrome",
|
|
387
|
+
browser_version: "2.0",
|
|
388
|
+
}),
|
|
389
|
+
).toEqual(true);
|
|
390
|
+
|
|
391
|
+
// not match
|
|
392
|
+
expect(
|
|
393
|
+
allConditionsAreMatched(conditions, {
|
|
394
|
+
browser_type: "chrome",
|
|
395
|
+
browser_version: "3.0",
|
|
396
|
+
}),
|
|
397
|
+
).toEqual(false);
|
|
398
|
+
|
|
399
|
+
expect(
|
|
400
|
+
allConditionsAreMatched(conditions, {
|
|
401
|
+
country: "us",
|
|
402
|
+
browser_version: "2.0",
|
|
403
|
+
}),
|
|
404
|
+
).toEqual(false);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it("should match with AND inside OR", function () {
|
|
408
|
+
const conditions: Condition[] = [
|
|
409
|
+
{
|
|
410
|
+
or: [
|
|
411
|
+
{
|
|
412
|
+
attribute: "browser_type",
|
|
413
|
+
operator: "equals",
|
|
414
|
+
value: "chrome",
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
and: [
|
|
418
|
+
{
|
|
419
|
+
attribute: "device_type",
|
|
420
|
+
operator: "equals",
|
|
421
|
+
value: "mobile",
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
attribute: "orientation",
|
|
425
|
+
operator: "equals",
|
|
426
|
+
value: "portrait",
|
|
427
|
+
},
|
|
428
|
+
],
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
},
|
|
432
|
+
];
|
|
433
|
+
|
|
434
|
+
// match
|
|
435
|
+
expect(
|
|
436
|
+
allConditionsAreMatched(conditions, {
|
|
437
|
+
browser_type: "chrome",
|
|
438
|
+
browser_version: "2.0",
|
|
439
|
+
}),
|
|
440
|
+
).toEqual(true);
|
|
441
|
+
|
|
442
|
+
expect(
|
|
443
|
+
allConditionsAreMatched(conditions, {
|
|
444
|
+
browser_type: "firefox",
|
|
445
|
+
device_type: "mobile",
|
|
446
|
+
orientation: "portrait",
|
|
447
|
+
}),
|
|
448
|
+
).toEqual(true);
|
|
449
|
+
|
|
450
|
+
// not match
|
|
451
|
+
expect(
|
|
452
|
+
allConditionsAreMatched(conditions, {
|
|
453
|
+
browser_type: "firefox",
|
|
454
|
+
browser_version: "2.0",
|
|
455
|
+
}),
|
|
456
|
+
).toEqual(false);
|
|
457
|
+
|
|
458
|
+
expect(
|
|
459
|
+
allConditionsAreMatched(conditions, {
|
|
460
|
+
browser_type: "firefox",
|
|
461
|
+
device_type: "desktop",
|
|
462
|
+
}),
|
|
463
|
+
).toEqual(false);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it("should match with plain conditions, followed by AND inside OR", function () {
|
|
467
|
+
const conditions: Condition[] = [
|
|
468
|
+
{
|
|
469
|
+
attribute: "country",
|
|
470
|
+
operator: "equals",
|
|
471
|
+
value: "nl",
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
or: [
|
|
475
|
+
{
|
|
476
|
+
attribute: "browser_type",
|
|
477
|
+
operator: "equals",
|
|
478
|
+
value: "chrome",
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
and: [
|
|
482
|
+
{
|
|
483
|
+
attribute: "device_type",
|
|
484
|
+
operator: "equals",
|
|
485
|
+
value: "mobile",
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
attribute: "orientation",
|
|
489
|
+
operator: "equals",
|
|
490
|
+
value: "portrait",
|
|
491
|
+
},
|
|
492
|
+
],
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
},
|
|
496
|
+
];
|
|
497
|
+
|
|
498
|
+
// match
|
|
499
|
+
expect(
|
|
500
|
+
allConditionsAreMatched(conditions, {
|
|
501
|
+
country: "nl",
|
|
502
|
+
browser_type: "chrome",
|
|
503
|
+
browser_version: "2.0",
|
|
504
|
+
}),
|
|
505
|
+
).toEqual(true);
|
|
506
|
+
|
|
507
|
+
expect(
|
|
508
|
+
allConditionsAreMatched(conditions, {
|
|
509
|
+
country: "nl",
|
|
510
|
+
browser_type: "firefox",
|
|
511
|
+
device_type: "mobile",
|
|
512
|
+
orientation: "portrait",
|
|
513
|
+
}),
|
|
514
|
+
).toEqual(true);
|
|
515
|
+
|
|
516
|
+
// not match
|
|
517
|
+
expect(
|
|
518
|
+
allConditionsAreMatched(conditions, {
|
|
519
|
+
browser_type: "firefox",
|
|
520
|
+
browser_version: "2.0",
|
|
521
|
+
}),
|
|
522
|
+
).toEqual(false);
|
|
523
|
+
|
|
524
|
+
expect(
|
|
525
|
+
allConditionsAreMatched(conditions, {
|
|
526
|
+
country: "de",
|
|
527
|
+
browser_type: "firefox",
|
|
528
|
+
device_type: "desktop",
|
|
529
|
+
}),
|
|
530
|
+
).toEqual(false);
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Attributes, Condition, PlainCondition } from "@featurevisor/types";
|
|
2
|
+
|
|
3
|
+
export function conditionIsMatched(condition: PlainCondition, attributes: Attributes): boolean {
|
|
4
|
+
const { attribute, operator, value } = condition;
|
|
5
|
+
|
|
6
|
+
if (operator === "equals") {
|
|
7
|
+
return attributes[attribute] === value;
|
|
8
|
+
} else if (operator === "notEquals") {
|
|
9
|
+
return attributes[attribute] !== value;
|
|
10
|
+
} else if (typeof attributes[attribute] === "string" && Array.isArray(value)) {
|
|
11
|
+
// array
|
|
12
|
+
const valueInAttributes = attributes[attribute] as string;
|
|
13
|
+
|
|
14
|
+
if (operator === "in") {
|
|
15
|
+
return value.indexOf(valueInAttributes) !== -1;
|
|
16
|
+
} else if (operator === "notIn") {
|
|
17
|
+
return value.indexOf(valueInAttributes) === -1;
|
|
18
|
+
}
|
|
19
|
+
} else if (typeof attributes[attribute] === "string" && typeof value === "string") {
|
|
20
|
+
// string
|
|
21
|
+
const valueInAttributes = attributes[attribute] as string;
|
|
22
|
+
|
|
23
|
+
if (operator === "contains") {
|
|
24
|
+
return valueInAttributes.indexOf(value) !== -1;
|
|
25
|
+
} else if (operator === "notContains") {
|
|
26
|
+
return valueInAttributes.indexOf(value) === -1;
|
|
27
|
+
} else if (operator === "startsWith") {
|
|
28
|
+
return valueInAttributes.startsWith(value);
|
|
29
|
+
} else if (operator === "endsWith") {
|
|
30
|
+
return valueInAttributes.endsWith(value);
|
|
31
|
+
}
|
|
32
|
+
} else if (typeof attributes[attribute] === "number" && typeof value === "number") {
|
|
33
|
+
// numeric
|
|
34
|
+
const valueInAttributes = attributes[attribute] as number;
|
|
35
|
+
|
|
36
|
+
if (operator === "greaterThan") {
|
|
37
|
+
return valueInAttributes > value;
|
|
38
|
+
} else if (operator === "greaterThanOrEquals") {
|
|
39
|
+
return valueInAttributes >= value;
|
|
40
|
+
} else if (operator === "lessThan") {
|
|
41
|
+
return valueInAttributes < value;
|
|
42
|
+
} else if (operator === "lessThanOrEquals") {
|
|
43
|
+
return valueInAttributes <= value;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function allConditionsAreMatched(
|
|
51
|
+
conditions: Condition[] | Condition,
|
|
52
|
+
attributes: Attributes,
|
|
53
|
+
): boolean {
|
|
54
|
+
if ("attribute" in conditions) {
|
|
55
|
+
return conditionIsMatched(conditions, attributes);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if ("and" in conditions && Array.isArray(conditions.and)) {
|
|
59
|
+
return conditions.and.every((c) => allConditionsAreMatched(c, attributes));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if ("or" in conditions && Array.isArray(conditions.or)) {
|
|
63
|
+
return conditions.or.some((c) => allConditionsAreMatched(c, attributes));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// @TODO: introduce `not`
|
|
67
|
+
|
|
68
|
+
if (Array.isArray(conditions)) {
|
|
69
|
+
return conditions.every((c) => allConditionsAreMatched(c, attributes));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Feature,
|
|
3
|
+
Segment,
|
|
4
|
+
DatafileContent,
|
|
5
|
+
Attribute,
|
|
6
|
+
AttributeKey,
|
|
7
|
+
SegmentKey,
|
|
8
|
+
FeatureKey,
|
|
9
|
+
} from "@featurevisor/types";
|
|
10
|
+
|
|
11
|
+
export function parseJsonConditionsIfStringified<T>(record: T, key: string): T {
|
|
12
|
+
if (typeof record[key] === "string" && record[key] !== "*") {
|
|
13
|
+
try {
|
|
14
|
+
record[key] = JSON.parse(record[key]);
|
|
15
|
+
} catch (e) {
|
|
16
|
+
console.error("Error parsing JSON", e);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return record;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class DatafileReader {
|
|
24
|
+
private schemaVersion: string;
|
|
25
|
+
private revision: string;
|
|
26
|
+
private attributes: Attribute[];
|
|
27
|
+
private segments: Segment[];
|
|
28
|
+
private features: Feature[];
|
|
29
|
+
|
|
30
|
+
constructor(datafileJson: DatafileContent) {
|
|
31
|
+
this.schemaVersion = datafileJson.schemaVersion;
|
|
32
|
+
this.revision = datafileJson.revision;
|
|
33
|
+
this.segments = datafileJson.segments;
|
|
34
|
+
this.attributes = datafileJson.attributes;
|
|
35
|
+
this.features = datafileJson.features;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getRevision(): string {
|
|
39
|
+
return this.revision;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getSchemaVersion(): string {
|
|
43
|
+
return this.schemaVersion;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getAllAttributes(): Attribute[] {
|
|
47
|
+
return this.attributes;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getAttribute(attributeKey: AttributeKey): Attribute | undefined {
|
|
51
|
+
return this.attributes.find((a) => a.key === attributeKey);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
getSegment(segmentKey: SegmentKey): Segment | undefined {
|
|
55
|
+
const segment = this.segments.find((s) => s.key === segmentKey);
|
|
56
|
+
|
|
57
|
+
if (!segment) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return parseJsonConditionsIfStringified(segment, "conditions");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getFeature(featureKey: FeatureKey): Feature | undefined {
|
|
65
|
+
const feature = this.features.find((s) => s.key === featureKey);
|
|
66
|
+
|
|
67
|
+
if (!feature) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return feature;
|
|
72
|
+
}
|
|
73
|
+
}
|