@featurevisor/core 2.26.1 → 3.0.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 (390) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/coverage/clover.xml +4991 -3130
  3. package/coverage/coverage-final.json +63 -39
  4. package/coverage/lcov-report/block-navigation.js +1 -1
  5. package/coverage/lcov-report/index.html +248 -98
  6. package/coverage/lcov-report/sorter.js +21 -7
  7. package/coverage/lcov-report/src/assess-distribution/index.html +116 -0
  8. package/coverage/lcov-report/src/assess-distribution/index.ts.html +754 -0
  9. package/coverage/lcov-report/{list → src/benchmark}/index.html +30 -30
  10. package/coverage/lcov-report/src/benchmark/index.ts.html +793 -0
  11. package/coverage/lcov-report/{builder → src/builder}/allocator.ts.html +38 -38
  12. package/coverage/lcov-report/{builder/buildScopedConditions.ts.html → src/builder/applyContextToConditions.ts.html} +80 -65
  13. package/coverage/lcov-report/{builder/buildScopedDatafile.ts.html → src/builder/applyContextToDatafile.ts.html} +92 -92
  14. package/coverage/lcov-report/{builder/buildScopedSegments.ts.html → src/builder/applyContextToSegments.ts.html} +103 -67
  15. package/coverage/lcov-report/{builder → src/builder}/buildDatafile.ts.html +336 -306
  16. package/coverage/lcov-report/src/builder/buildProject.ts.html +1117 -0
  17. package/coverage/lcov-report/src/builder/buildRuntimeDatafiles.ts.html +256 -0
  18. package/coverage/lcov-report/{builder → src/builder}/getFeatureRanges.ts.html +22 -22
  19. package/coverage/lcov-report/{builder → src/builder}/hashes.ts.html +50 -50
  20. package/coverage/lcov-report/{builder → src/builder}/index.html +114 -84
  21. package/coverage/lcov-report/{tester/cliFormat.ts.html → src/builder/index.ts.html} +17 -29
  22. package/coverage/lcov-report/{builder → src/builder}/mutateVariables.ts.html +55 -55
  23. package/coverage/lcov-report/{builder → src/builder}/mutator.ts.html +118 -118
  24. package/coverage/lcov-report/{builder → src/builder}/revision.ts.html +15 -15
  25. package/coverage/lcov-report/{builder → src/builder}/traffic.ts.html +86 -86
  26. package/coverage/lcov-report/src/cli/cli.ts.html +400 -0
  27. package/coverage/lcov-report/{tester → src/cli}/index.html +41 -41
  28. package/coverage/lcov-report/src/cli/plugins.ts.html +214 -0
  29. package/coverage/lcov-report/{config → src/config}/index.html +31 -31
  30. package/coverage/lcov-report/{config → src/config}/index.ts.html +12 -12
  31. package/coverage/lcov-report/{config → src/config}/projectConfig.ts.html +312 -96
  32. package/coverage/lcov-report/{datasource → src/datasource}/adapter.ts.html +28 -73
  33. package/coverage/lcov-report/{datasource → src/datasource}/datasource.ts.html +191 -104
  34. package/coverage/lcov-report/{datasource → src/datasource}/filesystemAdapter.ts.html +233 -635
  35. package/coverage/lcov-report/{datasource → src/datasource}/index.html +48 -48
  36. package/coverage/lcov-report/{datasource → src/datasource}/index.ts.html +14 -14
  37. package/coverage/lcov-report/src/evaluate/index.html +116 -0
  38. package/coverage/lcov-report/src/evaluate/index.ts.html +814 -0
  39. package/coverage/lcov-report/src/find-duplicate-segments/findDuplicateSegments.ts.html +313 -0
  40. package/coverage/lcov-report/src/find-duplicate-segments/index.html +131 -0
  41. package/coverage/lcov-report/src/find-duplicate-segments/index.ts.html +307 -0
  42. package/coverage/lcov-report/src/find-usage/index.html +116 -0
  43. package/coverage/lcov-report/src/find-usage/index.ts.html +1780 -0
  44. package/coverage/lcov-report/src/generate-code/index.html +131 -0
  45. package/coverage/lcov-report/src/generate-code/index.ts.html +403 -0
  46. package/coverage/lcov-report/{generate-code → src/generate-code}/typescript.ts.html +266 -1361
  47. package/coverage/lcov-report/{generate-code → src}/index.html +38 -23
  48. package/coverage/lcov-report/src/info/index.html +116 -0
  49. package/coverage/lcov-report/src/info/index.ts.html +472 -0
  50. package/coverage/lcov-report/src/init/index.html +116 -0
  51. package/coverage/lcov-report/src/init/index.ts.html +280 -0
  52. package/coverage/lcov-report/{linter → src/linter}/attributeSchema.ts.html +160 -157
  53. package/coverage/lcov-report/{linter → src/linter}/checkCircularDependency.ts.html +25 -25
  54. package/coverage/lcov-report/{linter → src/linter}/checkPercentageExceedingSlot.ts.html +42 -42
  55. package/coverage/lcov-report/{linter → src/linter}/conditionSchema.ts.html +207 -207
  56. package/coverage/lcov-report/{linter → src/linter}/featureSchema.ts.html +462 -471
  57. package/coverage/lcov-report/{linter → src/linter}/groupSchema.ts.html +25 -22
  58. package/coverage/lcov-report/{linter → src/linter}/index.html +129 -99
  59. package/coverage/lcov-report/src/linter/index.ts.html +88 -0
  60. package/coverage/lcov-report/{linter → src/linter}/lintProject.ts.html +740 -332
  61. package/coverage/lcov-report/{linter → src/linter}/mutationNotation.ts.html +130 -130
  62. package/coverage/lcov-report/{linter → src/linter}/printError.ts.html +27 -27
  63. package/coverage/lcov-report/{linter → src/linter}/schema.ts.html +153 -150
  64. package/coverage/lcov-report/{linter → src/linter}/segmentSchema.ts.html +18 -15
  65. package/coverage/lcov-report/src/linter/targetSchema.ts.html +223 -0
  66. package/coverage/lcov-report/{linter → src/linter}/testSchema.ts.html +54 -48
  67. package/coverage/lcov-report/{linter → src/linter}/zodHelpers.ts.html +17 -17
  68. package/coverage/lcov-report/src/list/index.html +131 -0
  69. package/coverage/lcov-report/src/list/index.ts.html +2065 -0
  70. package/coverage/lcov-report/{list → src/list}/matrix.ts.html +43 -58
  71. package/coverage/lcov-report/src/promoter/index.html +116 -0
  72. package/coverage/lcov-report/src/promoter/index.ts.html +3883 -0
  73. package/coverage/lcov-report/src/sets.ts.html +313 -0
  74. package/coverage/lcov-report/src/targeting.ts.html +403 -0
  75. package/coverage/lcov-report/src/tester/cliFormat.ts.html +133 -0
  76. package/coverage/lcov-report/{tester → src/tester}/helpers.ts.html +15 -15
  77. package/coverage/lcov-report/src/tester/index.html +206 -0
  78. package/coverage/lcov-report/src/tester/prettyDuration.ts.html +187 -0
  79. package/coverage/lcov-report/src/tester/printTestResult.ts.html +337 -0
  80. package/coverage/lcov-report/src/tester/testFeature.ts.html +1186 -0
  81. package/coverage/lcov-report/src/tester/testProject.ts.html +1018 -0
  82. package/coverage/lcov-report/src/tester/testSegment.ts.html +316 -0
  83. package/coverage/lcov-report/{utils → src/utils}/extractKeys.ts.html +68 -68
  84. package/coverage/lcov-report/{utils → src/utils}/git.ts.html +44 -68
  85. package/coverage/lcov-report/{utils → src/utils}/index.html +44 -44
  86. package/coverage/lcov-report/{utils → src/utils}/index.ts.html +14 -14
  87. package/coverage/lcov-report/{utils → src/utils}/pretty.ts.html +20 -20
  88. package/coverage/lcov.info +10121 -5723
  89. package/jest.config.js +13 -4
  90. package/lib/assess-distribution/index.d.ts +1 -1
  91. package/lib/assess-distribution/index.js +59 -40
  92. package/lib/assess-distribution/index.js.map +1 -1
  93. package/lib/benchmark/index.d.ts +8 -5
  94. package/lib/benchmark/index.js +82 -65
  95. package/lib/benchmark/index.js.map +1 -1
  96. package/lib/builder/applyContextToConditions.d.ts +5 -0
  97. package/lib/builder/{buildScopedConditions.js → applyContextToConditions.js} +19 -14
  98. package/lib/builder/applyContextToConditions.js.map +1 -0
  99. package/lib/builder/applyContextToDatafile.d.ts +2 -0
  100. package/lib/builder/{buildScopedDatafile.js → applyContextToDatafile.js} +26 -26
  101. package/lib/builder/applyContextToDatafile.js.map +1 -0
  102. package/lib/builder/applyContextToSegments.d.ts +5 -0
  103. package/lib/builder/{buildScopedSegments.js → applyContextToSegments.js} +19 -14
  104. package/lib/builder/applyContextToSegments.js.map +1 -0
  105. package/lib/builder/buildDatafile.d.ts +9 -6
  106. package/lib/builder/buildDatafile.js +86 -51
  107. package/lib/builder/buildDatafile.js.map +1 -1
  108. package/lib/builder/buildProject.d.ts +17 -3
  109. package/lib/builder/buildProject.js +151 -59
  110. package/lib/builder/buildProject.js.map +1 -1
  111. package/lib/builder/buildRuntimeDatafiles.d.ts +12 -0
  112. package/lib/builder/buildRuntimeDatafiles.js +35 -0
  113. package/lib/builder/buildRuntimeDatafiles.js.map +1 -0
  114. package/lib/builder/getFeatureRanges.js +34 -1
  115. package/lib/builder/getFeatureRanges.js.map +1 -1
  116. package/lib/builder/hashes.js +34 -1
  117. package/lib/builder/hashes.js.map +1 -1
  118. package/lib/builder/index.d.ts +0 -1
  119. package/lib/builder/index.js +0 -1
  120. package/lib/builder/index.js.map +1 -1
  121. package/lib/cli/cli.js +0 -4
  122. package/lib/cli/cli.js.map +1 -1
  123. package/lib/cli/plugins.js +7 -2
  124. package/lib/cli/plugins.js.map +1 -1
  125. package/lib/config/projectConfig.d.ts +17 -17
  126. package/lib/config/projectConfig.js +101 -15
  127. package/lib/config/projectConfig.js.map +1 -1
  128. package/lib/datasource/adapter.d.ts +7 -9
  129. package/lib/datasource/adapter.js +0 -7
  130. package/lib/datasource/adapter.js.map +1 -1
  131. package/lib/datasource/datasource.d.ts +15 -5
  132. package/lib/datasource/datasource.js +37 -9
  133. package/lib/datasource/datasource.js.map +1 -1
  134. package/lib/datasource/filesystemAdapter.d.ts +4 -10
  135. package/lib/datasource/filesystemAdapter.js +111 -149
  136. package/lib/datasource/filesystemAdapter.js.map +1 -1
  137. package/lib/evaluate/index.d.ts +1 -7
  138. package/lib/evaluate/index.js +81 -67
  139. package/lib/evaluate/index.js.map +1 -1
  140. package/lib/find-duplicate-segments/findDuplicateSegments.js +34 -1
  141. package/lib/find-duplicate-segments/findDuplicateSegments.js.map +1 -1
  142. package/lib/find-duplicate-segments/index.js +21 -13
  143. package/lib/find-duplicate-segments/index.js.map +1 -1
  144. package/lib/find-usage/index.js +57 -41
  145. package/lib/find-usage/index.js.map +1 -1
  146. package/lib/generate-code/index.d.ts +1 -1
  147. package/lib/generate-code/index.js +64 -21
  148. package/lib/generate-code/index.js.map +1 -1
  149. package/lib/generate-code/typescript.d.ts +1 -1
  150. package/lib/generate-code/typescript.js +59 -333
  151. package/lib/generate-code/typescript.js.map +1 -1
  152. package/lib/index.d.ts +2 -1
  153. package/lib/index.js +2 -1
  154. package/lib/index.js.map +1 -1
  155. package/lib/info/index.js +57 -16
  156. package/lib/info/index.js.map +1 -1
  157. package/lib/init/index.d.ts +2 -2
  158. package/lib/init/index.js +39 -3
  159. package/lib/init/index.js.map +1 -1
  160. package/lib/linter/attributeSchema.d.ts +1 -0
  161. package/lib/linter/attributeSchema.js +1 -0
  162. package/lib/linter/attributeSchema.js.map +1 -1
  163. package/lib/linter/conditionSchema.js +5 -5
  164. package/lib/linter/conditionSchema.js.map +1 -1
  165. package/lib/linter/featureSchema.d.ts +4 -1
  166. package/lib/linter/featureSchema.js +15 -13
  167. package/lib/linter/featureSchema.js.map +1 -1
  168. package/lib/linter/groupSchema.d.ts +1 -0
  169. package/lib/linter/groupSchema.js +1 -0
  170. package/lib/linter/groupSchema.js.map +1 -1
  171. package/lib/linter/lintProject.d.ts +1 -3
  172. package/lib/linter/lintProject.js +198 -68
  173. package/lib/linter/lintProject.js.map +1 -1
  174. package/lib/linter/schema.js +1 -0
  175. package/lib/linter/schema.js.map +1 -1
  176. package/lib/linter/segmentSchema.d.ts +1 -0
  177. package/lib/linter/segmentSchema.js +1 -0
  178. package/lib/linter/segmentSchema.js.map +1 -1
  179. package/lib/linter/targetSchema.d.ts +16 -0
  180. package/lib/linter/targetSchema.js +40 -0
  181. package/lib/linter/targetSchema.js.map +1 -0
  182. package/lib/linter/testSchema.d.ts +4 -3
  183. package/lib/linter/testSchema.js +9 -4
  184. package/lib/linter/testSchema.js.map +1 -1
  185. package/lib/list/index.d.ts +1 -0
  186. package/lib/list/index.js +131 -12
  187. package/lib/list/index.js.map +1 -1
  188. package/lib/list/matrix.js +3 -7
  189. package/lib/list/matrix.js.map +1 -1
  190. package/lib/promoter/index.d.ts +50 -0
  191. package/lib/promoter/index.js +880 -0
  192. package/lib/promoter/index.js.map +1 -0
  193. package/lib/sets.d.ts +11 -0
  194. package/lib/sets.js +81 -0
  195. package/lib/sets.js.map +1 -0
  196. package/lib/targeting.d.ts +14 -0
  197. package/lib/targeting.js +82 -0
  198. package/lib/targeting.js.map +1 -0
  199. package/lib/tester/cliFormat.d.ts +7 -1
  200. package/lib/tester/cliFormat.js +11 -2
  201. package/lib/tester/cliFormat.js.map +1 -1
  202. package/lib/tester/printTestResult.js +2 -2
  203. package/lib/tester/printTestResult.js.map +1 -1
  204. package/lib/tester/testFeature.d.ts +0 -1
  205. package/lib/tester/testFeature.js +8 -25
  206. package/lib/tester/testFeature.js.map +1 -1
  207. package/lib/tester/testProject.d.ts +2 -3
  208. package/lib/tester/testProject.js +93 -86
  209. package/lib/tester/testProject.js.map +1 -1
  210. package/lib/tester/testSegment.d.ts +1 -1
  211. package/lib/tester/testSegment.js +3 -21
  212. package/lib/tester/testSegment.js.map +1 -1
  213. package/lib/utils/git.js +45 -19
  214. package/lib/utils/git.js.map +1 -1
  215. package/package.json +12 -12
  216. package/src/assess-distribution/index.ts +72 -52
  217. package/src/benchmark/index.ts +124 -91
  218. package/src/builder/{buildScopedConditions.spec.ts → applyContextToConditions.spec.ts} +160 -142
  219. package/src/builder/{buildScopedConditions.ts → applyContextToConditions.ts} +19 -14
  220. package/src/builder/{buildScopedDatafile.spec.ts → applyContextToDatafile.spec.ts} +141 -81
  221. package/src/builder/{buildScopedDatafile.ts → applyContextToDatafile.ts} +33 -33
  222. package/src/builder/{buildScopedSegments.spec.ts → applyContextToSegments.spec.ts} +171 -151
  223. package/src/builder/{buildScopedSegments.ts → applyContextToSegments.ts} +26 -14
  224. package/src/builder/buildDatafile.spec.ts +192 -14
  225. package/src/builder/buildDatafile.ts +74 -64
  226. package/src/builder/buildProject.ts +171 -86
  227. package/src/builder/buildRuntimeDatafiles.ts +57 -0
  228. package/src/builder/index.ts +0 -1
  229. package/src/cli/cli.ts +0 -5
  230. package/src/cli/plugins.ts +7 -2
  231. package/src/config/projectConfig.spec.ts +171 -8
  232. package/src/config/projectConfig.ts +100 -28
  233. package/src/datasource/adapter.ts +8 -23
  234. package/src/datasource/datasource.ts +50 -21
  235. package/src/datasource/filesystemAdapter.spec.ts +133 -74
  236. package/src/datasource/filesystemAdapter.ts +93 -227
  237. package/src/evaluate/index.ts +109 -97
  238. package/src/find-duplicate-segments/index.ts +34 -16
  239. package/src/find-usage/index.ts +89 -44
  240. package/src/generate-code/index.ts +36 -24
  241. package/src/generate-code/typescript.spec.ts +106 -0
  242. package/src/generate-code/typescript.ts +33 -398
  243. package/src/index.ts +2 -1
  244. package/src/info/index.ts +72 -16
  245. package/src/init/index.ts +1 -1
  246. package/src/linter/attributeSchema.ts +1 -0
  247. package/src/linter/conditionSchema.spec.ts +23 -3
  248. package/src/linter/conditionSchema.ts +5 -5
  249. package/src/linter/featureSchema.spec.ts +107 -18
  250. package/src/linter/featureSchema.ts +25 -28
  251. package/src/linter/groupSchema.ts +1 -0
  252. package/src/linter/lintProject.spec.ts +131 -92
  253. package/src/linter/lintProject.ts +233 -97
  254. package/src/linter/schema.ts +1 -0
  255. package/src/linter/segmentSchema.spec.ts +5 -3
  256. package/src/linter/segmentSchema.ts +1 -0
  257. package/src/linter/targetSchema.spec.ts +159 -0
  258. package/src/linter/targetSchema.ts +46 -0
  259. package/src/linter/testSchema.spec.ts +70 -5
  260. package/src/linter/testSchema.ts +12 -10
  261. package/src/list/index.spec.ts +135 -0
  262. package/src/list/index.ts +188 -12
  263. package/src/list/matrix.ts +3 -8
  264. package/src/promoter/index.spec.ts +617 -0
  265. package/src/promoter/index.ts +1266 -0
  266. package/src/sets.ts +76 -0
  267. package/src/targeting.spec.ts +74 -0
  268. package/src/targeting.ts +106 -0
  269. package/src/tester/cliFormat.ts +11 -1
  270. package/src/tester/printTestResult.ts +12 -3
  271. package/src/tester/testFeature.ts +10 -36
  272. package/src/tester/testProject.spec.ts +50 -0
  273. package/src/tester/testProject.ts +89 -140
  274. package/src/tester/testSegment.ts +5 -22
  275. package/src/utils/git.ts +13 -21
  276. package/tsconfig.cjs.json +5 -1
  277. package/tsconfig.typecheck.json +9 -0
  278. package/coverage/lcov-report/builder/convertToV1.ts.html +0 -583
  279. package/lib/builder/allocator.spec.d.ts +0 -1
  280. package/lib/builder/allocator.spec.js +0 -85
  281. package/lib/builder/allocator.spec.js.map +0 -1
  282. package/lib/builder/buildDatafile.spec.d.ts +0 -1
  283. package/lib/builder/buildDatafile.spec.js +0 -233
  284. package/lib/builder/buildDatafile.spec.js.map +0 -1
  285. package/lib/builder/buildScopedConditions.d.ts +0 -5
  286. package/lib/builder/buildScopedConditions.js.map +0 -1
  287. package/lib/builder/buildScopedConditions.spec.d.ts +0 -1
  288. package/lib/builder/buildScopedConditions.spec.js +0 -2167
  289. package/lib/builder/buildScopedConditions.spec.js.map +0 -1
  290. package/lib/builder/buildScopedDatafile.d.ts +0 -2
  291. package/lib/builder/buildScopedDatafile.js.map +0 -1
  292. package/lib/builder/buildScopedDatafile.spec.d.ts +0 -1
  293. package/lib/builder/buildScopedDatafile.spec.js +0 -2277
  294. package/lib/builder/buildScopedDatafile.spec.js.map +0 -1
  295. package/lib/builder/buildScopedSegments.d.ts +0 -5
  296. package/lib/builder/buildScopedSegments.js.map +0 -1
  297. package/lib/builder/buildScopedSegments.spec.d.ts +0 -1
  298. package/lib/builder/buildScopedSegments.spec.js +0 -1062
  299. package/lib/builder/buildScopedSegments.spec.js.map +0 -1
  300. package/lib/builder/convertToV1.d.ts +0 -10
  301. package/lib/builder/convertToV1.js +0 -119
  302. package/lib/builder/convertToV1.js.map +0 -1
  303. package/lib/builder/mutateVariables.spec.d.ts +0 -1
  304. package/lib/builder/mutateVariables.spec.js +0 -1074
  305. package/lib/builder/mutateVariables.spec.js.map +0 -1
  306. package/lib/builder/mutator.spec.d.ts +0 -1
  307. package/lib/builder/mutator.spec.js +0 -368
  308. package/lib/builder/mutator.spec.js.map +0 -1
  309. package/lib/builder/revision.spec.d.ts +0 -1
  310. package/lib/builder/revision.spec.js +0 -21
  311. package/lib/builder/revision.spec.js.map +0 -1
  312. package/lib/builder/traffic.spec.d.ts +0 -1
  313. package/lib/builder/traffic.spec.js +0 -872
  314. package/lib/builder/traffic.spec.js.map +0 -1
  315. package/lib/config/projectConfig.spec.d.ts +0 -1
  316. package/lib/config/projectConfig.spec.js +0 -24
  317. package/lib/config/projectConfig.spec.js.map +0 -1
  318. package/lib/datasource/filesystemAdapter.spec.d.ts +0 -1
  319. package/lib/datasource/filesystemAdapter.spec.js +0 -88
  320. package/lib/datasource/filesystemAdapter.spec.js.map +0 -1
  321. package/lib/generate-code/typescript.spec.d.ts +0 -1
  322. package/lib/generate-code/typescript.spec.js +0 -78
  323. package/lib/generate-code/typescript.spec.js.map +0 -1
  324. package/lib/linter/attributeSchema.spec.d.ts +0 -1
  325. package/lib/linter/attributeSchema.spec.js +0 -266
  326. package/lib/linter/attributeSchema.spec.js.map +0 -1
  327. package/lib/linter/conditionSchema.spec.d.ts +0 -1
  328. package/lib/linter/conditionSchema.spec.js +0 -380
  329. package/lib/linter/conditionSchema.spec.js.map +0 -1
  330. package/lib/linter/featureSchema.spec.d.ts +0 -1
  331. package/lib/linter/featureSchema.spec.js +0 -1552
  332. package/lib/linter/featureSchema.spec.js.map +0 -1
  333. package/lib/linter/lintProject.spec.d.ts +0 -1
  334. package/lib/linter/lintProject.spec.js +0 -211
  335. package/lib/linter/lintProject.spec.js.map +0 -1
  336. package/lib/linter/mutationNotation.spec.d.ts +0 -1
  337. package/lib/linter/mutationNotation.spec.js +0 -598
  338. package/lib/linter/mutationNotation.spec.js.map +0 -1
  339. package/lib/linter/schema.spec.d.ts +0 -1
  340. package/lib/linter/schema.spec.js +0 -535
  341. package/lib/linter/schema.spec.js.map +0 -1
  342. package/lib/linter/segmentSchema.spec.d.ts +0 -1
  343. package/lib/linter/segmentSchema.spec.js +0 -303
  344. package/lib/linter/segmentSchema.spec.js.map +0 -1
  345. package/lib/linter/testSchema.spec.d.ts +0 -1
  346. package/lib/linter/testSchema.spec.js +0 -162
  347. package/lib/linter/testSchema.spec.js.map +0 -1
  348. package/lib/list/matrix.spec.d.ts +0 -1
  349. package/lib/list/matrix.spec.js +0 -42
  350. package/lib/list/matrix.spec.js.map +0 -1
  351. package/lib/site/exportSite.d.ts +0 -2
  352. package/lib/site/exportSite.js +0 -30
  353. package/lib/site/exportSite.js.map +0 -1
  354. package/lib/site/generateHistory.d.ts +0 -3
  355. package/lib/site/generateHistory.js +0 -31
  356. package/lib/site/generateHistory.js.map +0 -1
  357. package/lib/site/generateSiteSearchIndex.d.ts +0 -4
  358. package/lib/site/generateSiteSearchIndex.js +0 -195
  359. package/lib/site/generateSiteSearchIndex.js.map +0 -1
  360. package/lib/site/getLastModifiedFromHistory.d.ts +0 -2
  361. package/lib/site/getLastModifiedFromHistory.js +0 -18
  362. package/lib/site/getLastModifiedFromHistory.js.map +0 -1
  363. package/lib/site/getOwnerAndRepoFromUrl.d.ts +0 -4
  364. package/lib/site/getOwnerAndRepoFromUrl.js +0 -20
  365. package/lib/site/getOwnerAndRepoFromUrl.js.map +0 -1
  366. package/lib/site/getRelativePaths.d.ts +0 -6
  367. package/lib/site/getRelativePaths.js +0 -15
  368. package/lib/site/getRelativePaths.js.map +0 -1
  369. package/lib/site/getRepoDetails.d.ts +0 -8
  370. package/lib/site/getRepoDetails.js +0 -48
  371. package/lib/site/getRepoDetails.js.map +0 -1
  372. package/lib/site/index.d.ts +0 -2
  373. package/lib/site/index.js +0 -43
  374. package/lib/site/index.js.map +0 -1
  375. package/lib/site/serveSite.d.ts +0 -2
  376. package/lib/site/serveSite.js +0 -54
  377. package/lib/site/serveSite.js.map +0 -1
  378. package/lib/tester/helpers.spec.d.ts +0 -1
  379. package/lib/tester/helpers.spec.js +0 -115
  380. package/lib/tester/helpers.spec.js.map +0 -1
  381. package/src/builder/convertToV1.ts +0 -166
  382. package/src/site/exportSite.ts +0 -42
  383. package/src/site/generateHistory.ts +0 -40
  384. package/src/site/generateSiteSearchIndex.ts +0 -258
  385. package/src/site/getLastModifiedFromHistory.ts +0 -21
  386. package/src/site/getOwnerAndRepoFromUrl.ts +0 -17
  387. package/src/site/getRelativePaths.ts +0 -24
  388. package/src/site/getRepoDetails.ts +0 -62
  389. package/src/site/index.ts +0 -46
  390. package/src/site/serveSite.ts +0 -58
package/src/sets.ts ADDED
@@ -0,0 +1,76 @@
1
+ import * as path from "path";
2
+
3
+ import type { ProjectConfig } from "./config";
4
+ import type { Datasource } from "./datasource";
5
+ import { CLI_FORMAT_BOLD } from "./tester/cliFormat";
6
+
7
+ export interface ProjectSetExecution {
8
+ set: string;
9
+ projectConfig: ProjectConfig;
10
+ datasource: Datasource;
11
+ }
12
+
13
+ export async function getProjectSetExecutions(
14
+ projectConfig: ProjectConfig,
15
+ datasource: Datasource,
16
+ selectedSet?: string,
17
+ ): Promise<ProjectSetExecution[]> {
18
+ if (!projectConfig.sets) {
19
+ return [{ set: "", projectConfig, datasource }];
20
+ }
21
+
22
+ const availableSetKeys = await datasource.listSets();
23
+
24
+ if (selectedSet && !availableSetKeys.includes(selectedSet)) {
25
+ throw new Error(
26
+ `Unknown set "${selectedSet}". Available sets: ${availableSetKeys.join(", ") || "none"}.`,
27
+ );
28
+ }
29
+
30
+ const setKeys = selectedSet ? [selectedSet] : availableSetKeys;
31
+
32
+ if (setKeys.length === 0) {
33
+ throw new Error(`No sets found in ${projectConfig.setsDirectoryPath}.`);
34
+ }
35
+
36
+ return setKeys.map((set) => {
37
+ const setDatasource = datasource.forSet(set);
38
+
39
+ return {
40
+ set,
41
+ projectConfig: setDatasource.getConfig(),
42
+ datasource: setDatasource,
43
+ };
44
+ });
45
+ }
46
+
47
+ export function assertProjectSetJsonSelection(
48
+ projectConfig: ProjectConfig,
49
+ selectedSet: string | undefined,
50
+ json: boolean | undefined,
51
+ ) {
52
+ if (projectConfig.sets && json && !selectedSet) {
53
+ throw new Error("Pass --set=<set> when using --json in a project with sets enabled.");
54
+ }
55
+ }
56
+
57
+ export function getProjectSetRelativeFilePath(
58
+ projectConfig: ProjectConfig,
59
+ set: string,
60
+ filePath: string,
61
+ ) {
62
+ const setDirectoryPath = path.join(projectConfig.setsDirectoryPath, set);
63
+
64
+ if (filePath === setDirectoryPath || filePath.startsWith(`${setDirectoryPath}${path.sep}`)) {
65
+ return filePath;
66
+ }
67
+
68
+ return path.join(setDirectoryPath, filePath);
69
+ }
70
+
71
+ export function printSetHeader(projectConfig: ProjectConfig, set: string, silent = false) {
72
+ if (projectConfig.sets && !silent) {
73
+ console.log("");
74
+ console.log(CLI_FORMAT_BOLD, `Set "${set}"`);
75
+ }
76
+ }
@@ -0,0 +1,74 @@
1
+ import type { ParsedFeature, Target } from "@featurevisor/types";
2
+
3
+ import { getTargetFeatureKeys, resolveTargets, targetIncludesFeature } from "./targeting";
4
+
5
+ const features: Record<string, ParsedFeature> = {
6
+ webCheckout: {
7
+ key: "webCheckout",
8
+ description: "Web checkout",
9
+ tags: ["web", "checkout"],
10
+ bucketBy: "userId",
11
+ rules: [],
12
+ },
13
+ webInternal: {
14
+ key: "webInternal",
15
+ description: "Internal web",
16
+ tags: ["web", "internal"],
17
+ bucketBy: "userId",
18
+ rules: [],
19
+ },
20
+ mobileCheckout: {
21
+ key: "mobileCheckout",
22
+ description: "Mobile checkout",
23
+ tags: ["mobile", "checkout"],
24
+ bucketBy: "userId",
25
+ rules: [],
26
+ },
27
+ };
28
+
29
+ const targets: Record<string, Target> = {
30
+ web: {
31
+ description: "Web",
32
+ tags: { and: ["web", "checkout"] },
33
+ includeFeatures: ["web*"],
34
+ excludeFeatures: ["webInternal*"],
35
+ },
36
+ mobile: { description: "Mobile", tag: "mobile" },
37
+ };
38
+
39
+ function createDatasource() {
40
+ return {
41
+ listTargets: async () => Object.keys(targets),
42
+ readTarget: async (key: string) => targets[key],
43
+ listFeatures: async () => Object.keys(features),
44
+ readFeature: async (key: string) => features[key],
45
+ } as any;
46
+ }
47
+
48
+ describe("targeting", () => {
49
+ it("matches full target selectors", () => {
50
+ expect(targetIncludesFeature(targets.web, "webCheckout", features.webCheckout)).toEqual(true);
51
+ expect(targetIncludesFeature(targets.web, "webInternal", features.webInternal)).toEqual(false);
52
+ expect(targetIncludesFeature(targets.web, "mobileCheckout", features.mobileCheckout)).toEqual(
53
+ false,
54
+ );
55
+ });
56
+
57
+ it("resolves repeated targets once and returns their feature union", async () => {
58
+ const datasource = createDatasource();
59
+ const resolved = await resolveTargets(datasource, ["web", "mobile", "web"]);
60
+ const featureKeys = await getTargetFeatureKeys(datasource, resolved);
61
+
62
+ expect(resolved.map((target) => target.key)).toEqual(["web", "mobile"]);
63
+ expect(Array.from(featureKeys).sort()).toEqual(["mobileCheckout", "webCheckout"]);
64
+ });
65
+
66
+ it("validates unknown and missing targets", async () => {
67
+ await expect(resolveTargets(createDatasource(), "missing")).rejects.toThrow(
68
+ 'Unknown target "missing"',
69
+ );
70
+ await expect(resolveTargets({ listTargets: async () => [] } as any, undefined)).rejects.toThrow(
71
+ "No targets found",
72
+ );
73
+ });
74
+ });
@@ -0,0 +1,106 @@
1
+ import type { ParsedFeature, Target } from "@featurevisor/types";
2
+
3
+ import type { Datasource } from "./datasource";
4
+
5
+ export type ResolvedTarget = Target & { key: string };
6
+
7
+ export function normalizeOptionValues(value: string | string[] | undefined): string[] {
8
+ if (typeof value === "undefined") return [];
9
+ return Array.isArray(value) ? value : [value];
10
+ }
11
+
12
+ export function matchesFeaturePatterns(
13
+ featureKey: string,
14
+ patterns: Target["includeFeatures"],
15
+ ): boolean {
16
+ if (!patterns) return false;
17
+ return normalizeOptionValues(patterns).some((pattern) => {
18
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
19
+ return new RegExp(`^${escaped}$`).test(featureKey);
20
+ });
21
+ }
22
+
23
+ export function matchesTargetTags(candidateTags: string[], selector: Target["tags"]): boolean {
24
+ if (!selector) return true;
25
+ if (Array.isArray(selector)) {
26
+ return selector.some((tag) => candidateTags.includes(tag));
27
+ }
28
+ if ("or" in selector) {
29
+ return selector.or.some((tag) => candidateTags.includes(tag));
30
+ }
31
+ return selector.and.every((tag) => candidateTags.includes(tag));
32
+ }
33
+
34
+ export function targetIncludesFeature(
35
+ target: Target,
36
+ featureKey: string,
37
+ feature: ParsedFeature,
38
+ ): boolean {
39
+ if (feature.archived === true) return false;
40
+
41
+ const featureTags = feature.tags || [];
42
+ if (target.tag && !featureTags.includes(target.tag)) return false;
43
+ if (target.tags && !matchesTargetTags(featureTags, target.tags)) return false;
44
+ if (target.includeFeatures && !matchesFeaturePatterns(featureKey, target.includeFeatures)) {
45
+ return false;
46
+ }
47
+ if (target.excludeFeatures && matchesFeaturePatterns(featureKey, target.excludeFeatures)) {
48
+ return false;
49
+ }
50
+
51
+ return true;
52
+ }
53
+
54
+ export async function resolveTargets(
55
+ datasource: Datasource,
56
+ requestedTargets?: string | string[],
57
+ options: { defaultToAll?: boolean; requireTargets?: boolean } = {},
58
+ ): Promise<ResolvedTarget[]> {
59
+ const targetKeys = await datasource.listTargets();
60
+ const requestedTargetKeys = normalizeOptionValues(requestedTargets);
61
+ const selectedKeys =
62
+ requestedTargetKeys.length > 0
63
+ ? requestedTargetKeys
64
+ : options.defaultToAll === false
65
+ ? []
66
+ : targetKeys;
67
+
68
+ if (options.requireTargets !== false && targetKeys.length === 0) {
69
+ throw new Error(
70
+ 'No targets found. Add at least one target definition, for example "targets/all.yml".',
71
+ );
72
+ }
73
+
74
+ const uniqueKeys = Array.from(new Set(selectedKeys));
75
+ for (const targetKey of uniqueKeys) {
76
+ if (!targetKeys.includes(targetKey)) {
77
+ throw new Error(
78
+ `Unknown target "${targetKey}". Available targets: ${targetKeys.join(", ") || "none"}.`,
79
+ );
80
+ }
81
+ }
82
+
83
+ return Promise.all(
84
+ uniqueKeys.map(async (targetKey) => ({
85
+ ...(await datasource.readTarget(targetKey)),
86
+ key: targetKey,
87
+ })),
88
+ );
89
+ }
90
+
91
+ export async function getTargetFeatureKeys(
92
+ datasource: Datasource,
93
+ targets: ResolvedTarget[],
94
+ ): Promise<Set<string>> {
95
+ const result = new Set<string>();
96
+ const featureKeys = await datasource.listFeatures();
97
+
98
+ for (const featureKey of featureKeys) {
99
+ const feature = await datasource.readFeature(featureKey);
100
+ if (targets.some((target) => targetIncludesFeature(target, featureKey, feature))) {
101
+ result.add(featureKey);
102
+ }
103
+ }
104
+
105
+ return result;
106
+ }
@@ -1,6 +1,16 @@
1
1
  export const CLI_FORMAT_RED = "\x1b[31m%s\x1b[0m";
2
2
  export const CLI_FORMAT_GREEN = "\x1b[32m%s\x1b[0m";
3
+ export const CLI_FORMAT_YELLOW = "\x1b[33m%s\x1b[0m";
4
+ export const CLI_FORMAT_DIM = "\x1b[2m%s\x1b[0m";
5
+
6
+ export const CLI_COLOR_GREEN = 32;
7
+ export const CLI_COLOR_YELLOW = 33;
8
+ export const CLI_COLOR_CYAN = 36;
9
+ export const CLI_COLOR_DIM = 2;
3
10
 
4
11
  export const CLI_FORMAT_BOLD = "\x1b[1m%s\x1b[0m";
5
- export const CLI_FORMAT_UNDERLINE = "\x1b[4m%s\x1b[0m";
6
12
  export const CLI_FORMAT_BOLD_UNDERLINE = "\x1b[1m\x1b[4m%s\x1b[0m";
13
+
14
+ export function colorize(value: string | number | boolean, colorCode: number) {
15
+ return `\x1b[${colorCode}m${value}\x1b[0m`;
16
+ }
@@ -1,6 +1,12 @@
1
1
  import type { TestResult } from "@featurevisor/types";
2
2
 
3
- import { CLI_FORMAT_BOLD, CLI_FORMAT_RED } from "./cliFormat";
3
+ import {
4
+ CLI_COLOR_CYAN,
5
+ CLI_FORMAT_BOLD,
6
+ CLI_FORMAT_GREEN,
7
+ CLI_FORMAT_RED,
8
+ colorize,
9
+ } from "./cliFormat";
4
10
  import { prettyDuration } from "./prettyDuration";
5
11
 
6
12
  export function printTestResult(testResult: TestResult, relativeTestFilePath, rootDirectoryPath) {
@@ -9,7 +15,7 @@ export function printTestResult(testResult: TestResult, relativeTestFilePath, ro
9
15
  const title = `Testing: ${relativeTestFilePath.replace(rootDirectoryPath, "")} (${prettyDuration(
10
16
  testResult.duration,
11
17
  )})`;
12
- console.log(title);
18
+ console.log(colorize(title, CLI_COLOR_CYAN));
13
19
 
14
20
  if (testResult.notFound) {
15
21
  console.log(CLI_FORMAT_RED, ` => ${testResult.type} ${testResult.key} not found`);
@@ -21,7 +27,10 @@ export function printTestResult(testResult: TestResult, relativeTestFilePath, ro
21
27
 
22
28
  testResult.assertions.forEach(function (assertion) {
23
29
  if (assertion.passed) {
24
- console.log(` ✔ ${assertion.description} (${prettyDuration(assertion.duration)})`);
30
+ console.log(
31
+ CLI_FORMAT_GREEN,
32
+ ` ✔ ${assertion.description} (${prettyDuration(assertion.duration)})`,
33
+ );
25
34
  } else {
26
35
  console.log(
27
36
  CLI_FORMAT_RED,
@@ -5,13 +5,9 @@ import type {
5
5
  TestResultAssertion,
6
6
  TestResultAssertionError,
7
7
  } from "@featurevisor/types";
8
- import {
9
- createInstance,
10
- FeaturevisorInstance,
11
- LogLevel,
12
- MAX_BUCKETED_NUMBER,
13
- OverrideOptions,
14
- } from "@featurevisor/sdk";
8
+ import { createFeaturevisor } from "@featurevisor/sdk";
9
+ import type { Featurevisor, FeaturevisorLogLevel, OverrideOptions } from "@featurevisor/sdk";
10
+ import { MAX_BUCKETED_NUMBER } from "@featurevisor/sdk";
15
11
 
16
12
  import { Datasource } from "../datasource";
17
13
  import { ProjectConfig } from "../config";
@@ -23,7 +19,6 @@ export interface TestFeatureOptions {
23
19
  verbose?: boolean;
24
20
  quiet?: boolean;
25
21
  showDatafile?: boolean;
26
- withScopes?: boolean;
27
22
  [key: string]: any;
28
23
  }
29
24
 
@@ -61,16 +56,10 @@ export async function testFeature(
61
56
 
62
57
  let datafileContent = datafileContentByKey.get(assertion.environment || false);
63
58
 
64
- // scope
65
- const scopedDatafileKey = `${assertion.environment}-scope-${assertion.scope}`;
66
- if (assertion.scope && datafileContentByKey.has(scopedDatafileKey)) {
67
- datafileContent = datafileContentByKey.get(scopedDatafileKey);
68
- }
69
-
70
- // tag
71
- const taggedDatafileKey = `${assertion.environment}-tag-${assertion.tag}`;
72
- if (assertion.tag && datafileContentByKey.has(taggedDatafileKey)) {
73
- datafileContent = datafileContentByKey.get(taggedDatafileKey);
59
+ // target
60
+ const targetDatafileKey = `${assertion.environment || false}-target-${assertion.target}`;
61
+ if (assertion.target && datafileContentByKey.has(targetDatafileKey)) {
62
+ datafileContent = datafileContentByKey.get(targetDatafileKey);
74
63
  }
75
64
 
76
65
  if (options.showDatafile) {
@@ -79,17 +68,17 @@ export async function testFeature(
79
68
  console.log("");
80
69
  }
81
70
 
82
- let logLevel: LogLevel = "warn";
71
+ let logLevel: FeaturevisorLogLevel = "warn";
83
72
  if (options.verbose) {
84
73
  logLevel = "debug";
85
74
  } else if (options.quiet) {
86
75
  logLevel = "fatal";
87
76
  }
88
77
 
89
- const sdk: FeaturevisorInstance = createInstance({
78
+ const sdk: Featurevisor = createFeaturevisor({
90
79
  datafile: datafileContent as DatafileContent,
91
80
  sticky: assertion.sticky ? assertion.sticky : {},
92
- hooks: [
81
+ modules: [
93
82
  {
94
83
  name: "tester",
95
84
  bucketValue: ({ bucketValue }) => {
@@ -114,21 +103,6 @@ export async function testFeature(
114
103
 
115
104
  let context = {};
116
105
 
117
- if (assertion.scope) {
118
- if (!options.withScopes) {
119
- // if not testing with scoped datafiles,
120
- // then we need to add the scope's context to the context
121
- const scope = projectConfig.scopes?.find((s) => s.name === assertion.scope);
122
-
123
- if (scope) {
124
- context = {
125
- ...(scope.context || {}),
126
- ...context,
127
- };
128
- }
129
- }
130
- }
131
-
132
106
  if (assertion.context) {
133
107
  context = {
134
108
  ...context,
@@ -0,0 +1,50 @@
1
+ import type { Test, TestFeature } from "@featurevisor/types";
2
+
3
+ import { filterTestForTargets } from "./testProject";
4
+
5
+ describe("core: test target selection", () => {
6
+ const featureTest = {
7
+ key: "checkout",
8
+ feature: "checkout",
9
+ assertions: [
10
+ { description: "base", context: {}, expectedToBeEnabled: true },
11
+ { description: "web", target: "web", context: {}, expectedToBeEnabled: true },
12
+ { description: "mobile", target: "mobile", context: {}, expectedToBeEnabled: true },
13
+ ],
14
+ } as TestFeature;
15
+
16
+ it("keeps untargeted assertions and assertions for all selected targets", () => {
17
+ const filtered = filterTestForTargets(featureTest, ["web", "mobile"]) as TestFeature;
18
+
19
+ expect(filtered.assertions.map((assertion) => assertion.description)).toEqual([
20
+ "base",
21
+ "web",
22
+ "mobile",
23
+ ]);
24
+ });
25
+
26
+ it("removes assertions for targets that were not selected", () => {
27
+ const filtered = filterTestForTargets(featureTest, ["web"]) as TestFeature;
28
+
29
+ expect(filtered.assertions.map((assertion) => assertion.description)).toEqual(["base", "web"]);
30
+ });
31
+
32
+ it("skips a feature test when none of its targeted assertions were selected", () => {
33
+ const targetedOnly = {
34
+ ...featureTest,
35
+ assertions: featureTest.assertions.slice(1),
36
+ } as TestFeature;
37
+
38
+ expect(filterTestForTargets(targetedOnly, ["api"])).toBeUndefined();
39
+ });
40
+
41
+ it("does not filter segment tests", () => {
42
+ const segmentTest = {
43
+ key: "everyone",
44
+ segment: "everyone",
45
+ assertions: [],
46
+ } as unknown as Test;
47
+
48
+ expect(filterTestForTargets(segmentTest, ["web"])).toBe(segmentTest);
49
+ });
50
+ });