@featurevisor/core 1.35.2 → 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 (252) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +0 -6
  3. package/coverage/clover.xml +321 -237
  4. package/coverage/coverage-final.json +8 -8
  5. package/coverage/lcov-report/index.html +77 -47
  6. package/coverage/lcov-report/lib/builder/allocator.js.html +14 -14
  7. package/coverage/lcov-report/lib/builder/index.html +16 -16
  8. package/coverage/lcov-report/lib/builder/revision.js.html +3 -3
  9. package/coverage/lcov-report/lib/builder/traffic.js.html +90 -63
  10. package/coverage/lcov-report/lib/list/index.html +116 -0
  11. package/coverage/lcov-report/lib/{tester → list}/matrix.js.html +90 -66
  12. package/coverage/lcov-report/lib/tester/helpers.js.html +295 -0
  13. package/coverage/lcov-report/lib/tester/index.html +20 -35
  14. package/coverage/lcov-report/src/builder/allocator.ts.html +2 -2
  15. package/coverage/lcov-report/src/builder/index.html +15 -15
  16. package/coverage/lcov-report/src/builder/revision.ts.html +1 -1
  17. package/coverage/lcov-report/src/builder/traffic.ts.html +101 -23
  18. package/coverage/lcov-report/src/list/index.html +116 -0
  19. package/coverage/lcov-report/src/{tester → list}/matrix.ts.html +87 -21
  20. package/coverage/lcov-report/src/tester/helpers.ts.html +313 -0
  21. package/coverage/lcov-report/src/tester/index.html +20 -35
  22. package/coverage/lcov.info +592 -436
  23. package/lib/assess-distribution/index.d.ts +1 -1
  24. package/lib/assess-distribution/index.js +102 -162
  25. package/lib/assess-distribution/index.js.map +1 -1
  26. package/lib/benchmark/index.js +87 -143
  27. package/lib/benchmark/index.js.map +1 -1
  28. package/lib/builder/allocator.d.ts +1 -1
  29. package/lib/builder/allocator.js +12 -12
  30. package/lib/builder/allocator.js.map +1 -1
  31. package/lib/builder/allocator.spec.js +22 -22
  32. package/lib/builder/allocator.spec.js.map +1 -1
  33. package/lib/builder/buildDatafile.d.ts +4 -3
  34. package/lib/builder/buildDatafile.js +311 -388
  35. package/lib/builder/buildDatafile.js.map +1 -1
  36. package/lib/builder/buildProject.d.ts +2 -1
  37. package/lib/builder/buildProject.js +96 -183
  38. package/lib/builder/buildProject.js.map +1 -1
  39. package/lib/builder/convertToV1.d.ts +10 -0
  40. package/lib/builder/convertToV1.js +119 -0
  41. package/lib/builder/convertToV1.js.map +1 -0
  42. package/lib/builder/getFeatureRanges.d.ts +1 -1
  43. package/lib/builder/getFeatureRanges.js +32 -105
  44. package/lib/builder/getFeatureRanges.js.map +1 -1
  45. package/lib/builder/hashes.d.ts +4 -0
  46. package/lib/builder/hashes.js +70 -0
  47. package/lib/builder/hashes.js.map +1 -0
  48. package/lib/builder/revision.js +2 -2
  49. package/lib/builder/revision.js.map +1 -1
  50. package/lib/builder/revision.spec.js +1 -1
  51. package/lib/builder/revision.spec.js.map +1 -1
  52. package/lib/builder/traffic.d.ts +1 -1
  53. package/lib/builder/traffic.js +57 -48
  54. package/lib/builder/traffic.js.map +1 -1
  55. package/lib/builder/traffic.spec.js +14 -14
  56. package/lib/builder/traffic.spec.js.map +1 -1
  57. package/lib/cli/cli.js +60 -129
  58. package/lib/cli/cli.js.map +1 -1
  59. package/lib/cli/plugins.js +14 -16
  60. package/lib/cli/plugins.js.map +1 -1
  61. package/lib/config/parsers.js +1 -1
  62. package/lib/config/parsers.js.map +1 -1
  63. package/lib/config/projectConfig.d.ts +8 -6
  64. package/lib/config/projectConfig.js +31 -72
  65. package/lib/config/projectConfig.js.map +1 -1
  66. package/lib/datasource/adapter.d.ts +1 -1
  67. package/lib/datasource/adapter.js +2 -5
  68. package/lib/datasource/adapter.js.map +1 -1
  69. package/lib/datasource/datasource.d.ts +2 -1
  70. package/lib/datasource/datasource.js +107 -148
  71. package/lib/datasource/datasource.js.map +1 -1
  72. package/lib/datasource/filesystemAdapter.d.ts +1 -1
  73. package/lib/datasource/filesystemAdapter.js +224 -360
  74. package/lib/datasource/filesystemAdapter.js.map +1 -1
  75. package/lib/evaluate/index.d.ts +1 -1
  76. package/lib/evaluate/index.js +120 -188
  77. package/lib/evaluate/index.js.map +1 -1
  78. package/lib/find-duplicate-segments/findDuplicateSegments.d.ts +1 -1
  79. package/lib/find-duplicate-segments/findDuplicateSegments.js +40 -128
  80. package/lib/find-duplicate-segments/findDuplicateSegments.js.map +1 -1
  81. package/lib/find-duplicate-segments/index.js +27 -82
  82. package/lib/find-duplicate-segments/index.js.map +1 -1
  83. package/lib/find-usage/index.d.ts +7 -5
  84. package/lib/find-usage/index.js +333 -507
  85. package/lib/find-usage/index.js.map +1 -1
  86. package/lib/generate-code/index.js +36 -91
  87. package/lib/generate-code/index.js.map +1 -1
  88. package/lib/generate-code/typescript.js +117 -157
  89. package/lib/generate-code/typescript.js.map +1 -1
  90. package/lib/index.d.ts +0 -1
  91. package/lib/index.js +0 -1
  92. package/lib/index.js.map +1 -1
  93. package/lib/info/index.js +45 -133
  94. package/lib/info/index.js.map +1 -1
  95. package/lib/init/index.d.ts +1 -1
  96. package/lib/init/index.js +16 -64
  97. package/lib/init/index.js.map +1 -1
  98. package/lib/linter/attributeSchema.d.ts +21 -6
  99. package/lib/linter/attributeSchema.js +18 -4
  100. package/lib/linter/attributeSchema.js.map +1 -1
  101. package/lib/linter/checkCircularDependency.d.ts +1 -1
  102. package/lib/linter/checkCircularDependency.js +22 -80
  103. package/lib/linter/checkCircularDependency.js.map +1 -1
  104. package/lib/linter/checkPercentageExceedingSlot.d.ts +1 -1
  105. package/lib/linter/checkPercentageExceedingSlot.js +36 -76
  106. package/lib/linter/checkPercentageExceedingSlot.js.map +1 -1
  107. package/lib/linter/conditionSchema.d.ts +1 -1
  108. package/lib/linter/conditionSchema.js +89 -41
  109. package/lib/linter/conditionSchema.js.map +1 -1
  110. package/lib/linter/featureSchema.d.ts +345 -197
  111. package/lib/linter/featureSchema.js +313 -172
  112. package/lib/linter/featureSchema.js.map +1 -1
  113. package/lib/linter/groupSchema.js +6 -6
  114. package/lib/linter/groupSchema.js.map +1 -1
  115. package/lib/linter/lintProject.js +306 -480
  116. package/lib/linter/lintProject.js.map +1 -1
  117. package/lib/linter/printError.js +7 -7
  118. package/lib/linter/printError.js.map +1 -1
  119. package/lib/linter/segmentSchema.js +2 -2
  120. package/lib/linter/segmentSchema.js.map +1 -1
  121. package/lib/linter/testSchema.d.ts +155 -3
  122. package/lib/linter/testSchema.js +47 -17
  123. package/lib/linter/testSchema.js.map +1 -1
  124. package/lib/list/index.d.ts +1 -0
  125. package/lib/list/index.js +349 -517
  126. package/lib/list/index.js.map +1 -1
  127. package/lib/{tester → list}/matrix.d.ts +1 -1
  128. package/lib/{tester → list}/matrix.js +50 -42
  129. package/lib/list/matrix.js.map +1 -0
  130. package/lib/{tester → list}/matrix.spec.js +7 -7
  131. package/lib/list/matrix.spec.js.map +1 -0
  132. package/lib/site/exportSite.js +25 -71
  133. package/lib/site/exportSite.js.map +1 -1
  134. package/lib/site/generateHistory.d.ts +1 -1
  135. package/lib/site/generateHistory.js +26 -82
  136. package/lib/site/generateHistory.js.map +1 -1
  137. package/lib/site/generateSiteSearchIndex.d.ts +1 -1
  138. package/lib/site/generateSiteSearchIndex.js +182 -259
  139. package/lib/site/generateSiteSearchIndex.js.map +1 -1
  140. package/lib/site/getLastModifiedFromHistory.d.ts +1 -1
  141. package/lib/site/getLastModifiedFromHistory.js +2 -2
  142. package/lib/site/getLastModifiedFromHistory.js.map +1 -1
  143. package/lib/site/getOwnerAndRepoFromUrl.js +6 -6
  144. package/lib/site/getOwnerAndRepoFromUrl.js.map +1 -1
  145. package/lib/site/getRelativePaths.js +7 -7
  146. package/lib/site/getRelativePaths.js.map +1 -1
  147. package/lib/site/getRepoDetails.js +20 -20
  148. package/lib/site/getRepoDetails.js.map +1 -1
  149. package/lib/site/index.js +25 -73
  150. package/lib/site/index.js.map +1 -1
  151. package/lib/site/serveSite.js +10 -10
  152. package/lib/site/serveSite.js.map +1 -1
  153. package/lib/tester/helpers.d.ts +2 -0
  154. package/lib/tester/helpers.js +71 -0
  155. package/lib/tester/helpers.js.map +1 -0
  156. package/lib/tester/helpers.spec.js +115 -0
  157. package/lib/tester/helpers.spec.js.map +1 -0
  158. package/lib/tester/index.d.ts +0 -1
  159. package/lib/tester/index.js +0 -1
  160. package/lib/tester/index.js.map +1 -1
  161. package/lib/tester/prettyDuration.js +11 -11
  162. package/lib/tester/prettyDuration.js.map +1 -1
  163. package/lib/tester/printTestResult.d.ts +1 -1
  164. package/lib/tester/printTestResult.js +35 -15
  165. package/lib/tester/printTestResult.js.map +1 -1
  166. package/lib/tester/testFeature.d.ts +4 -2
  167. package/lib/tester/testFeature.js +264 -226
  168. package/lib/tester/testFeature.js.map +1 -1
  169. package/lib/tester/testProject.d.ts +3 -7
  170. package/lib/tester/testProject.js +145 -246
  171. package/lib/tester/testProject.js.map +1 -1
  172. package/lib/tester/testSegment.d.ts +5 -2
  173. package/lib/tester/testSegment.js +65 -102
  174. package/lib/tester/testSegment.js.map +1 -1
  175. package/lib/utils/extractKeys.d.ts +2 -1
  176. package/lib/utils/extractKeys.js +57 -12
  177. package/lib/utils/extractKeys.js.map +1 -1
  178. package/lib/utils/git.d.ts +1 -1
  179. package/lib/utils/git.js +23 -23
  180. package/lib/utils/git.js.map +1 -1
  181. package/lib/utils/pretty.js +2 -4
  182. package/lib/utils/pretty.js.map +1 -1
  183. package/package.json +5 -6
  184. package/src/assess-distribution/index.ts +3 -2
  185. package/src/benchmark/index.ts +3 -3
  186. package/src/builder/allocator.spec.ts +1 -1
  187. package/src/builder/allocator.ts +1 -1
  188. package/src/builder/buildDatafile.ts +161 -124
  189. package/src/builder/buildProject.ts +6 -3
  190. package/src/builder/convertToV1.ts +166 -0
  191. package/src/builder/getFeatureRanges.ts +1 -1
  192. package/src/builder/hashes.ts +109 -0
  193. package/src/builder/traffic.ts +41 -15
  194. package/src/cli/cli.ts +1 -1
  195. package/src/cli/plugins.ts +0 -2
  196. package/src/config/projectConfig.ts +13 -10
  197. package/src/datasource/adapter.ts +1 -1
  198. package/src/datasource/datasource.ts +23 -2
  199. package/src/datasource/filesystemAdapter.ts +11 -12
  200. package/src/evaluate/index.ts +7 -6
  201. package/src/find-duplicate-segments/findDuplicateSegments.ts +1 -1
  202. package/src/find-usage/index.ts +111 -44
  203. package/src/generate-code/index.ts +1 -3
  204. package/src/generate-code/typescript.ts +7 -29
  205. package/src/index.ts +0 -1
  206. package/src/info/index.ts +2 -2
  207. package/src/init/index.ts +2 -2
  208. package/src/linter/attributeSchema.ts +18 -2
  209. package/src/linter/checkCircularDependency.ts +1 -1
  210. package/src/linter/checkPercentageExceedingSlot.ts +28 -8
  211. package/src/linter/conditionSchema.ts +66 -10
  212. package/src/linter/featureSchema.ts +312 -116
  213. package/src/linter/lintProject.ts +9 -4
  214. package/src/linter/testSchema.ts +42 -3
  215. package/src/list/index.ts +18 -30
  216. package/src/{tester → list}/matrix.ts +33 -11
  217. package/src/site/exportSite.ts +2 -4
  218. package/src/site/generateHistory.ts +1 -1
  219. package/src/site/generateSiteSearchIndex.ts +58 -50
  220. package/src/site/getLastModifiedFromHistory.ts +1 -1
  221. package/src/tester/helpers.spec.ts +149 -0
  222. package/src/tester/helpers.ts +76 -0
  223. package/src/tester/index.ts +0 -1
  224. package/src/tester/printTestResult.ts +25 -3
  225. package/src/tester/testFeature.ts +270 -124
  226. package/src/tester/testProject.ts +28 -49
  227. package/src/tester/testSegment.ts +48 -40
  228. package/src/utils/extractKeys.ts +58 -1
  229. package/src/utils/git.ts +1 -1
  230. package/tsconfig.cjs.json +1 -0
  231. package/coverage/lcov-report/lib/tester/checkIfObjectsAreEqual.js.html +0 -151
  232. package/coverage/lcov-report/src/tester/checkIfObjectsAreEqual.ts.html +0 -157
  233. package/lib/restore/index.d.ts +0 -4
  234. package/lib/restore/index.js +0 -91
  235. package/lib/restore/index.js.map +0 -1
  236. package/lib/tester/checkIfArraysAreEqual.d.ts +0 -1
  237. package/lib/tester/checkIfArraysAreEqual.js +0 -18
  238. package/lib/tester/checkIfArraysAreEqual.js.map +0 -1
  239. package/lib/tester/checkIfObjectsAreEqual.d.ts +0 -1
  240. package/lib/tester/checkIfObjectsAreEqual.js +0 -23
  241. package/lib/tester/checkIfObjectsAreEqual.js.map +0 -1
  242. package/lib/tester/checkIfObjectsAreEqual.spec.js +0 -26
  243. package/lib/tester/checkIfObjectsAreEqual.spec.js.map +0 -1
  244. package/lib/tester/matrix.js.map +0 -1
  245. package/lib/tester/matrix.spec.js.map +0 -1
  246. package/src/restore/index.ts +0 -42
  247. package/src/tester/checkIfArraysAreEqual.ts +0 -16
  248. package/src/tester/checkIfObjectsAreEqual.spec.ts +0 -31
  249. package/src/tester/checkIfObjectsAreEqual.ts +0 -24
  250. /package/lib/{tester → list}/matrix.spec.d.ts +0 -0
  251. /package/lib/tester/{checkIfObjectsAreEqual.spec.d.ts → helpers.spec.d.ts} +0 -0
  252. /package/src/{tester → list}/matrix.spec.ts +0 -0
@@ -1,407 +1,330 @@
1
1
  "use strict";
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
- return new (P || (P = Promise))(function (resolve, reject) {
16
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
- step((generator = generator.apply(thisArg, _arguments || [])).next());
20
- });
21
- };
22
- var __generator = (this && this.__generator) || function (thisArg, body) {
23
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
- function verb(n) { return function (v) { return step([n, v]); }; }
26
- function step(op) {
27
- if (f) throw new TypeError("Generator is already executing.");
28
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
- if (y = 0, t) op = [op[0] & 2, t.value];
31
- switch (op[0]) {
32
- case 0: case 1: t = op; break;
33
- case 4: _.label++; return { value: op[1], done: false };
34
- case 5: _.label++; y = op[1]; op = [0]; continue;
35
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
- default:
37
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
- if (t[2]) _.ops.pop();
42
- _.trys.pop(); continue;
43
- }
44
- op = body.call(thisArg, _);
45
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
- }
48
- };
49
2
  Object.defineProperty(exports, "__esModule", { value: true });
50
3
  exports.getCustomDatafile = getCustomDatafile;
51
4
  exports.buildDatafile = buildDatafile;
52
- var fs = require("fs");
53
- var config_1 = require("../config");
54
- var utils_1 = require("../utils");
55
- var traffic_1 = require("./traffic");
56
- var getFeatureRanges_1 = require("./getFeatureRanges");
57
- function getCustomDatafile(options) {
58
- return __awaiter(this, void 0, void 0, function () {
59
- var featuresToInclude, requiredChain, existingState, datafileContent;
60
- return __generator(this, function (_a) {
61
- switch (_a.label) {
62
- case 0:
63
- if (!options.featureKey) return [3 /*break*/, 2];
64
- return [4 /*yield*/, options.datasource.getRequiredFeaturesChain(options.featureKey)];
65
- case 1:
66
- requiredChain = _a.sent();
67
- featuresToInclude = Array.from(requiredChain);
68
- _a.label = 2;
69
- case 2: return [4 /*yield*/, options.datasource.readState(options.environment)];
70
- case 3:
71
- existingState = _a.sent();
72
- return [4 /*yield*/, buildDatafile(options.projectConfig, options.datasource, {
73
- schemaVersion: options.schemaVersion || config_1.SCHEMA_VERSION,
74
- revision: options.revision || "tester",
75
- environment: options.environment,
76
- features: featuresToInclude,
77
- inflate: options.inflate,
78
- }, existingState)];
79
- case 4:
80
- datafileContent = _a.sent();
81
- return [2 /*return*/, datafileContent];
82
- }
83
- });
84
- });
5
+ const fs = require("fs");
6
+ const config_1 = require("../config");
7
+ const utils_1 = require("../utils");
8
+ const hashes_1 = require("./hashes");
9
+ const traffic_1 = require("./traffic");
10
+ const getFeatureRanges_1 = require("./getFeatureRanges");
11
+ const convertToV1_1 = require("./convertToV1");
12
+ async function getCustomDatafile(options) {
13
+ let featuresToInclude;
14
+ if (options.featureKey) {
15
+ const requiredChain = await options.datasource.getRequiredFeaturesChain(options.featureKey);
16
+ featuresToInclude = Array.from(requiredChain);
17
+ }
18
+ const existingState = await options.datasource.readState(options.environment);
19
+ const datafileContent = await buildDatafile(options.projectConfig, options.datasource, {
20
+ schemaVersion: options.schemaVersion || config_1.SCHEMA_VERSION,
21
+ revision: options.revision || "tester",
22
+ environment: options.environment,
23
+ features: featuresToInclude,
24
+ inflate: options.inflate,
25
+ }, existingState);
26
+ return datafileContent;
85
27
  }
86
- function buildDatafile(projectConfig, datasource, options, existingState) {
87
- return __awaiter(this, void 0, void 0, function () {
88
- var datafileContent, segmentKeysUsedByTag, attributeKeysUsedByTag, _a, featureRanges, featureIsInGroup, features, featuresDirectory, featureFiles, _i, featureFiles_1, featureKey, parsedFeature, expose, rules, force, exposeTags, _b, rules_1, parsedRule, extractedSegmentKeys, feature, segments, segmentsDirectory, segmentFiles, _c, segmentFiles_1, segmentKey, parsedSegment, extractedAttributeKeys, segment, attributes, attributesDirectory, attributeFiles, _d, attributeFiles_1, attributeKey, parsedAttribute, attribute, allFeatureKeys, allSegmentKeys, allAttributeKeys, i, _loop_1, _e, allFeatureKeys_1, featureKey, _loop_2, _f, allSegmentKeys_1, segmentKey, _loop_3, _g, allAttributeKeys_1, attributeKey, datafileContentV2;
89
- var _h;
90
- return __generator(this, function (_j) {
91
- switch (_j.label) {
92
- case 0:
93
- datafileContent = {
94
- schemaVersion: options.schemaVersion,
95
- revision: options.revision,
96
- attributes: [],
97
- segments: [],
98
- features: [],
99
- };
100
- segmentKeysUsedByTag = new Set();
101
- attributeKeysUsedByTag = new Set();
102
- return [4 /*yield*/, (0, getFeatureRanges_1.getFeatureRanges)(projectConfig, datasource)];
103
- case 1:
104
- _a = _j.sent(), featureRanges = _a.featureRanges, featureIsInGroup = _a.featureIsInGroup;
105
- features = [];
106
- featuresDirectory = projectConfig.featuresDirectoryPath;
107
- if (!fs.existsSync(featuresDirectory)) return [3 /*break*/, 6];
108
- return [4 /*yield*/, datasource.listFeatures()];
109
- case 2:
110
- featureFiles = _j.sent();
111
- _i = 0, featureFiles_1 = featureFiles;
112
- _j.label = 3;
113
- case 3:
114
- if (!(_i < featureFiles_1.length)) return [3 /*break*/, 6];
115
- featureKey = featureFiles_1[_i];
116
- return [4 /*yield*/, datasource.readFeature(featureKey)];
117
- case 4:
118
- parsedFeature = _j.sent();
119
- if (parsedFeature.archived === true) {
120
- return [3 /*break*/, 5];
121
- }
122
- if (options.tag && parsedFeature.tags.indexOf(options.tag) === -1) {
123
- return [3 /*break*/, 5];
124
- }
125
- if (options.features && options.features.indexOf(featureKey) === -1) {
126
- return [3 /*break*/, 5];
127
- }
128
- expose = void 0;
129
- rules = void 0;
130
- force = void 0;
131
- if (options.environment && parsedFeature.environments) {
132
- expose = parsedFeature.environments[options.environment].expose;
133
- rules = parsedFeature.environments[options.environment].rules;
134
- force = parsedFeature.environments[options.environment].force;
135
- }
136
- else {
137
- expose = parsedFeature.expose;
138
- rules = parsedFeature.rules;
139
- force = parsedFeature.force;
140
- }
141
- if (expose === false) {
142
- return [3 /*break*/, 5];
143
- }
144
- if (Array.isArray(expose)) {
145
- exposeTags = expose;
146
- if (options.tag && exposeTags.indexOf(options.tag) === -1) {
147
- return [3 /*break*/, 5];
148
- }
149
- }
150
- for (_b = 0, rules_1 = rules; _b < rules_1.length; _b++) {
151
- parsedRule = rules_1[_b];
152
- extractedSegmentKeys = (0, utils_1.extractSegmentKeysFromGroupSegments)(parsedRule.segments);
153
- extractedSegmentKeys.forEach(function (segmentKey) { return segmentKeysUsedByTag.add(segmentKey); });
154
- }
155
- feature = {
156
- key: featureKey,
157
- deprecated: parsedFeature.deprecated === true ? true : undefined,
158
- bucketBy: parsedFeature.bucketBy || projectConfig.defaultBucketBy,
159
- required: parsedFeature.required,
160
- variations: Array.isArray(parsedFeature.variations)
161
- ? parsedFeature.variations.map(function (variation) {
162
- var mappedVariation = {
163
- value: variation.value,
164
- weight: variation.weight, // @TODO: added so state files can maintain weight info, but datafiles don't need this. find a way to remove it from datafiles later
165
- };
166
- if (!variation.variables) {
167
- return mappedVariation;
168
- }
169
- mappedVariation.variables = variation.variables.map(function (variable) {
170
- var mappedVariable = {
171
- key: variable.key,
172
- value: variable.value,
173
- };
174
- if (!variable.overrides) {
175
- return mappedVariable;
28
+ async function buildDatafile(projectConfig, datasource, options, existingState) {
29
+ const segmentKeysUsedByTag = new Set();
30
+ const attributeKeysUsedByTag = new Set();
31
+ const { featureRanges, featureIsInGroup } = await (0, getFeatureRanges_1.getFeatureRanges)(projectConfig, datasource);
32
+ // features
33
+ const features = [];
34
+ const featuresDirectory = projectConfig.featuresDirectoryPath;
35
+ if (fs.existsSync(featuresDirectory)) {
36
+ const featureFiles = await datasource.listFeatures();
37
+ for (const featureKey of featureFiles) {
38
+ const parsedFeature = await datasource.readFeature(featureKey);
39
+ if (parsedFeature.archived === true) {
40
+ continue;
41
+ }
42
+ if (options.tag && parsedFeature.tags.indexOf(options.tag) === -1) {
43
+ continue;
44
+ }
45
+ if (options.features && options.features.indexOf(featureKey) === -1) {
46
+ continue;
47
+ }
48
+ let expose;
49
+ let rules;
50
+ let force;
51
+ if (options.environment) {
52
+ expose = parsedFeature.expose?.[options.environment];
53
+ rules = parsedFeature.rules?.[options.environment];
54
+ force = parsedFeature.force?.[options.environment];
55
+ }
56
+ else {
57
+ expose = parsedFeature.expose;
58
+ rules = parsedFeature.rules;
59
+ force = parsedFeature.force;
60
+ }
61
+ if (expose === false) {
62
+ continue;
63
+ }
64
+ if (Array.isArray(expose)) {
65
+ const exposeTags = expose;
66
+ if (options.tag && exposeTags.indexOf(options.tag) === -1) {
67
+ continue;
68
+ }
69
+ }
70
+ for (const parsedRule of rules) {
71
+ const extractedSegmentKeys = (0, utils_1.extractSegmentKeysFromGroupSegments)(parsedRule.segments);
72
+ extractedSegmentKeys.forEach((segmentKey) => segmentKeysUsedByTag.add(segmentKey));
73
+ }
74
+ const feature = {
75
+ key: featureKey,
76
+ deprecated: parsedFeature.deprecated === true ? true : undefined,
77
+ bucketBy: parsedFeature.bucketBy || projectConfig.defaultBucketBy,
78
+ required: parsedFeature.required,
79
+ disabledVariationValue: parsedFeature.disabledVariationValue,
80
+ variations: Array.isArray(parsedFeature.variations)
81
+ ? parsedFeature.variations.map((variation) => {
82
+ const mappedVariation = {
83
+ value: variation.value,
84
+ weight: variation.weight, // @NOTE: added so state files can maintain weight info, but datafiles don't need this. find a way to remove it from datafiles later
85
+ variables: variation.variables,
86
+ variableOverrides: variation.variableOverrides,
87
+ };
88
+ if (variation.variableOverrides) {
89
+ const variableOverrides = variation.variableOverrides;
90
+ const variableKeys = Object.keys(variableOverrides);
91
+ for (const variableKey of variableKeys) {
92
+ mappedVariation.variableOverrides[variableKey] = variableOverrides[variableKey].map((override) => {
93
+ if (typeof override.conditions !== "undefined") {
94
+ const extractedAttributeKeys = (0, utils_1.extractAttributeKeysFromConditions)(override.conditions);
95
+ extractedAttributeKeys.forEach((attributeKey) => attributeKeysUsedByTag.add(attributeKey));
96
+ return {
97
+ conditions: projectConfig.stringify && typeof override.conditions !== "string"
98
+ ? JSON.stringify(override.conditions)
99
+ : override.conditions,
100
+ value: override.value,
101
+ };
102
+ }
103
+ if (typeof override.segments !== "undefined") {
104
+ const extractedSegmentKeys = (0, utils_1.extractSegmentKeysFromGroupSegments)(override.segments);
105
+ extractedSegmentKeys.forEach((segmentKey) => segmentKeysUsedByTag.add(segmentKey));
106
+ return {
107
+ segments: projectConfig.stringify && typeof override.segments !== "string"
108
+ ? JSON.stringify(override.segments)
109
+ : override.segments,
110
+ value: override.value,
111
+ };
176
112
  }
177
- mappedVariable.overrides = variable.overrides.map(function (override) {
178
- if (typeof override.conditions !== "undefined") {
179
- var extractedAttributeKeys = (0, utils_1.extractAttributeKeysFromConditions)(override.conditions);
180
- extractedAttributeKeys.forEach(function (attributeKey) {
181
- return attributeKeysUsedByTag.add(attributeKey);
182
- });
183
- return {
184
- conditions: projectConfig.stringify
185
- ? JSON.stringify(override.conditions)
186
- : override.conditions,
187
- value: override.value,
188
- };
189
- }
190
- if (typeof override.segments !== "undefined") {
191
- var extractedSegmentKeys = (0, utils_1.extractSegmentKeysFromGroupSegments)(override.segments);
192
- extractedSegmentKeys.forEach(function (segmentKey) {
193
- return segmentKeysUsedByTag.add(segmentKey);
194
- });
195
- return {
196
- segments: typeof override.segments !== "string" && projectConfig.stringify
197
- ? JSON.stringify(override.segments)
198
- : override.segments,
199
- value: override.value,
200
- };
201
- }
202
- return override;
203
- });
204
- return mappedVariable;
113
+ return override;
205
114
  });
206
- return mappedVariation;
207
- })
208
- : undefined,
209
- traffic: (0, traffic_1.getTraffic)(parsedFeature.variations, rules, existingState.features[featureKey], featureRanges.get(featureKey) || []).map(function (t) {
210
- return __assign(__assign({}, t), { segments: typeof t.segments !== "string" && projectConfig.stringify
211
- ? JSON.stringify(t.segments)
212
- : t.segments });
213
- }),
214
- ranges: featureRanges.get(featureKey) || undefined,
115
+ }
116
+ }
117
+ return mappedVariation;
118
+ })
119
+ : undefined,
120
+ traffic: (0, traffic_1.getTraffic)(parsedFeature.variations, rules, existingState.features[featureKey], featureRanges.get(featureKey) || []).map((t) => {
121
+ return {
122
+ ...t,
123
+ segments: typeof t.segments !== "string" && projectConfig.stringify
124
+ ? JSON.stringify(t.segments)
125
+ : t.segments,
215
126
  };
216
- // update state in memory, so that next datafile build can use it (in case it contains the same feature)
217
- existingState.features[featureKey] = {
218
- variations: Array.isArray(feature.variations)
219
- ? feature.variations.map(function (v) {
127
+ }),
128
+ ranges: featureRanges.get(featureKey) || undefined,
129
+ };
130
+ // update state in memory, so that next datafile build can use it (in case it contains the same feature)
131
+ existingState.features[featureKey] = {
132
+ variations: Array.isArray(feature.variations)
133
+ ? feature.variations.map((v) => {
134
+ return {
135
+ value: v.value,
136
+ weight: v.weight || 0,
137
+ };
138
+ })
139
+ : undefined,
140
+ traffic: feature.traffic.map((t) => {
141
+ return {
142
+ key: t.key,
143
+ percentage: t.percentage,
144
+ allocation: t.allocation &&
145
+ t.allocation.map((a) => {
220
146
  return {
221
- value: v.value,
222
- weight: v.weight || 0,
147
+ variation: a.variation,
148
+ range: a.range,
223
149
  };
224
- })
225
- : undefined,
226
- traffic: feature.traffic.map(function (t) {
227
- return {
228
- key: t.key,
229
- percentage: t.percentage,
230
- allocation: t.allocation.map(function (a) {
231
- return {
232
- variation: a.variation,
233
- range: a.range,
234
- };
235
- }),
236
- };
237
- }),
238
- };
239
- if (featureIsInGroup[featureKey] === true) {
240
- feature.ranges = featureRanges.get(feature.key);
241
- }
242
- if (parsedFeature.variablesSchema) {
243
- feature.variablesSchema = parsedFeature.variablesSchema.map(function (v) {
244
- return {
245
- key: v.key,
246
- type: v.type,
247
- defaultValue: v.defaultValue,
248
- deprecated: v.deprecated === true ? true : undefined,
249
- };
250
- });
251
- }
252
- if (force) {
253
- feature.force = force;
254
- (_h = feature.force) === null || _h === void 0 ? void 0 : _h.forEach(function (f) {
255
- if (f.segments) {
256
- var extractedSegmentKeys = (0, utils_1.extractSegmentKeysFromGroupSegments)(f.segments);
257
- extractedSegmentKeys.forEach(function (segmentKey) { return segmentKeysUsedByTag.add(segmentKey); });
258
- }
259
- });
260
- }
261
- features.push(feature);
262
- _j.label = 5;
263
- case 5:
264
- _i++;
265
- return [3 /*break*/, 3];
266
- case 6:
267
- segments = [];
268
- segmentsDirectory = projectConfig.segmentsDirectoryPath;
269
- if (!fs.existsSync(segmentsDirectory)) return [3 /*break*/, 11];
270
- return [4 /*yield*/, datasource.listSegments()];
271
- case 7:
272
- segmentFiles = _j.sent();
273
- _c = 0, segmentFiles_1 = segmentFiles;
274
- _j.label = 8;
275
- case 8:
276
- if (!(_c < segmentFiles_1.length)) return [3 /*break*/, 11];
277
- segmentKey = segmentFiles_1[_c];
278
- return [4 /*yield*/, datasource.readSegment(segmentKey)];
279
- case 9:
280
- parsedSegment = _j.sent();
281
- if (parsedSegment.archived === true) {
282
- return [3 /*break*/, 10];
283
- }
284
- if (segmentKeysUsedByTag.has(segmentKey) === false) {
285
- return [3 /*break*/, 10];
286
- }
287
- extractedAttributeKeys = (0, utils_1.extractAttributeKeysFromConditions)(parsedSegment.conditions);
288
- extractedAttributeKeys.forEach(function (attributeKey) { return attributeKeysUsedByTag.add(attributeKey); });
289
- segment = {
290
- key: segmentKey,
291
- conditions: typeof parsedSegment.conditions !== "string" && projectConfig.stringify === true
292
- ? JSON.stringify(parsedSegment.conditions)
293
- : parsedSegment.conditions,
150
+ }),
294
151
  };
295
- segments.push(segment);
296
- _j.label = 10;
297
- case 10:
298
- _c++;
299
- return [3 /*break*/, 8];
300
- case 11:
301
- attributes = [];
302
- attributesDirectory = projectConfig.attributesDirectoryPath;
303
- if (!fs.existsSync(attributesDirectory)) return [3 /*break*/, 16];
304
- return [4 /*yield*/, datasource.listAttributes()];
305
- case 12:
306
- attributeFiles = _j.sent();
307
- _d = 0, attributeFiles_1 = attributeFiles;
308
- _j.label = 13;
309
- case 13:
310
- if (!(_d < attributeFiles_1.length)) return [3 /*break*/, 16];
311
- attributeKey = attributeFiles_1[_d];
312
- return [4 /*yield*/, datasource.readAttribute(attributeKey)];
313
- case 14:
314
- parsedAttribute = _j.sent();
315
- if (parsedAttribute.archived === true) {
316
- return [3 /*break*/, 15];
317
- }
318
- if (attributeKeysUsedByTag.has(attributeKey) === false && !parsedAttribute.capture) {
319
- return [3 /*break*/, 15];
320
- }
321
- attribute = {
322
- key: attributeKey,
323
- type: parsedAttribute.type,
152
+ }),
153
+ };
154
+ if (featureIsInGroup[featureKey] === true) {
155
+ feature.ranges = featureRanges.get(featureKey);
156
+ }
157
+ if (parsedFeature.variablesSchema) {
158
+ const variableKeys = Object.keys(parsedFeature.variablesSchema);
159
+ feature.variablesSchema = {};
160
+ for (const variableKey of variableKeys) {
161
+ const v = parsedFeature.variablesSchema[variableKey];
162
+ feature.variablesSchema[variableKey] = {
163
+ key: variableKey,
164
+ type: v.type,
165
+ defaultValue: v.defaultValue,
166
+ deprecated: v.deprecated === true ? true : undefined,
167
+ useDefaultWhenDisabled: v.useDefaultWhenDisabled === true ? true : undefined,
168
+ disabledValue: typeof v.disabledValue !== "undefined" ? v.disabledValue : undefined,
324
169
  };
325
- if (parsedAttribute.capture === true) {
326
- attribute.capture = true;
327
- }
328
- attributes.push(attribute);
329
- _j.label = 15;
330
- case 15:
331
- _d++;
332
- return [3 /*break*/, 13];
333
- case 16:
334
- // inflate
335
- if (options.inflate) {
336
- allFeatureKeys = features.map(function (f) { return f.key; });
337
- allSegmentKeys = segments.map(function (s) { return s.key; });
338
- allAttributeKeys = attributes.map(function (a) { return a.key; });
339
- for (i = 0; i < options.inflate; i++) {
340
- _loop_1 = function (featureKey) {
341
- var originalFeature = features.find(function (f) { return f.key === featureKey; });
342
- features.unshift(__assign(__assign({}, originalFeature), { key: "".concat(originalFeature.key, "-").concat(i) }));
343
- };
344
- // feature
345
- for (_e = 0, allFeatureKeys_1 = allFeatureKeys; _e < allFeatureKeys_1.length; _e++) {
346
- featureKey = allFeatureKeys_1[_e];
347
- _loop_1(featureKey);
348
- }
349
- _loop_2 = function (segmentKey) {
350
- var originalSegment = segments.find(function (s) { return s.key === segmentKey; });
351
- segments.unshift(__assign(__assign({}, originalSegment), { key: "".concat(originalSegment.key, "-").concat(i) }));
352
- };
353
- // segment
354
- for (_f = 0, allSegmentKeys_1 = allSegmentKeys; _f < allSegmentKeys_1.length; _f++) {
355
- segmentKey = allSegmentKeys_1[_f];
356
- _loop_2(segmentKey);
357
- }
358
- _loop_3 = function (attributeKey) {
359
- var originalAttribute = attributes.find(function (a) { return a.key === attributeKey; });
360
- attributes.unshift(__assign(__assign({}, originalAttribute), { key: "".concat(originalAttribute.key, "-").concat(i) }));
361
- };
362
- // attribute
363
- for (_g = 0, allAttributeKeys_1 = allAttributeKeys; _g < allAttributeKeys_1.length; _g++) {
364
- attributeKey = allAttributeKeys_1[_g];
365
- _loop_3(attributeKey);
366
- }
367
- }
170
+ }
171
+ }
172
+ if (force) {
173
+ feature.force = force.map((f) => {
174
+ if (f.segments) {
175
+ const extractedSegmentKeys = (0, utils_1.extractSegmentKeysFromGroupSegments)(f.segments);
176
+ extractedSegmentKeys.forEach((segmentKey) => segmentKeysUsedByTag.add(segmentKey));
177
+ f.segments =
178
+ typeof f.segments !== "string" && projectConfig.stringify
179
+ ? JSON.stringify(f.segments)
180
+ : f.segments;
368
181
  }
369
- // schema v2
370
- if (options.schemaVersion === "2") {
371
- datafileContentV2 = {
372
- schemaVersion: "2",
373
- revision: options.revision,
374
- attributes: {},
375
- segments: {},
376
- features: {},
377
- };
378
- datafileContentV2.attributes = attributes.reduce(function (acc, attribute) {
379
- acc[attribute.key] = attribute;
380
- return acc;
381
- }, {});
382
- datafileContentV2.segments = segments.reduce(function (acc, segment) {
383
- acc[segment.key] = segment;
384
- return acc;
385
- }, {});
386
- datafileContentV2.features = features.reduce(function (acc, feature) {
387
- if (Array.isArray(feature.variablesSchema)) {
388
- feature.variablesSchema = feature.variablesSchema.reduce(function (vAcc, variableSchema) {
389
- vAcc[variableSchema.key] = variableSchema;
390
- return vAcc;
391
- }, {});
392
- }
393
- acc[feature.key] = feature;
394
- return acc;
395
- }, {});
396
- return [2 /*return*/, datafileContentV2];
182
+ if (f.conditions) {
183
+ f.conditions =
184
+ typeof f.conditions !== "string" && projectConfig.stringify
185
+ ? JSON.stringify(f.conditions)
186
+ : f.conditions;
397
187
  }
398
- // default behaviour
399
- datafileContent.attributes = attributes;
400
- datafileContent.segments = segments;
401
- datafileContent.features = features;
402
- return [2 /*return*/, datafileContent];
188
+ return f;
189
+ });
403
190
  }
191
+ features.push(feature);
192
+ }
193
+ }
194
+ // segments
195
+ const segments = [];
196
+ const segmentsDirectory = projectConfig.segmentsDirectoryPath;
197
+ if (fs.existsSync(segmentsDirectory)) {
198
+ const segmentFiles = await datasource.listSegments();
199
+ for (const segmentKey of segmentFiles) {
200
+ const parsedSegment = await datasource.readSegment(segmentKey);
201
+ if (parsedSegment.archived === true) {
202
+ continue;
203
+ }
204
+ if (segmentKeysUsedByTag.has(segmentKey) === false) {
205
+ continue;
206
+ }
207
+ const extractedAttributeKeys = (0, utils_1.extractAttributeKeysFromConditions)(parsedSegment.conditions);
208
+ extractedAttributeKeys.forEach((attributeKey) => attributeKeysUsedByTag.add(attributeKey));
209
+ const segment = {
210
+ key: segmentKey,
211
+ conditions: typeof parsedSegment.conditions !== "string" && projectConfig.stringify === true
212
+ ? JSON.stringify(parsedSegment.conditions)
213
+ : parsedSegment.conditions,
214
+ };
215
+ segments.push(segment);
216
+ }
217
+ }
218
+ // attributes
219
+ const attributes = [];
220
+ const attributesDirectory = projectConfig.attributesDirectoryPath;
221
+ if (fs.existsSync(attributesDirectory)) {
222
+ const attributeFiles = await datasource.listAttributes();
223
+ for (const attributeKey of attributeFiles) {
224
+ const parsedAttribute = await datasource.readAttribute(attributeKey);
225
+ if (parsedAttribute.archived === true) {
226
+ continue;
227
+ }
228
+ if (attributeKeysUsedByTag.has(attributeKey) === false) {
229
+ continue;
230
+ }
231
+ const attribute = {
232
+ key: attributeKey,
233
+ type: parsedAttribute.type,
234
+ };
235
+ attributes.push(attribute);
236
+ }
237
+ }
238
+ // inflate
239
+ if (options.inflate && options.inflate >= 2) {
240
+ const allFeatureKeys = features.map((f) => f.key);
241
+ const allSegmentKeys = segments.map((s) => s.key);
242
+ const allAttributeKeys = attributes.map((a) => a.key);
243
+ for (let i = 0; i < options.inflate - 1; i++) {
244
+ // feature
245
+ for (const featureKey of allFeatureKeys) {
246
+ const originalFeature = features.find((f) => f.key === featureKey);
247
+ features.unshift({
248
+ ...originalFeature,
249
+ key: `${originalFeature.key}-${i}`,
250
+ });
251
+ }
252
+ // segment
253
+ for (const segmentKey of allSegmentKeys) {
254
+ const originalSegment = segments.find((s) => s.key === segmentKey);
255
+ segments.unshift({
256
+ ...originalSegment,
257
+ key: `${originalSegment.key}-${i}`,
258
+ });
259
+ }
260
+ // attribute
261
+ for (const attributeKey of allAttributeKeys) {
262
+ const originalAttribute = attributes.find((a) => a.key === attributeKey);
263
+ attributes.unshift({
264
+ ...originalAttribute,
265
+ key: `${originalAttribute.key}-${i}`,
266
+ });
267
+ }
268
+ }
269
+ }
270
+ // schema v1
271
+ if (options.schemaVersion === "1") {
272
+ return (0, convertToV1_1.convertToV1)({
273
+ revision: options.revision,
274
+ projectConfig,
275
+ attributes,
276
+ features,
277
+ segments,
404
278
  });
279
+ }
280
+ // schema v2
281
+ const datafileContentV2 = {
282
+ schemaVersion: "2",
283
+ revision: options.revision,
284
+ segments: {},
285
+ features: {},
286
+ };
287
+ datafileContentV2.segments = segments.reduce((acc, segment) => {
288
+ // key check needed for supporting v1 datafile generation
289
+ if (segment.key) {
290
+ acc[segment.key] = segment;
291
+ delete acc[segment.key].key; // remove key from segment, as it is not needed in v2 datafile
292
+ }
293
+ return acc;
294
+ }, {});
295
+ datafileContentV2.features = features.reduce((acc, feature) => {
296
+ if (!feature.key) {
297
+ return acc;
298
+ }
299
+ const featureKey = feature.key;
300
+ const featureV2 = feature;
301
+ // remove key, as it is not needed in v2 datafile
302
+ delete featureV2.key;
303
+ // remove variablesSchema[key].key
304
+ if (featureV2.variablesSchema) {
305
+ for (const [variableKey, variable] of Object.entries(featureV2.variablesSchema)) {
306
+ if (variable.key) {
307
+ delete featureV2.variablesSchema[variableKey].key;
308
+ }
309
+ }
310
+ }
311
+ acc[featureKey] = featureV2;
312
+ return acc;
313
+ }, {});
314
+ // add feature hashes for change detection
315
+ const segmentHashes = (0, hashes_1.getSegmentHashes)(datafileContentV2.segments);
316
+ Object.keys(datafileContentV2.features).forEach((featureKey) => {
317
+ const hash = (0, hashes_1.generateHashForFeature)(featureKey, datafileContentV2.features, segmentHashes);
318
+ datafileContentV2.features[featureKey].hash = hash;
319
+ // check needed to support --inflate option
320
+ if (existingState.features[featureKey]) {
321
+ existingState.features[featureKey].hash = hash;
322
+ }
405
323
  });
324
+ if (options.revisionFromHash) {
325
+ const datafileHash = (0, hashes_1.generateHashForDatafile)(datafileContentV2);
326
+ datafileContentV2.revision = `${datafileHash}`;
327
+ }
328
+ return datafileContentV2;
406
329
  }
407
330
  //# sourceMappingURL=buildDatafile.js.map