@featurevisor/core 1.13.0 → 1.14.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/.eslintcache +1 -1
- package/CHANGELOG.md +22 -0
- package/coverage/clover.xml +2 -2
- package/coverage/lcov-report/index.html +1 -1
- package/coverage/lcov-report/lib/builder/allocator.js.html +1 -1
- package/coverage/lcov-report/lib/builder/index.html +1 -1
- package/coverage/lcov-report/lib/builder/revision.js.html +1 -1
- package/coverage/lcov-report/lib/builder/traffic.js.html +1 -1
- package/coverage/lcov-report/lib/tester/checkIfObjectsAreEqual.js.html +1 -1
- package/coverage/lcov-report/lib/tester/index.html +1 -1
- package/coverage/lcov-report/lib/tester/matrix.js.html +1 -1
- package/coverage/lcov-report/src/builder/allocator.ts.html +1 -1
- package/coverage/lcov-report/src/builder/index.html +1 -1
- package/coverage/lcov-report/src/builder/revision.ts.html +1 -1
- package/coverage/lcov-report/src/builder/traffic.ts.html +1 -1
- package/coverage/lcov-report/src/tester/checkIfObjectsAreEqual.ts.html +1 -1
- package/coverage/lcov-report/src/tester/index.html +1 -1
- package/coverage/lcov-report/src/tester/matrix.ts.html +1 -1
- package/lib/benchmark/index.d.ts +18 -0
- package/lib/benchmark/index.js +139 -0
- package/lib/benchmark/index.js.map +1 -0
- package/lib/find-usage/index.d.ts +14 -0
- package/lib/find-usage/index.js +164 -136
- package/lib/find-usage/index.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/benchmark/index.ts +150 -0
- package/src/find-usage/index.ts +131 -76
- package/src/index.ts +1 -0
package/src/find-usage/index.ts
CHANGED
|
@@ -6,19 +6,49 @@ import {
|
|
|
6
6
|
extractSegmentKeysFromGroupSegments,
|
|
7
7
|
} from "../utils/extractKeys";
|
|
8
8
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
export interface UsageInFeatures {
|
|
10
|
+
[featureKey: string]: {
|
|
11
|
+
features: Set<FeatureKey>;
|
|
12
|
+
segments: Set<SegmentKey>;
|
|
13
|
+
attributes: Set<AttributeKey>;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function findAllUsageInFeatures(deps: Dependencies): Promise<UsageInFeatures> {
|
|
13
18
|
const { datasource, projectConfig } = deps;
|
|
19
|
+
const usageInFeatures: UsageInFeatures = {};
|
|
14
20
|
|
|
15
21
|
const featureKeys = await datasource.listFeatures();
|
|
16
22
|
|
|
17
|
-
const usedInFeatures = new Set<FeatureKey>();
|
|
18
|
-
|
|
19
23
|
for (const featureKey of featureKeys) {
|
|
20
24
|
const feature = await datasource.readFeature(featureKey);
|
|
21
|
-
|
|
25
|
+
usageInFeatures[featureKey] = {
|
|
26
|
+
features: new Set<FeatureKey>(),
|
|
27
|
+
segments: new Set<SegmentKey>(),
|
|
28
|
+
attributes: new Set<AttributeKey>(),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// required
|
|
32
|
+
if (feature.required) {
|
|
33
|
+
feature.required.forEach((required) => {
|
|
34
|
+
if (typeof required === "string") {
|
|
35
|
+
usageInFeatures[featureKey].features.add(required);
|
|
36
|
+
} else if (typeof required === "object" && required.key) {
|
|
37
|
+
usageInFeatures[featureKey].features.add(required.key);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// bucketBy
|
|
43
|
+
if (feature.bucketBy) {
|
|
44
|
+
if (typeof feature.bucketBy === "string") {
|
|
45
|
+
usageInFeatures[featureKey].attributes.add(feature.bucketBy);
|
|
46
|
+
} else if (Array.isArray(feature.bucketBy)) {
|
|
47
|
+
feature.bucketBy.forEach((b) => usageInFeatures[featureKey].attributes.add(b));
|
|
48
|
+
} else if (typeof feature.bucketBy === "object" && feature.bucketBy.or) {
|
|
49
|
+
feature.bucketBy.or.forEach((b) => usageInFeatures[featureKey].attributes.add(b));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
22
52
|
|
|
23
53
|
// variable overrides inside variations
|
|
24
54
|
projectConfig.environments.forEach((environment) => {
|
|
@@ -30,7 +60,13 @@ export async function findSegmentUsage(
|
|
|
30
60
|
variable.overrides.forEach((override) => {
|
|
31
61
|
if (override.segments) {
|
|
32
62
|
extractSegmentKeysFromGroupSegments(override.segments).forEach((segmentKey) =>
|
|
33
|
-
|
|
63
|
+
usageInFeatures[featureKey].segments.add(segmentKey),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (override.conditions) {
|
|
68
|
+
extractAttributeKeysFromConditions(override.conditions).forEach(
|
|
69
|
+
(attributeKey) => usageInFeatures[featureKey].attributes.add(attributeKey),
|
|
34
70
|
);
|
|
35
71
|
}
|
|
36
72
|
});
|
|
@@ -45,7 +81,13 @@ export async function findSegmentUsage(
|
|
|
45
81
|
feature.environments[environment].force?.forEach((force) => {
|
|
46
82
|
if (force.segments) {
|
|
47
83
|
extractSegmentKeysFromGroupSegments(force.segments).forEach((segmentKey) =>
|
|
48
|
-
|
|
84
|
+
usageInFeatures[featureKey].segments.add(segmentKey),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (force.conditions) {
|
|
89
|
+
extractAttributeKeysFromConditions(force.conditions).forEach((attributeKey) =>
|
|
90
|
+
usageInFeatures[featureKey].attributes.add(attributeKey),
|
|
49
91
|
);
|
|
50
92
|
}
|
|
51
93
|
});
|
|
@@ -55,13 +97,54 @@ export async function findSegmentUsage(
|
|
|
55
97
|
if (feature.environments[environment].rules) {
|
|
56
98
|
feature.environments[environment].rules?.forEach((rule) => {
|
|
57
99
|
extractSegmentKeysFromGroupSegments(rule.segments).forEach((segmentKey) =>
|
|
58
|
-
|
|
100
|
+
usageInFeatures[featureKey].segments.add(segmentKey),
|
|
59
101
|
);
|
|
60
102
|
});
|
|
61
103
|
}
|
|
62
104
|
});
|
|
105
|
+
}
|
|
63
106
|
|
|
64
|
-
|
|
107
|
+
return usageInFeatures;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface UsageInSegments {
|
|
111
|
+
[segmentKey: string]: {
|
|
112
|
+
attributes: Set<AttributeKey>;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function findAllUsageInSegments(deps: Dependencies): Promise<UsageInSegments> {
|
|
117
|
+
const { datasource } = deps;
|
|
118
|
+
const usageInSegments: UsageInSegments = {};
|
|
119
|
+
|
|
120
|
+
const segmentKeys = await datasource.listSegments();
|
|
121
|
+
|
|
122
|
+
for (const segmentKey of segmentKeys) {
|
|
123
|
+
const segment = await datasource.readSegment(segmentKey);
|
|
124
|
+
usageInSegments[segmentKey] = {
|
|
125
|
+
attributes: new Set<AttributeKey>(),
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
extractAttributeKeysFromConditions(segment.conditions as Condition | Condition[]).forEach(
|
|
129
|
+
(attributeKey) => {
|
|
130
|
+
usageInSegments[segmentKey].attributes.add(attributeKey);
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return usageInSegments;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function findSegmentUsage(
|
|
139
|
+
deps: Dependencies,
|
|
140
|
+
segmentKey: SegmentKey,
|
|
141
|
+
): Promise<Set<FeatureKey>> {
|
|
142
|
+
const usedInFeatures = new Set<FeatureKey>();
|
|
143
|
+
|
|
144
|
+
const usageInFeatures = await findAllUsageInFeatures(deps);
|
|
145
|
+
|
|
146
|
+
for (const featureKey in usageInFeatures) {
|
|
147
|
+
if (usageInFeatures[featureKey].segments.has(segmentKey)) {
|
|
65
148
|
usedInFeatures.add(featureKey);
|
|
66
149
|
}
|
|
67
150
|
}
|
|
@@ -78,69 +161,22 @@ export async function findAttributeUsage(
|
|
|
78
161
|
deps: Dependencies,
|
|
79
162
|
attributeKey: AttributeKey,
|
|
80
163
|
): Promise<AttributeUsage> {
|
|
81
|
-
const { datasource, projectConfig } = deps;
|
|
82
|
-
|
|
83
164
|
const usedIn: AttributeUsage = {
|
|
84
165
|
features: new Set<FeatureKey>(),
|
|
85
166
|
segments: new Set<SegmentKey>(),
|
|
86
167
|
};
|
|
87
168
|
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
for (const featureKey of featureKeys) {
|
|
91
|
-
const feature = await datasource.readFeature(featureKey);
|
|
92
|
-
const attributeKeys = new Set<AttributeKey>();
|
|
169
|
+
const usageInFeatures = await findAllUsageInFeatures(deps);
|
|
170
|
+
const usageInSegments = await findAllUsageInSegments(deps);
|
|
93
171
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (feature.variations) {
|
|
97
|
-
feature.variations.forEach((variation) => {
|
|
98
|
-
if (variation.variables) {
|
|
99
|
-
variation.variables.forEach((variable) => {
|
|
100
|
-
if (variable.overrides) {
|
|
101
|
-
variable.overrides.forEach((override) => {
|
|
102
|
-
if (override.conditions) {
|
|
103
|
-
extractAttributeKeysFromConditions(override.conditions).forEach(
|
|
104
|
-
(attributeKey) => attributeKeys.add(attributeKey),
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// force
|
|
115
|
-
if (feature.environments[environment].force) {
|
|
116
|
-
feature.environments[environment].force?.forEach((force) => {
|
|
117
|
-
if (force.conditions) {
|
|
118
|
-
extractAttributeKeysFromConditions(force.conditions).forEach((attributeKey) =>
|
|
119
|
-
attributeKeys.add(attributeKey),
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
if (attributeKeys.has(attributeKey)) {
|
|
172
|
+
for (const featureKey in usageInFeatures) {
|
|
173
|
+
if (usageInFeatures[featureKey].attributes.has(attributeKey)) {
|
|
127
174
|
usedIn.features.add(featureKey);
|
|
128
175
|
}
|
|
129
176
|
}
|
|
130
177
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
for (const segmentKey of segmentKeys) {
|
|
134
|
-
const segment = await datasource.readSegment(segmentKey);
|
|
135
|
-
const attributeKeys = new Set<AttributeKey>();
|
|
136
|
-
|
|
137
|
-
extractAttributeKeysFromConditions(segment.conditions as Condition | Condition[]).forEach(
|
|
138
|
-
(attributeKey) => {
|
|
139
|
-
attributeKeys.add(attributeKey);
|
|
140
|
-
},
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
if (attributeKeys.has(attributeKey)) {
|
|
178
|
+
for (const segmentKey in usageInSegments) {
|
|
179
|
+
if (usageInSegments[segmentKey].attributes.has(attributeKey)) {
|
|
144
180
|
usedIn.segments.add(segmentKey);
|
|
145
181
|
}
|
|
146
182
|
}
|
|
@@ -150,34 +186,53 @@ export async function findAttributeUsage(
|
|
|
150
186
|
|
|
151
187
|
export async function findUnusedSegments(deps: Dependencies): Promise<Set<SegmentKey>> {
|
|
152
188
|
const { datasource } = deps;
|
|
153
|
-
|
|
154
|
-
const segmentKeys = await datasource.listSegments();
|
|
155
189
|
const unusedSegments = new Set<SegmentKey>();
|
|
156
190
|
|
|
157
|
-
|
|
158
|
-
|
|
191
|
+
const allSegmentKeys = await datasource.listSegments();
|
|
192
|
+
const usageInFeatures = await findAllUsageInFeatures(deps);
|
|
193
|
+
const usedSegmentKeys = new Set<SegmentKey>();
|
|
159
194
|
|
|
160
|
-
|
|
195
|
+
for (const featureKey in usageInFeatures) {
|
|
196
|
+
usageInFeatures[featureKey].segments.forEach((segmentKey) => {
|
|
197
|
+
usedSegmentKeys.add(segmentKey);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
allSegmentKeys.forEach((segmentKey) => {
|
|
202
|
+
if (!usedSegmentKeys.has(segmentKey)) {
|
|
161
203
|
unusedSegments.add(segmentKey);
|
|
162
204
|
}
|
|
163
|
-
}
|
|
205
|
+
});
|
|
164
206
|
|
|
165
207
|
return unusedSegments;
|
|
166
208
|
}
|
|
167
209
|
|
|
168
210
|
export async function findUnusedAttributes(deps: Dependencies): Promise<Set<AttributeKey>> {
|
|
169
211
|
const { datasource } = deps;
|
|
170
|
-
|
|
171
|
-
const attributeKeys = await datasource.listAttributes();
|
|
172
212
|
const unusedAttributes = new Set<AttributeKey>();
|
|
173
213
|
|
|
174
|
-
|
|
175
|
-
|
|
214
|
+
const allAttributeKeys = await datasource.listAttributes();
|
|
215
|
+
const usageInFeatures = await findAllUsageInFeatures(deps);
|
|
216
|
+
const usageInSegments = await findAllUsageInSegments(deps);
|
|
217
|
+
const usedAttributeKeys = new Set<AttributeKey>();
|
|
176
218
|
|
|
177
|
-
|
|
219
|
+
for (const featureKey in usageInFeatures) {
|
|
220
|
+
usageInFeatures[featureKey].attributes.forEach((attributeKey) => {
|
|
221
|
+
usedAttributeKeys.add(attributeKey);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
for (const segmentKey in usageInSegments) {
|
|
226
|
+
usageInSegments[segmentKey].attributes.forEach((attributeKey) => {
|
|
227
|
+
usedAttributeKeys.add(attributeKey);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
allAttributeKeys.forEach((attributeKey) => {
|
|
232
|
+
if (!usedAttributeKeys.has(attributeKey)) {
|
|
178
233
|
unusedAttributes.add(attributeKey);
|
|
179
234
|
}
|
|
180
|
-
}
|
|
235
|
+
});
|
|
181
236
|
|
|
182
237
|
return unusedAttributes;
|
|
183
238
|
}
|
package/src/index.ts
CHANGED