@featurevisor/sdk 1.35.3 → 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.
Files changed (85) hide show
  1. package/README.md +2 -381
  2. package/coverage/clover.xml +707 -645
  3. package/coverage/coverage-final.json +11 -9
  4. package/coverage/lcov-report/{segments.ts.html → bucketer.ts.html} +155 -77
  5. package/coverage/lcov-report/child.ts.html +940 -0
  6. package/coverage/lcov-report/conditions.ts.html +107 -158
  7. package/coverage/lcov-report/datafileReader.ts.html +763 -103
  8. package/coverage/lcov-report/emitter.ts.html +77 -59
  9. package/coverage/lcov-report/evaluate.ts.html +689 -416
  10. package/coverage/lcov-report/events.ts.html +334 -0
  11. package/coverage/lcov-report/helpers.ts.html +184 -0
  12. package/coverage/lcov-report/{bucket.ts.html → hooks.ts.html} +86 -239
  13. package/coverage/lcov-report/index.html +119 -89
  14. package/coverage/lcov-report/instance.ts.html +341 -773
  15. package/coverage/lcov-report/logger.ts.html +64 -64
  16. package/coverage/lcov.info +1433 -1226
  17. package/dist/bucketer.d.ts +11 -0
  18. package/dist/child.d.ts +26 -0
  19. package/dist/compareVersions.d.ts +4 -0
  20. package/dist/conditions.d.ts +4 -4
  21. package/dist/datafileReader.d.ts +26 -6
  22. package/dist/emitter.d.ts +8 -9
  23. package/dist/evaluate.d.ts +31 -29
  24. package/dist/events.d.ts +5 -0
  25. package/dist/helpers.d.ts +5 -0
  26. package/dist/hooks.d.ts +45 -0
  27. package/dist/index.d.ts +3 -2
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.mjs +1 -1
  31. package/dist/index.mjs.gz +0 -0
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/instance.d.ts +40 -72
  34. package/dist/logger.d.ts +6 -5
  35. package/dist/murmurhash.d.ts +1 -0
  36. package/jest.config.js +2 -0
  37. package/lib/bucketer.d.ts +11 -0
  38. package/lib/child.d.ts +26 -0
  39. package/lib/compareVersions.d.ts +4 -0
  40. package/lib/conditions.d.ts +4 -4
  41. package/lib/datafileReader.d.ts +26 -6
  42. package/lib/emitter.d.ts +8 -9
  43. package/lib/evaluate.d.ts +31 -29
  44. package/lib/events.d.ts +5 -0
  45. package/lib/helpers.d.ts +5 -0
  46. package/lib/hooks.d.ts +45 -0
  47. package/lib/index.d.ts +3 -2
  48. package/lib/instance.d.ts +40 -72
  49. package/lib/logger.d.ts +6 -5
  50. package/lib/murmurhash.d.ts +1 -0
  51. package/package.json +3 -5
  52. package/src/bucketer.spec.ts +165 -0
  53. package/src/bucketer.ts +84 -0
  54. package/src/child.spec.ts +267 -0
  55. package/src/child.ts +285 -0
  56. package/src/compareVersions.ts +93 -0
  57. package/src/conditions.spec.ts +563 -353
  58. package/src/conditions.ts +46 -63
  59. package/src/datafileReader.spec.ts +396 -84
  60. package/src/datafileReader.ts +280 -60
  61. package/src/emitter.spec.ts +27 -86
  62. package/src/emitter.ts +38 -32
  63. package/src/evaluate.ts +349 -258
  64. package/src/events.spec.ts +154 -0
  65. package/src/events.ts +83 -0
  66. package/src/helpers.ts +33 -0
  67. package/src/hooks.ts +88 -0
  68. package/src/index.ts +3 -2
  69. package/src/instance.spec.ts +305 -489
  70. package/src/instance.ts +247 -391
  71. package/src/logger.spec.ts +212 -134
  72. package/src/logger.ts +36 -36
  73. package/src/murmurhash.ts +71 -0
  74. package/coverage/lcov-report/feature.ts.html +0 -508
  75. package/dist/bucket.d.ts +0 -30
  76. package/dist/feature.d.ts +0 -16
  77. package/dist/segments.d.ts +0 -5
  78. package/lib/bucket.d.ts +0 -30
  79. package/lib/feature.d.ts +0 -16
  80. package/lib/segments.d.ts +0 -5
  81. package/src/bucket.spec.ts +0 -37
  82. package/src/bucket.ts +0 -139
  83. package/src/feature.ts +0 -141
  84. package/src/segments.spec.ts +0 -468
  85. package/src/segments.ts +0 -58
@@ -1,468 +0,0 @@
1
- import { DatafileContent, GroupSegment } from "@featurevisor/types";
2
-
3
- import { DatafileReader } from "./datafileReader";
4
- import { allGroupSegmentsAreMatched } from "./segments";
5
- import { createLogger } from "./logger";
6
-
7
- interface Group {
8
- key: string;
9
- segments: GroupSegment | GroupSegment[] | "*";
10
- }
11
-
12
- describe("sdk: Segments", function () {
13
- const logger = createLogger();
14
-
15
- it("should be a function", function () {
16
- expect(typeof allGroupSegmentsAreMatched).toEqual("function");
17
- });
18
-
19
- describe("datafile #1", function () {
20
- const groups = [
21
- // everyone
22
- {
23
- key: "*",
24
- segments: "*",
25
- },
26
-
27
- // dutch
28
- {
29
- key: "dutchMobileUsers",
30
- segments: ["mobileUsers", "netherlands"],
31
- },
32
- {
33
- key: "dutchMobileUsers2",
34
- segments: {
35
- and: ["mobileUsers", "netherlands"],
36
- },
37
- },
38
- {
39
- key: "dutchMobileOrDesktopUsers",
40
- segments: ["netherlands", { or: ["mobileUsers", "desktopUsers"] }],
41
- },
42
- {
43
- key: "dutchMobileOrDesktopUsers2",
44
- segments: {
45
- and: ["netherlands", { or: ["mobileUsers", "desktopUsers"] }],
46
- },
47
- },
48
-
49
- // german
50
- {
51
- key: "germanMobileUsers",
52
- segments: [
53
- {
54
- and: ["mobileUsers", "germany"],
55
- },
56
- ],
57
- },
58
- {
59
- key: "germanNonMobileUsers",
60
- segments: [
61
- {
62
- and: [
63
- "germany",
64
- {
65
- not: ["mobileUsers"],
66
- },
67
- ],
68
- },
69
- ],
70
- },
71
-
72
- // version
73
- {
74
- key: "notVersion5.5",
75
- segments: [
76
- {
77
- not: ["version_5.5"],
78
- },
79
- ],
80
- },
81
- ];
82
-
83
- const datafileContent: DatafileContent = {
84
- schemaVersion: "1.0",
85
- revision: "1",
86
- features: [],
87
- attributes: [],
88
-
89
- segments: [
90
- // deviceType
91
- {
92
- key: "mobileUsers",
93
- conditions: [
94
- {
95
- attribute: "deviceType",
96
- operator: "equals",
97
- value: "mobile",
98
- },
99
- ],
100
- },
101
- {
102
- key: "desktopUsers",
103
- conditions: [
104
- {
105
- attribute: "deviceType",
106
- operator: "equals",
107
- value: "desktop",
108
- },
109
- ],
110
- },
111
-
112
- // browser
113
- {
114
- key: "chromeBrowser",
115
- conditions: [
116
- {
117
- attribute: "browser",
118
- operator: "equals",
119
- value: "chrome",
120
- },
121
- ],
122
- },
123
- {
124
- key: "firefoxBrowser",
125
- conditions: [
126
- {
127
- attribute: "browser",
128
- operator: "equals",
129
- value: "firefox",
130
- },
131
- ],
132
- },
133
-
134
- // country
135
- {
136
- key: "netherlands",
137
- conditions: [
138
- {
139
- attribute: "country",
140
- operator: "equals",
141
- value: "nl",
142
- },
143
- ],
144
- },
145
- {
146
- key: "germany",
147
- conditions: [
148
- {
149
- attribute: "country",
150
- operator: "equals",
151
- value: "de",
152
- },
153
- ],
154
- },
155
-
156
- // version
157
- {
158
- key: "version_5.5",
159
- conditions: [
160
- {
161
- or: [
162
- {
163
- attribute: "version",
164
- operator: "equals",
165
- value: "5.5",
166
- },
167
- {
168
- attribute: "version",
169
- operator: "equals",
170
- value: 5.5,
171
- },
172
- ],
173
- },
174
- ],
175
- },
176
- ],
177
- };
178
-
179
- const datafileReader = new DatafileReader(datafileContent);
180
-
181
- it("should match everyone", function () {
182
- const group = groups.find((g) => g.key === "*") as Group;
183
-
184
- // match
185
- expect(allGroupSegmentsAreMatched(group.segments, {}, datafileReader, logger)).toEqual(true);
186
- expect(
187
- allGroupSegmentsAreMatched(group.segments, { foo: "foo" }, datafileReader, logger),
188
- ).toEqual(true);
189
- expect(
190
- allGroupSegmentsAreMatched(group.segments, { bar: "bar" }, datafileReader, logger),
191
- ).toEqual(true);
192
- });
193
-
194
- it("should match dutchMobileUsers", function () {
195
- const group = groups.find((g) => g.key === "dutchMobileUsers") as Group;
196
-
197
- // match
198
- expect(
199
- allGroupSegmentsAreMatched(
200
- group.segments,
201
- { country: "nl", deviceType: "mobile" },
202
- datafileReader,
203
- logger,
204
- ),
205
- ).toEqual(true);
206
- expect(
207
- allGroupSegmentsAreMatched(
208
- group.segments,
209
- { country: "nl", deviceType: "mobile", browser: "chrome" },
210
- datafileReader,
211
- logger,
212
- ),
213
- ).toEqual(true);
214
-
215
- // not match
216
- expect(allGroupSegmentsAreMatched(group.segments, {}, datafileReader, logger)).toEqual(false);
217
- expect(
218
- allGroupSegmentsAreMatched(
219
- group.segments,
220
- { country: "de", deviceType: "mobile" },
221
- datafileReader,
222
- logger,
223
- ),
224
- ).toEqual(false);
225
- });
226
-
227
- it("should match dutchMobileUsers2", function () {
228
- const group = groups.find((g) => g.key === "dutchMobileUsers") as Group;
229
-
230
- // match
231
- expect(
232
- allGroupSegmentsAreMatched(
233
- group.segments,
234
- { country: "nl", deviceType: "mobile" },
235
- datafileReader,
236
- logger,
237
- ),
238
- ).toEqual(true);
239
- expect(
240
- allGroupSegmentsAreMatched(
241
- group.segments,
242
- { country: "nl", deviceType: "mobile", browser: "chrome" },
243
- datafileReader,
244
- logger,
245
- ),
246
- ).toEqual(true);
247
-
248
- // not match
249
- expect(allGroupSegmentsAreMatched(group.segments, {}, datafileReader, logger)).toEqual(false);
250
- expect(
251
- allGroupSegmentsAreMatched(
252
- group.segments,
253
- { country: "de", deviceType: "mobile" },
254
- datafileReader,
255
- logger,
256
- ),
257
- ).toEqual(false);
258
- });
259
-
260
- it("should match dutchMobileOrDesktopUsers", function () {
261
- const group = groups.find((g) => g.key === "dutchMobileOrDesktopUsers") as Group;
262
-
263
- // match
264
- expect(
265
- allGroupSegmentsAreMatched(
266
- group.segments,
267
- { country: "nl", deviceType: "mobile" },
268
- datafileReader,
269
- logger,
270
- ),
271
- ).toEqual(true);
272
- expect(
273
- allGroupSegmentsAreMatched(
274
- group.segments,
275
- { country: "nl", deviceType: "mobile", browser: "chrome" },
276
- datafileReader,
277
- logger,
278
- ),
279
- ).toEqual(true);
280
- expect(
281
- allGroupSegmentsAreMatched(
282
- group.segments,
283
- { country: "nl", deviceType: "desktop" },
284
- datafileReader,
285
- logger,
286
- ),
287
- ).toEqual(true);
288
- expect(
289
- allGroupSegmentsAreMatched(
290
- group.segments,
291
- { country: "nl", deviceType: "desktop", browser: "chrome" },
292
- datafileReader,
293
- logger,
294
- ),
295
- ).toEqual(true);
296
-
297
- // not match
298
- expect(allGroupSegmentsAreMatched(group.segments, {}, datafileReader, logger)).toEqual(false);
299
- expect(
300
- allGroupSegmentsAreMatched(
301
- group.segments,
302
- { country: "de", deviceType: "mobile" },
303
- datafileReader,
304
- logger,
305
- ),
306
- ).toEqual(false);
307
- expect(
308
- allGroupSegmentsAreMatched(
309
- group.segments,
310
- { country: "de", deviceType: "desktop" },
311
- datafileReader,
312
- logger,
313
- ),
314
- ).toEqual(false);
315
- });
316
-
317
- it("should match dutchMobileOrDesktopUsers2", function () {
318
- const group = groups.find((g) => g.key === "dutchMobileOrDesktopUsers2") as Group;
319
-
320
- // match
321
- expect(
322
- allGroupSegmentsAreMatched(
323
- group.segments,
324
- { country: "nl", deviceType: "mobile" },
325
- datafileReader,
326
- logger,
327
- ),
328
- ).toEqual(true);
329
- expect(
330
- allGroupSegmentsAreMatched(
331
- group.segments,
332
- { country: "nl", deviceType: "mobile", browser: "chrome" },
333
- datafileReader,
334
- logger,
335
- ),
336
- ).toEqual(true);
337
- expect(
338
- allGroupSegmentsAreMatched(
339
- group.segments,
340
- { country: "nl", deviceType: "desktop" },
341
- datafileReader,
342
- logger,
343
- ),
344
- ).toEqual(true);
345
- expect(
346
- allGroupSegmentsAreMatched(
347
- group.segments,
348
- { country: "nl", deviceType: "desktop", browser: "chrome" },
349
- datafileReader,
350
- logger,
351
- ),
352
- ).toEqual(true);
353
-
354
- // not match
355
- expect(allGroupSegmentsAreMatched(group.segments, {}, datafileReader, logger)).toEqual(false);
356
- expect(
357
- allGroupSegmentsAreMatched(
358
- group.segments,
359
- { country: "de", deviceType: "mobile" },
360
- datafileReader,
361
- logger,
362
- ),
363
- ).toEqual(false);
364
- expect(
365
- allGroupSegmentsAreMatched(
366
- group.segments,
367
- { country: "de", deviceType: "desktop" },
368
- datafileReader,
369
- logger,
370
- ),
371
- ).toEqual(false);
372
- });
373
-
374
- it("should match germanMobileUsers", function () {
375
- const group = groups.find((g) => g.key === "germanMobileUsers") as Group;
376
-
377
- // match
378
- expect(
379
- allGroupSegmentsAreMatched(
380
- group.segments,
381
- { country: "de", deviceType: "mobile" },
382
- datafileReader,
383
- logger,
384
- ),
385
- ).toEqual(true);
386
- expect(
387
- allGroupSegmentsAreMatched(
388
- group.segments,
389
- { country: "de", deviceType: "mobile", browser: "chrome" },
390
- datafileReader,
391
- logger,
392
- ),
393
- ).toEqual(true);
394
-
395
- // not match
396
- expect(allGroupSegmentsAreMatched(group.segments, {}, datafileReader, logger)).toEqual(false);
397
- expect(
398
- allGroupSegmentsAreMatched(
399
- group.segments,
400
- { country: "nl", deviceType: "mobile" },
401
- datafileReader,
402
- logger,
403
- ),
404
- ).toEqual(false);
405
- });
406
-
407
- it("should match germanNonMobileUsers", function () {
408
- const group = groups.find((g) => g.key === "germanNonMobileUsers") as Group;
409
-
410
- // match
411
- expect(
412
- allGroupSegmentsAreMatched(
413
- group.segments,
414
- { country: "de", deviceType: "desktop" },
415
- datafileReader,
416
- logger,
417
- ),
418
- ).toEqual(true);
419
- expect(
420
- allGroupSegmentsAreMatched(
421
- group.segments,
422
- { country: "de", deviceType: "desktop", browser: "chrome" },
423
- datafileReader,
424
- logger,
425
- ),
426
- ).toEqual(true);
427
-
428
- // not match
429
- expect(allGroupSegmentsAreMatched(group.segments, {}, datafileReader, logger)).toEqual(false);
430
- expect(
431
- allGroupSegmentsAreMatched(
432
- group.segments,
433
- { country: "nl", deviceType: "desktop" },
434
- datafileReader,
435
- logger,
436
- ),
437
- ).toEqual(false);
438
- });
439
-
440
- it("should match notVersion5.5", function () {
441
- const group = groups.find((g) => g.key === "notVersion5.5") as Group;
442
-
443
- // match
444
- expect(allGroupSegmentsAreMatched(group.segments, {}, datafileReader, logger)).toEqual(true);
445
- expect(allGroupSegmentsAreMatched(group.segments, {}, datafileReader, logger)).toEqual(true);
446
- expect(
447
- allGroupSegmentsAreMatched(group.segments, { version: "5.6" }, datafileReader, logger),
448
- ).toEqual(true);
449
- expect(
450
- allGroupSegmentsAreMatched(group.segments, { version: 5.6 }, datafileReader, logger),
451
- ).toEqual(true);
452
- expect(
453
- allGroupSegmentsAreMatched(group.segments, { version: "5.7" }, datafileReader, logger),
454
- ).toEqual(true);
455
- expect(
456
- allGroupSegmentsAreMatched(group.segments, { version: 5.7 }, datafileReader, logger),
457
- ).toEqual(true);
458
-
459
- // not match
460
- expect(
461
- allGroupSegmentsAreMatched(group.segments, { version: "5.5" }, datafileReader, logger),
462
- ).toEqual(false);
463
- expect(
464
- allGroupSegmentsAreMatched(group.segments, { version: 5.5 }, datafileReader, logger),
465
- ).toEqual(false);
466
- });
467
- });
468
- });
package/src/segments.ts DELETED
@@ -1,58 +0,0 @@
1
- import { Context, GroupSegment, Segment, Condition } from "@featurevisor/types";
2
- import { allConditionsAreMatched } from "./conditions";
3
- import { DatafileReader } from "./datafileReader";
4
- import { Logger } from "./logger";
5
-
6
- export function segmentIsMatched(segment: Segment, context: Context, logger: Logger): boolean {
7
- return allConditionsAreMatched(segment.conditions as Condition | Condition[], context, logger);
8
- }
9
-
10
- export function allGroupSegmentsAreMatched(
11
- groupSegments: GroupSegment | GroupSegment[] | "*",
12
- context: Context,
13
- datafileReader: DatafileReader,
14
- logger: Logger,
15
- ): boolean {
16
- if (groupSegments === "*") {
17
- return true;
18
- }
19
-
20
- if (typeof groupSegments === "string") {
21
- const segment = datafileReader.getSegment(groupSegments);
22
-
23
- if (segment) {
24
- return segmentIsMatched(segment, context, logger);
25
- }
26
-
27
- return false;
28
- }
29
-
30
- if (typeof groupSegments === "object") {
31
- if ("and" in groupSegments && Array.isArray(groupSegments.and)) {
32
- return groupSegments.and.every((groupSegment) =>
33
- allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger),
34
- );
35
- }
36
-
37
- if ("or" in groupSegments && Array.isArray(groupSegments.or)) {
38
- return groupSegments.or.some((groupSegment) =>
39
- allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger),
40
- );
41
- }
42
-
43
- if ("not" in groupSegments && Array.isArray(groupSegments.not)) {
44
- return groupSegments.not.every(
45
- (groupSegment) =>
46
- allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger) === false,
47
- );
48
- }
49
- }
50
-
51
- if (Array.isArray(groupSegments)) {
52
- return groupSegments.every((groupSegment) =>
53
- allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger),
54
- );
55
- }
56
-
57
- return false;
58
- }