@featurevisor/core 0.52.1 → 0.53.1

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 (51) hide show
  1. package/.eslintcache +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/coverage/clover.xml +2 -2
  4. package/coverage/lcov-report/index.html +1 -1
  5. package/coverage/lcov-report/lib/builder/allocator.js.html +1 -1
  6. package/coverage/lcov-report/lib/builder/index.html +1 -1
  7. package/coverage/lcov-report/lib/builder/traffic.js.html +1 -1
  8. package/coverage/lcov-report/src/builder/allocator.ts.html +1 -1
  9. package/coverage/lcov-report/src/builder/index.html +1 -1
  10. package/coverage/lcov-report/src/builder/traffic.ts.html +1 -1
  11. package/lib/find-duplicate-segments/findDuplicateSegments.d.ts +3 -0
  12. package/lib/find-duplicate-segments/findDuplicateSegments.js +27 -0
  13. package/lib/find-duplicate-segments/findDuplicateSegments.js.map +1 -0
  14. package/lib/find-duplicate-segments/index.d.ts +2 -0
  15. package/lib/find-duplicate-segments/index.js +19 -0
  16. package/lib/find-duplicate-segments/index.js.map +1 -0
  17. package/lib/index.d.ts +1 -0
  18. package/lib/index.js +1 -0
  19. package/lib/index.js.map +1 -1
  20. package/lib/tester/checkIfArraysAreEqual.d.ts +1 -0
  21. package/lib/tester/checkIfArraysAreEqual.js +19 -0
  22. package/lib/tester/checkIfArraysAreEqual.js.map +1 -0
  23. package/lib/tester/checkIfObjectsAreEqual.d.ts +1 -0
  24. package/lib/tester/checkIfObjectsAreEqual.js +22 -0
  25. package/lib/tester/checkIfObjectsAreEqual.js.map +1 -0
  26. package/lib/tester/index.d.ts +1 -0
  27. package/lib/tester/index.js +18 -0
  28. package/lib/tester/index.js.map +1 -0
  29. package/lib/tester/testFeature.d.ts +4 -0
  30. package/lib/tester/testFeature.js +74 -0
  31. package/lib/tester/testFeature.js.map +1 -0
  32. package/lib/tester/testProject.d.ts +2 -0
  33. package/lib/tester/testProject.js +51 -0
  34. package/lib/tester/testProject.js.map +1 -0
  35. package/lib/tester/testSegment.d.ts +3 -0
  36. package/lib/tester/testSegment.js +30 -0
  37. package/lib/tester/testSegment.js.map +1 -0
  38. package/package.json +5 -5
  39. package/src/find-duplicate-segments/findDuplicateSegments.ts +33 -0
  40. package/src/find-duplicate-segments/index.ts +21 -0
  41. package/src/index.ts +1 -0
  42. package/src/tester/checkIfArraysAreEqual.ts +16 -0
  43. package/src/tester/checkIfObjectsAreEqual.ts +21 -0
  44. package/src/tester/index.ts +1 -0
  45. package/src/tester/testFeature.ts +112 -0
  46. package/src/tester/testProject.ts +63 -0
  47. package/src/tester/testSegment.ts +41 -0
  48. package/lib/tester.d.ts +0 -4
  49. package/lib/tester.js +0 -159
  50. package/lib/tester.js.map +0 -1
  51. package/src/tester.ts +0 -213
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featurevisor/core",
3
- "version": "0.52.1",
3
+ "version": "0.53.1",
4
4
  "description": "Core package of Featurevisor for Node.js usage",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -44,9 +44,9 @@
44
44
  },
45
45
  "license": "MIT",
46
46
  "dependencies": {
47
- "@featurevisor/sdk": "^0.52.0",
48
- "@featurevisor/site": "^0.52.0",
49
- "@featurevisor/types": "^0.52.0",
47
+ "@featurevisor/sdk": "^0.53.0",
48
+ "@featurevisor/site": "^0.53.0",
49
+ "@featurevisor/types": "^0.53.0",
50
50
  "axios": "^1.3.4",
51
51
  "joi": "^17.8.3",
52
52
  "js-yaml": "^4.1.0",
@@ -57,5 +57,5 @@
57
57
  "@types/js-yaml": "^4.0.5",
58
58
  "@types/tar": "^6.1.4"
59
59
  },
60
- "gitHead": "2ab10538e5f287087fe0892c3a383476dbe6df86"
60
+ "gitHead": "d1a30c5cd870a149bcee916a9b90eb9bbbaa38f1"
61
61
  }
@@ -0,0 +1,33 @@
1
+ import * as crypto from "crypto";
2
+
3
+ import { SegmentKey } from "@featurevisor/types";
4
+
5
+ import { Datasource } from "../datasource";
6
+
7
+ export function findDuplicateSegments(datasource: Datasource): SegmentKey[][] {
8
+ const segmentsWithHash = datasource.listSegments().map((segmentKey) => {
9
+ const segment = datasource.readSegment(segmentKey);
10
+ const conditions = JSON.stringify(segment.conditions);
11
+ const hash = crypto.createHash("sha256").update(conditions).digest("hex");
12
+
13
+ return {
14
+ segmentKey,
15
+ hash,
16
+ };
17
+ });
18
+
19
+ const groupedSegments: { [hash: string]: SegmentKey[] } = segmentsWithHash.reduce(
20
+ (acc, { segmentKey, hash }) => {
21
+ if (!acc[hash]) {
22
+ acc[hash] = [];
23
+ }
24
+ acc[hash].push(segmentKey);
25
+ return acc;
26
+ },
27
+ {},
28
+ );
29
+
30
+ const result = Object.values(groupedSegments).filter((segmentKeys) => segmentKeys.length > 1);
31
+
32
+ return result;
33
+ }
@@ -0,0 +1,21 @@
1
+ import { Datasource } from "../datasource";
2
+ import { ProjectConfig } from "../config";
3
+
4
+ import { findDuplicateSegments } from "./findDuplicateSegments";
5
+
6
+ export function findDuplicateSegmentsInProject(rootDirectoryPath, projectConfig: ProjectConfig) {
7
+ const datasource = new Datasource(projectConfig);
8
+
9
+ const duplicates = findDuplicateSegments(datasource);
10
+
11
+ if (duplicates.length === 0) {
12
+ console.log("No duplicate segments found");
13
+ return;
14
+ }
15
+
16
+ console.log(`Found ${duplicates.length} duplicates:\n`);
17
+
18
+ duplicates.forEach((segmentKeys) => {
19
+ console.log(` - ${segmentKeys.join(", ")}`);
20
+ });
21
+ }
package/src/index.ts CHANGED
@@ -6,3 +6,4 @@ export * from "./init";
6
6
  export * from "./site";
7
7
  export * from "./generate-code";
8
8
  export * from "./restore";
9
+ export * from "./find-duplicate-segments";
@@ -0,0 +1,16 @@
1
+ // @TODO: make it better
2
+ export function checkIfArraysAreEqual(a, b) {
3
+ if (!Array.isArray(a) || !Array.isArray(b)) {
4
+ return false;
5
+ }
6
+
7
+ if (a.length !== b.length) return false;
8
+
9
+ for (let i = 0; i < a.length; ++i) {
10
+ if (a[i] !== b[i]) {
11
+ return false;
12
+ }
13
+ }
14
+
15
+ return true;
16
+ }
@@ -0,0 +1,21 @@
1
+ export function checkIfObjectsAreEqual(a, b) {
2
+ if (typeof a !== "object" || typeof b !== "object") {
3
+ return false;
4
+ }
5
+
6
+ if (a === null || b === null) {
7
+ return false;
8
+ }
9
+
10
+ if (Object.keys(a).length !== Object.keys(b).length) {
11
+ return false;
12
+ }
13
+
14
+ for (const key in a) {
15
+ if (a[key] !== b[key]) {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ return true;
21
+ }
@@ -0,0 +1 @@
1
+ export * from "./testProject";
@@ -0,0 +1,112 @@
1
+ import * as fs from "fs";
2
+
3
+ import { TestFeature, ExistingState } from "@featurevisor/types";
4
+ import { createInstance, MAX_BUCKETED_NUMBER } from "@featurevisor/sdk";
5
+
6
+ import { Datasource } from "../datasource";
7
+ import { ProjectConfig } from "../config";
8
+ import { buildDatafile, getExistingStateFilePath } from "../builder";
9
+ import { SCHEMA_VERSION } from "../config";
10
+
11
+ import { checkIfArraysAreEqual } from "./checkIfArraysAreEqual";
12
+ import { checkIfObjectsAreEqual } from "./checkIfObjectsAreEqual";
13
+
14
+ export function testFeature(
15
+ datasource: Datasource,
16
+ projectConfig: ProjectConfig,
17
+ test: TestFeature,
18
+ ): boolean {
19
+ let hasError = false;
20
+ const featureKey = test.feature;
21
+
22
+ console.log(` => Feature "${featureKey}":`);
23
+
24
+ test.assertions.forEach(function (assertion, aIndex) {
25
+ const description = assertion.description || `at ${assertion.at}%`;
26
+
27
+ console.log(` => Assertion #${aIndex + 1}: (${assertion.environment}) ${description}`);
28
+
29
+ const featuresToInclude = Array.from(datasource.getRequiredFeaturesChain(test.feature));
30
+
31
+ const datafileContent = buildDatafile(
32
+ projectConfig,
33
+ datasource,
34
+ {
35
+ schemaVersion: SCHEMA_VERSION,
36
+ revision: "testing",
37
+ environment: assertion.environment,
38
+ features: featuresToInclude,
39
+ },
40
+ JSON.parse(
41
+ fs.readFileSync(getExistingStateFilePath(projectConfig, assertion.environment), "utf8"),
42
+ ) as ExistingState,
43
+ );
44
+
45
+ const sdk = createInstance({
46
+ datafile: datafileContent,
47
+ configureBucketValue: () => {
48
+ return assertion.at * (MAX_BUCKETED_NUMBER / 100);
49
+ },
50
+ // logger: createLogger({
51
+ // levels: ["debug", "info", "warn", "error"],
52
+ // }),
53
+ });
54
+
55
+ // isEnabled
56
+ if ("expectedToBeEnabled" in assertion) {
57
+ const isEnabled = sdk.isEnabled(featureKey, assertion.context);
58
+
59
+ if (isEnabled !== assertion.expectedToBeEnabled) {
60
+ hasError = true;
61
+
62
+ console.error(
63
+ ` isEnabled failed: expected "${assertion.expectedToBeEnabled}", got "${isEnabled}"`,
64
+ );
65
+ }
66
+ }
67
+
68
+ // variation
69
+ if ("expectedVariation" in assertion) {
70
+ const variation = sdk.getVariation(featureKey, assertion.context);
71
+
72
+ if (variation !== assertion.expectedVariation) {
73
+ hasError = true;
74
+
75
+ console.error(
76
+ ` Variation failed: expected "${assertion.expectedVariation}", got "${variation}"`,
77
+ );
78
+ }
79
+ }
80
+
81
+ // variables
82
+ if (typeof assertion.expectedVariables === "object") {
83
+ Object.keys(assertion.expectedVariables).forEach(function (variableKey) {
84
+ const expectedValue =
85
+ assertion.expectedVariables && assertion.expectedVariables[variableKey];
86
+ const actualValue = sdk.getVariable(featureKey, variableKey, assertion.context);
87
+
88
+ let passed;
89
+
90
+ if (typeof expectedValue === "object") {
91
+ passed = checkIfObjectsAreEqual(expectedValue, actualValue);
92
+ } else if (Array.isArray(expectedValue)) {
93
+ passed = checkIfArraysAreEqual(expectedValue, actualValue);
94
+ } else {
95
+ passed = expectedValue === actualValue;
96
+ }
97
+
98
+ if (!passed) {
99
+ hasError = true;
100
+
101
+ console.error(
102
+ ` Variable "${variableKey}" failed: expected ${JSON.stringify(
103
+ expectedValue,
104
+ )}, got "${JSON.stringify(actualValue)}"`,
105
+ );
106
+ }
107
+ });
108
+ }
109
+ });
110
+
111
+ return hasError;
112
+ }
@@ -0,0 +1,63 @@
1
+ import * as fs from "fs";
2
+
3
+ import { TestSegment, TestFeature } from "@featurevisor/types";
4
+
5
+ import { ProjectConfig } from "../config";
6
+ import { Datasource } from "../datasource";
7
+
8
+ import { testSegment } from "./testSegment";
9
+ import { testFeature } from "./testFeature";
10
+
11
+ export function testProject(rootDirectoryPath: string, projectConfig: ProjectConfig): boolean {
12
+ let hasError = false;
13
+ const datasource = new Datasource(projectConfig);
14
+
15
+ if (!fs.existsSync(projectConfig.testsDirectoryPath)) {
16
+ console.error(`Tests directory does not exist: ${projectConfig.testsDirectoryPath}`);
17
+ hasError = true;
18
+
19
+ return hasError;
20
+ }
21
+
22
+ const testFiles = datasource.listTests();
23
+
24
+ if (testFiles.length === 0) {
25
+ console.error(`No tests found in: ${projectConfig.testsDirectoryPath}`);
26
+ hasError = true;
27
+
28
+ return hasError;
29
+ }
30
+
31
+ for (const testFile of testFiles) {
32
+ const testFilePath = datasource.getEntityPath("test", testFile);
33
+
34
+ console.log(` => Testing: ${testFilePath.replace(rootDirectoryPath, "")}`);
35
+
36
+ const t = datasource.readTest(testFile);
37
+
38
+ if ((t as TestSegment).segment) {
39
+ // segment testing
40
+ const test = t as TestSegment;
41
+
42
+ const segmentHasError = testSegment(datasource, test);
43
+
44
+ if (segmentHasError) {
45
+ hasError = true;
46
+ }
47
+ } else if ((t as TestFeature).feature) {
48
+ // feature testing
49
+ const test = t as TestFeature;
50
+
51
+ const featureHasError = testFeature(datasource, projectConfig, test);
52
+
53
+ if (featureHasError) {
54
+ hasError = true;
55
+ }
56
+ } else {
57
+ console.error(` => Invalid test: ${JSON.stringify(test)}`);
58
+ hasError = true;
59
+ }
60
+ }
61
+
62
+ return hasError;
63
+ }
@@ -0,0 +1,41 @@
1
+ import { TestSegment, Condition } from "@featurevisor/types";
2
+ import { allConditionsAreMatched } from "@featurevisor/sdk";
3
+
4
+ import { Datasource } from "../datasource";
5
+
6
+ export function testSegment(datasource: Datasource, test: TestSegment): boolean {
7
+ let hasError = false;
8
+
9
+ const segmentKey = test.segment;
10
+
11
+ console.log(` => Segment "${segmentKey}":`);
12
+
13
+ const segmentExists = datasource.entityExists("segment", segmentKey);
14
+
15
+ if (!segmentExists) {
16
+ console.error(` => Segment does not exist: ${segmentKey}`);
17
+ hasError = true;
18
+
19
+ return hasError;
20
+ }
21
+
22
+ const parsedSegment = datasource.readSegment(segmentKey);
23
+ const conditions = parsedSegment.conditions as Condition | Condition[];
24
+
25
+ test.assertions.forEach(function (assertion, aIndex) {
26
+ const description = assertion.description || `#${aIndex + 1}`;
27
+
28
+ console.log(` => Assertion #${aIndex + 1}: ${description}`);
29
+
30
+ const expected = assertion.expectedToMatch;
31
+ const actual = allConditionsAreMatched(conditions, assertion.context);
32
+
33
+ if (actual !== expected) {
34
+ hasError = true;
35
+
36
+ console.error(` Segment failed: expected "${expected}", got "${actual}"`);
37
+ }
38
+ });
39
+
40
+ return hasError;
41
+ }
package/lib/tester.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import { ProjectConfig } from "./config";
2
- export declare function checkIfArraysAreEqual(a: any, b: any): boolean;
3
- export declare function checkIfObjectsAreEqual(a: any, b: any): boolean;
4
- export declare function testProject(rootDirectoryPath: string, projectConfig: ProjectConfig): boolean;
package/lib/tester.js DELETED
@@ -1,159 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.testProject = exports.checkIfObjectsAreEqual = exports.checkIfArraysAreEqual = void 0;
4
- var fs = require("fs");
5
- var sdk_1 = require("@featurevisor/sdk");
6
- var config_1 = require("./config");
7
- var builder_1 = require("./builder");
8
- var datasource_1 = require("./datasource");
9
- // @TODO: make it better
10
- function checkIfArraysAreEqual(a, b) {
11
- if (!Array.isArray(a) || !Array.isArray(b)) {
12
- return false;
13
- }
14
- if (a.length !== b.length)
15
- return false;
16
- for (var i = 0; i < a.length; ++i) {
17
- if (a[i] !== b[i]) {
18
- return false;
19
- }
20
- }
21
- return true;
22
- }
23
- exports.checkIfArraysAreEqual = checkIfArraysAreEqual;
24
- function checkIfObjectsAreEqual(a, b) {
25
- if (typeof a !== "object" || typeof b !== "object") {
26
- return false;
27
- }
28
- if (a === null || b === null) {
29
- return false;
30
- }
31
- if (Object.keys(a).length !== Object.keys(b).length) {
32
- return false;
33
- }
34
- for (var key in a) {
35
- if (a[key] !== b[key]) {
36
- return false;
37
- }
38
- }
39
- return true;
40
- }
41
- exports.checkIfObjectsAreEqual = checkIfObjectsAreEqual;
42
- function testProject(rootDirectoryPath, projectConfig) {
43
- var hasError = false;
44
- var datasource = new datasource_1.Datasource(projectConfig);
45
- if (!fs.existsSync(projectConfig.testsDirectoryPath)) {
46
- console.error("Tests directory does not exist: ".concat(projectConfig.testsDirectoryPath));
47
- hasError = true;
48
- return hasError;
49
- }
50
- var testFiles = datasource.listTests();
51
- if (testFiles.length === 0) {
52
- console.error("No tests found in: ".concat(projectConfig.testsDirectoryPath));
53
- hasError = true;
54
- return hasError;
55
- }
56
- var _loop_1 = function (testFile) {
57
- var testFilePath = datasource.getEntityPath("test", testFile);
58
- console.log(" => Testing: ".concat(testFilePath.replace(rootDirectoryPath, "")));
59
- var test_1 = datasource.readTest(testFile);
60
- if (test_1.segment) {
61
- // segment testing
62
- var testSegment = test_1;
63
- var segmentKey = testSegment.segment;
64
- console.log(" => Segment \"".concat(segmentKey, "\":"));
65
- var segmentExists = datasource.entityExists("segment", segmentKey);
66
- if (!segmentExists) {
67
- console.error(" => Segment does not exist: ".concat(segmentKey));
68
- hasError = true;
69
- return "continue";
70
- }
71
- var parsedSegment = datasource.readSegment(segmentKey);
72
- var conditions_1 = parsedSegment.conditions;
73
- testSegment.assertions.forEach(function (assertion, aIndex) {
74
- var description = assertion.description || "#".concat(aIndex + 1);
75
- console.log(" => Assertion #".concat(aIndex + 1, ": ").concat(description));
76
- var expected = assertion.expectedToMatch;
77
- var actual = (0, sdk_1.allConditionsAreMatched)(conditions_1, assertion.context);
78
- if (actual !== expected) {
79
- hasError = true;
80
- console.error(" Segment failed: expected \"".concat(expected, "\", got \"").concat(actual, "\""));
81
- }
82
- });
83
- }
84
- else if (test_1.feature) {
85
- // feature testing
86
- var testFeature_1 = test_1;
87
- var featureKey_1 = testFeature_1.feature;
88
- console.log(" => Feature \"".concat(featureKey_1, "\":"));
89
- testFeature_1.assertions.forEach(function (assertion, aIndex) {
90
- var description = assertion.description || "at ".concat(assertion.at, "%");
91
- console.log(" => Assertion #".concat(aIndex + 1, ": (").concat(assertion.environment, ") ").concat(description));
92
- var featuresToInclude = Array.from(datasource.getRequiredFeaturesChain(testFeature_1.feature));
93
- var datafileContent = (0, builder_1.buildDatafile)(projectConfig, datasource, {
94
- schemaVersion: config_1.SCHEMA_VERSION,
95
- revision: "testing",
96
- environment: assertion.environment,
97
- features: featuresToInclude,
98
- }, JSON.parse(fs.readFileSync((0, builder_1.getExistingStateFilePath)(projectConfig, assertion.environment), "utf8")));
99
- var sdk = (0, sdk_1.createInstance)({
100
- datafile: datafileContent,
101
- configureBucketValue: function () {
102
- return assertion.at * (sdk_1.MAX_BUCKETED_NUMBER / 100);
103
- },
104
- // logger: createLogger({
105
- // levels: ["debug", "info", "warn", "error"],
106
- // }),
107
- });
108
- // isEnabled
109
- if ("expectedToBeEnabled" in assertion) {
110
- var isEnabled = sdk.isEnabled(featureKey_1, assertion.context);
111
- if (isEnabled !== assertion.expectedToBeEnabled) {
112
- hasError = true;
113
- console.error(" isEnabled failed: expected \"".concat(assertion.expectedToBeEnabled, "\", got \"").concat(isEnabled, "\""));
114
- }
115
- }
116
- // variation
117
- if ("expectedVariation" in assertion) {
118
- var variation = sdk.getVariation(featureKey_1, assertion.context);
119
- if (variation !== assertion.expectedVariation) {
120
- hasError = true;
121
- console.error(" Variation failed: expected \"".concat(assertion.expectedVariation, "\", got \"").concat(variation, "\""));
122
- }
123
- }
124
- // variables
125
- if (typeof assertion.expectedVariables === "object") {
126
- Object.keys(assertion.expectedVariables).forEach(function (variableKey) {
127
- var expectedValue = assertion.expectedVariables && assertion.expectedVariables[variableKey];
128
- var actualValue = sdk.getVariable(featureKey_1, variableKey, assertion.context);
129
- var passed;
130
- if (typeof expectedValue === "object") {
131
- passed = checkIfObjectsAreEqual(expectedValue, actualValue);
132
- }
133
- else if (Array.isArray(expectedValue)) {
134
- passed = checkIfArraysAreEqual(expectedValue, actualValue);
135
- }
136
- else {
137
- passed = expectedValue === actualValue;
138
- }
139
- if (!passed) {
140
- hasError = true;
141
- console.error(" Variable \"".concat(variableKey, "\" failed: expected ").concat(JSON.stringify(expectedValue), ", got \"").concat(JSON.stringify(actualValue), "\""));
142
- }
143
- });
144
- }
145
- });
146
- }
147
- else {
148
- console.error(" => Invalid test: ".concat(JSON.stringify(test_1)));
149
- hasError = true;
150
- }
151
- };
152
- for (var _i = 0, testFiles_1 = testFiles; _i < testFiles_1.length; _i++) {
153
- var testFile = testFiles_1[_i];
154
- _loop_1(testFile);
155
- }
156
- return hasError;
157
- }
158
- exports.testProject = testProject;
159
- //# sourceMappingURL=tester.js.map
package/lib/tester.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"tester.js","sourceRoot":"","sources":["../src/tester.ts"],"names":[],"mappings":"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"}