@featurevisor/core 2.27.0 → 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 (389) hide show
  1. package/coverage/clover.xml +4991 -3130
  2. package/coverage/coverage-final.json +63 -39
  3. package/coverage/lcov-report/block-navigation.js +1 -1
  4. package/coverage/lcov-report/index.html +248 -98
  5. package/coverage/lcov-report/sorter.js +21 -7
  6. package/coverage/lcov-report/src/assess-distribution/index.html +116 -0
  7. package/coverage/lcov-report/src/assess-distribution/index.ts.html +754 -0
  8. package/coverage/lcov-report/{list → src/benchmark}/index.html +30 -30
  9. package/coverage/lcov-report/src/benchmark/index.ts.html +793 -0
  10. package/coverage/lcov-report/{builder → src/builder}/allocator.ts.html +38 -38
  11. package/coverage/lcov-report/{builder/buildScopedConditions.ts.html → src/builder/applyContextToConditions.ts.html} +80 -65
  12. package/coverage/lcov-report/{builder/buildScopedDatafile.ts.html → src/builder/applyContextToDatafile.ts.html} +92 -92
  13. package/coverage/lcov-report/{builder/buildScopedSegments.ts.html → src/builder/applyContextToSegments.ts.html} +103 -67
  14. package/coverage/lcov-report/{builder → src/builder}/buildDatafile.ts.html +336 -306
  15. package/coverage/lcov-report/src/builder/buildProject.ts.html +1117 -0
  16. package/coverage/lcov-report/src/builder/buildRuntimeDatafiles.ts.html +256 -0
  17. package/coverage/lcov-report/{builder → src/builder}/getFeatureRanges.ts.html +22 -22
  18. package/coverage/lcov-report/{builder → src/builder}/hashes.ts.html +50 -50
  19. package/coverage/lcov-report/{builder → src/builder}/index.html +114 -84
  20. package/coverage/lcov-report/{tester/cliFormat.ts.html → src/builder/index.ts.html} +17 -29
  21. package/coverage/lcov-report/{builder → src/builder}/mutateVariables.ts.html +55 -55
  22. package/coverage/lcov-report/{builder → src/builder}/mutator.ts.html +118 -118
  23. package/coverage/lcov-report/{builder → src/builder}/revision.ts.html +15 -15
  24. package/coverage/lcov-report/{builder → src/builder}/traffic.ts.html +86 -86
  25. package/coverage/lcov-report/src/cli/cli.ts.html +400 -0
  26. package/coverage/lcov-report/{tester → src/cli}/index.html +41 -41
  27. package/coverage/lcov-report/src/cli/plugins.ts.html +214 -0
  28. package/coverage/lcov-report/{config → src/config}/index.html +31 -31
  29. package/coverage/lcov-report/{config → src/config}/index.ts.html +12 -12
  30. package/coverage/lcov-report/{config → src/config}/projectConfig.ts.html +312 -96
  31. package/coverage/lcov-report/{datasource → src/datasource}/adapter.ts.html +28 -73
  32. package/coverage/lcov-report/{datasource → src/datasource}/datasource.ts.html +191 -104
  33. package/coverage/lcov-report/{datasource → src/datasource}/filesystemAdapter.ts.html +233 -635
  34. package/coverage/lcov-report/{datasource → src/datasource}/index.html +48 -48
  35. package/coverage/lcov-report/{datasource → src/datasource}/index.ts.html +14 -14
  36. package/coverage/lcov-report/src/evaluate/index.html +116 -0
  37. package/coverage/lcov-report/src/evaluate/index.ts.html +814 -0
  38. package/coverage/lcov-report/src/find-duplicate-segments/findDuplicateSegments.ts.html +313 -0
  39. package/coverage/lcov-report/src/find-duplicate-segments/index.html +131 -0
  40. package/coverage/lcov-report/src/find-duplicate-segments/index.ts.html +307 -0
  41. package/coverage/lcov-report/src/find-usage/index.html +116 -0
  42. package/coverage/lcov-report/src/find-usage/index.ts.html +1780 -0
  43. package/coverage/lcov-report/src/generate-code/index.html +131 -0
  44. package/coverage/lcov-report/src/generate-code/index.ts.html +403 -0
  45. package/coverage/lcov-report/{generate-code → src/generate-code}/typescript.ts.html +266 -1361
  46. package/coverage/lcov-report/{generate-code → src}/index.html +38 -23
  47. package/coverage/lcov-report/src/info/index.html +116 -0
  48. package/coverage/lcov-report/src/info/index.ts.html +472 -0
  49. package/coverage/lcov-report/src/init/index.html +116 -0
  50. package/coverage/lcov-report/src/init/index.ts.html +280 -0
  51. package/coverage/lcov-report/{linter → src/linter}/attributeSchema.ts.html +160 -157
  52. package/coverage/lcov-report/{linter → src/linter}/checkCircularDependency.ts.html +25 -25
  53. package/coverage/lcov-report/{linter → src/linter}/checkPercentageExceedingSlot.ts.html +42 -42
  54. package/coverage/lcov-report/{linter → src/linter}/conditionSchema.ts.html +207 -207
  55. package/coverage/lcov-report/{linter → src/linter}/featureSchema.ts.html +462 -471
  56. package/coverage/lcov-report/{linter → src/linter}/groupSchema.ts.html +25 -22
  57. package/coverage/lcov-report/{linter → src/linter}/index.html +129 -99
  58. package/coverage/lcov-report/src/linter/index.ts.html +88 -0
  59. package/coverage/lcov-report/{linter → src/linter}/lintProject.ts.html +740 -332
  60. package/coverage/lcov-report/{linter → src/linter}/mutationNotation.ts.html +130 -130
  61. package/coverage/lcov-report/{linter → src/linter}/printError.ts.html +27 -27
  62. package/coverage/lcov-report/{linter → src/linter}/schema.ts.html +153 -150
  63. package/coverage/lcov-report/{linter → src/linter}/segmentSchema.ts.html +18 -15
  64. package/coverage/lcov-report/src/linter/targetSchema.ts.html +223 -0
  65. package/coverage/lcov-report/{linter → src/linter}/testSchema.ts.html +54 -48
  66. package/coverage/lcov-report/{linter → src/linter}/zodHelpers.ts.html +17 -17
  67. package/coverage/lcov-report/src/list/index.html +131 -0
  68. package/coverage/lcov-report/src/list/index.ts.html +2065 -0
  69. package/coverage/lcov-report/{list → src/list}/matrix.ts.html +43 -58
  70. package/coverage/lcov-report/src/promoter/index.html +116 -0
  71. package/coverage/lcov-report/src/promoter/index.ts.html +3883 -0
  72. package/coverage/lcov-report/src/sets.ts.html +313 -0
  73. package/coverage/lcov-report/src/targeting.ts.html +403 -0
  74. package/coverage/lcov-report/src/tester/cliFormat.ts.html +133 -0
  75. package/coverage/lcov-report/{tester → src/tester}/helpers.ts.html +15 -15
  76. package/coverage/lcov-report/src/tester/index.html +206 -0
  77. package/coverage/lcov-report/src/tester/prettyDuration.ts.html +187 -0
  78. package/coverage/lcov-report/src/tester/printTestResult.ts.html +337 -0
  79. package/coverage/lcov-report/src/tester/testFeature.ts.html +1186 -0
  80. package/coverage/lcov-report/src/tester/testProject.ts.html +1018 -0
  81. package/coverage/lcov-report/src/tester/testSegment.ts.html +316 -0
  82. package/coverage/lcov-report/{utils → src/utils}/extractKeys.ts.html +68 -68
  83. package/coverage/lcov-report/{utils → src/utils}/git.ts.html +44 -68
  84. package/coverage/lcov-report/{utils → src/utils}/index.html +44 -44
  85. package/coverage/lcov-report/{utils → src/utils}/index.ts.html +14 -14
  86. package/coverage/lcov-report/{utils → src/utils}/pretty.ts.html +20 -20
  87. package/coverage/lcov.info +10121 -5723
  88. package/jest.config.js +13 -4
  89. package/lib/assess-distribution/index.d.ts +1 -1
  90. package/lib/assess-distribution/index.js +59 -40
  91. package/lib/assess-distribution/index.js.map +1 -1
  92. package/lib/benchmark/index.d.ts +8 -5
  93. package/lib/benchmark/index.js +82 -65
  94. package/lib/benchmark/index.js.map +1 -1
  95. package/lib/builder/applyContextToConditions.d.ts +5 -0
  96. package/lib/builder/{buildScopedConditions.js → applyContextToConditions.js} +19 -14
  97. package/lib/builder/applyContextToConditions.js.map +1 -0
  98. package/lib/builder/applyContextToDatafile.d.ts +2 -0
  99. package/lib/builder/{buildScopedDatafile.js → applyContextToDatafile.js} +26 -26
  100. package/lib/builder/applyContextToDatafile.js.map +1 -0
  101. package/lib/builder/applyContextToSegments.d.ts +5 -0
  102. package/lib/builder/{buildScopedSegments.js → applyContextToSegments.js} +19 -14
  103. package/lib/builder/applyContextToSegments.js.map +1 -0
  104. package/lib/builder/buildDatafile.d.ts +9 -6
  105. package/lib/builder/buildDatafile.js +86 -51
  106. package/lib/builder/buildDatafile.js.map +1 -1
  107. package/lib/builder/buildProject.d.ts +17 -3
  108. package/lib/builder/buildProject.js +151 -59
  109. package/lib/builder/buildProject.js.map +1 -1
  110. package/lib/builder/buildRuntimeDatafiles.d.ts +12 -0
  111. package/lib/builder/buildRuntimeDatafiles.js +35 -0
  112. package/lib/builder/buildRuntimeDatafiles.js.map +1 -0
  113. package/lib/builder/getFeatureRanges.js +34 -1
  114. package/lib/builder/getFeatureRanges.js.map +1 -1
  115. package/lib/builder/hashes.js +34 -1
  116. package/lib/builder/hashes.js.map +1 -1
  117. package/lib/builder/index.d.ts +0 -1
  118. package/lib/builder/index.js +0 -1
  119. package/lib/builder/index.js.map +1 -1
  120. package/lib/cli/cli.js +0 -4
  121. package/lib/cli/cli.js.map +1 -1
  122. package/lib/cli/plugins.js +7 -2
  123. package/lib/cli/plugins.js.map +1 -1
  124. package/lib/config/projectConfig.d.ts +17 -17
  125. package/lib/config/projectConfig.js +101 -15
  126. package/lib/config/projectConfig.js.map +1 -1
  127. package/lib/datasource/adapter.d.ts +7 -9
  128. package/lib/datasource/adapter.js +0 -7
  129. package/lib/datasource/adapter.js.map +1 -1
  130. package/lib/datasource/datasource.d.ts +15 -5
  131. package/lib/datasource/datasource.js +37 -9
  132. package/lib/datasource/datasource.js.map +1 -1
  133. package/lib/datasource/filesystemAdapter.d.ts +4 -10
  134. package/lib/datasource/filesystemAdapter.js +111 -149
  135. package/lib/datasource/filesystemAdapter.js.map +1 -1
  136. package/lib/evaluate/index.d.ts +1 -7
  137. package/lib/evaluate/index.js +81 -67
  138. package/lib/evaluate/index.js.map +1 -1
  139. package/lib/find-duplicate-segments/findDuplicateSegments.js +34 -1
  140. package/lib/find-duplicate-segments/findDuplicateSegments.js.map +1 -1
  141. package/lib/find-duplicate-segments/index.js +21 -13
  142. package/lib/find-duplicate-segments/index.js.map +1 -1
  143. package/lib/find-usage/index.js +57 -41
  144. package/lib/find-usage/index.js.map +1 -1
  145. package/lib/generate-code/index.d.ts +1 -1
  146. package/lib/generate-code/index.js +64 -21
  147. package/lib/generate-code/index.js.map +1 -1
  148. package/lib/generate-code/typescript.d.ts +1 -1
  149. package/lib/generate-code/typescript.js +59 -333
  150. package/lib/generate-code/typescript.js.map +1 -1
  151. package/lib/index.d.ts +2 -1
  152. package/lib/index.js +2 -1
  153. package/lib/index.js.map +1 -1
  154. package/lib/info/index.js +57 -16
  155. package/lib/info/index.js.map +1 -1
  156. package/lib/init/index.d.ts +2 -2
  157. package/lib/init/index.js +39 -3
  158. package/lib/init/index.js.map +1 -1
  159. package/lib/linter/attributeSchema.d.ts +1 -0
  160. package/lib/linter/attributeSchema.js +1 -0
  161. package/lib/linter/attributeSchema.js.map +1 -1
  162. package/lib/linter/conditionSchema.js +5 -5
  163. package/lib/linter/conditionSchema.js.map +1 -1
  164. package/lib/linter/featureSchema.d.ts +4 -1
  165. package/lib/linter/featureSchema.js +15 -13
  166. package/lib/linter/featureSchema.js.map +1 -1
  167. package/lib/linter/groupSchema.d.ts +1 -0
  168. package/lib/linter/groupSchema.js +1 -0
  169. package/lib/linter/groupSchema.js.map +1 -1
  170. package/lib/linter/lintProject.d.ts +1 -3
  171. package/lib/linter/lintProject.js +198 -68
  172. package/lib/linter/lintProject.js.map +1 -1
  173. package/lib/linter/schema.js +1 -0
  174. package/lib/linter/schema.js.map +1 -1
  175. package/lib/linter/segmentSchema.d.ts +1 -0
  176. package/lib/linter/segmentSchema.js +1 -0
  177. package/lib/linter/segmentSchema.js.map +1 -1
  178. package/lib/linter/targetSchema.d.ts +16 -0
  179. package/lib/linter/targetSchema.js +40 -0
  180. package/lib/linter/targetSchema.js.map +1 -0
  181. package/lib/linter/testSchema.d.ts +4 -3
  182. package/lib/linter/testSchema.js +9 -4
  183. package/lib/linter/testSchema.js.map +1 -1
  184. package/lib/list/index.d.ts +1 -0
  185. package/lib/list/index.js +131 -12
  186. package/lib/list/index.js.map +1 -1
  187. package/lib/list/matrix.js +3 -7
  188. package/lib/list/matrix.js.map +1 -1
  189. package/lib/promoter/index.d.ts +50 -0
  190. package/lib/promoter/index.js +880 -0
  191. package/lib/promoter/index.js.map +1 -0
  192. package/lib/sets.d.ts +11 -0
  193. package/lib/sets.js +81 -0
  194. package/lib/sets.js.map +1 -0
  195. package/lib/targeting.d.ts +14 -0
  196. package/lib/targeting.js +82 -0
  197. package/lib/targeting.js.map +1 -0
  198. package/lib/tester/cliFormat.d.ts +7 -1
  199. package/lib/tester/cliFormat.js +11 -2
  200. package/lib/tester/cliFormat.js.map +1 -1
  201. package/lib/tester/printTestResult.js +2 -2
  202. package/lib/tester/printTestResult.js.map +1 -1
  203. package/lib/tester/testFeature.d.ts +0 -1
  204. package/lib/tester/testFeature.js +8 -25
  205. package/lib/tester/testFeature.js.map +1 -1
  206. package/lib/tester/testProject.d.ts +2 -3
  207. package/lib/tester/testProject.js +93 -86
  208. package/lib/tester/testProject.js.map +1 -1
  209. package/lib/tester/testSegment.d.ts +1 -1
  210. package/lib/tester/testSegment.js +3 -21
  211. package/lib/tester/testSegment.js.map +1 -1
  212. package/lib/utils/git.js +45 -19
  213. package/lib/utils/git.js.map +1 -1
  214. package/package.json +12 -12
  215. package/src/assess-distribution/index.ts +72 -52
  216. package/src/benchmark/index.ts +124 -91
  217. package/src/builder/{buildScopedConditions.spec.ts → applyContextToConditions.spec.ts} +160 -142
  218. package/src/builder/{buildScopedConditions.ts → applyContextToConditions.ts} +19 -14
  219. package/src/builder/{buildScopedDatafile.spec.ts → applyContextToDatafile.spec.ts} +141 -81
  220. package/src/builder/{buildScopedDatafile.ts → applyContextToDatafile.ts} +33 -33
  221. package/src/builder/{buildScopedSegments.spec.ts → applyContextToSegments.spec.ts} +171 -151
  222. package/src/builder/{buildScopedSegments.ts → applyContextToSegments.ts} +26 -14
  223. package/src/builder/buildDatafile.spec.ts +192 -14
  224. package/src/builder/buildDatafile.ts +74 -64
  225. package/src/builder/buildProject.ts +171 -86
  226. package/src/builder/buildRuntimeDatafiles.ts +57 -0
  227. package/src/builder/index.ts +0 -1
  228. package/src/cli/cli.ts +0 -5
  229. package/src/cli/plugins.ts +7 -2
  230. package/src/config/projectConfig.spec.ts +171 -8
  231. package/src/config/projectConfig.ts +100 -28
  232. package/src/datasource/adapter.ts +8 -23
  233. package/src/datasource/datasource.ts +50 -21
  234. package/src/datasource/filesystemAdapter.spec.ts +133 -74
  235. package/src/datasource/filesystemAdapter.ts +93 -227
  236. package/src/evaluate/index.ts +109 -97
  237. package/src/find-duplicate-segments/index.ts +34 -16
  238. package/src/find-usage/index.ts +89 -44
  239. package/src/generate-code/index.ts +36 -24
  240. package/src/generate-code/typescript.spec.ts +106 -0
  241. package/src/generate-code/typescript.ts +33 -398
  242. package/src/index.ts +2 -1
  243. package/src/info/index.ts +72 -16
  244. package/src/init/index.ts +1 -1
  245. package/src/linter/attributeSchema.ts +1 -0
  246. package/src/linter/conditionSchema.spec.ts +23 -3
  247. package/src/linter/conditionSchema.ts +5 -5
  248. package/src/linter/featureSchema.spec.ts +107 -18
  249. package/src/linter/featureSchema.ts +25 -28
  250. package/src/linter/groupSchema.ts +1 -0
  251. package/src/linter/lintProject.spec.ts +131 -92
  252. package/src/linter/lintProject.ts +233 -97
  253. package/src/linter/schema.ts +1 -0
  254. package/src/linter/segmentSchema.spec.ts +5 -3
  255. package/src/linter/segmentSchema.ts +1 -0
  256. package/src/linter/targetSchema.spec.ts +159 -0
  257. package/src/linter/targetSchema.ts +46 -0
  258. package/src/linter/testSchema.spec.ts +70 -5
  259. package/src/linter/testSchema.ts +12 -10
  260. package/src/list/index.spec.ts +135 -0
  261. package/src/list/index.ts +188 -12
  262. package/src/list/matrix.ts +3 -8
  263. package/src/promoter/index.spec.ts +617 -0
  264. package/src/promoter/index.ts +1266 -0
  265. package/src/sets.ts +76 -0
  266. package/src/targeting.spec.ts +74 -0
  267. package/src/targeting.ts +106 -0
  268. package/src/tester/cliFormat.ts +11 -1
  269. package/src/tester/printTestResult.ts +12 -3
  270. package/src/tester/testFeature.ts +10 -36
  271. package/src/tester/testProject.spec.ts +50 -0
  272. package/src/tester/testProject.ts +89 -140
  273. package/src/tester/testSegment.ts +5 -22
  274. package/src/utils/git.ts +13 -21
  275. package/tsconfig.cjs.json +5 -1
  276. package/tsconfig.typecheck.json +9 -0
  277. package/coverage/lcov-report/builder/convertToV1.ts.html +0 -583
  278. package/lib/builder/allocator.spec.d.ts +0 -1
  279. package/lib/builder/allocator.spec.js +0 -85
  280. package/lib/builder/allocator.spec.js.map +0 -1
  281. package/lib/builder/buildDatafile.spec.d.ts +0 -1
  282. package/lib/builder/buildDatafile.spec.js +0 -233
  283. package/lib/builder/buildDatafile.spec.js.map +0 -1
  284. package/lib/builder/buildScopedConditions.d.ts +0 -5
  285. package/lib/builder/buildScopedConditions.js.map +0 -1
  286. package/lib/builder/buildScopedConditions.spec.d.ts +0 -1
  287. package/lib/builder/buildScopedConditions.spec.js +0 -2167
  288. package/lib/builder/buildScopedConditions.spec.js.map +0 -1
  289. package/lib/builder/buildScopedDatafile.d.ts +0 -2
  290. package/lib/builder/buildScopedDatafile.js.map +0 -1
  291. package/lib/builder/buildScopedDatafile.spec.d.ts +0 -1
  292. package/lib/builder/buildScopedDatafile.spec.js +0 -2277
  293. package/lib/builder/buildScopedDatafile.spec.js.map +0 -1
  294. package/lib/builder/buildScopedSegments.d.ts +0 -5
  295. package/lib/builder/buildScopedSegments.js.map +0 -1
  296. package/lib/builder/buildScopedSegments.spec.d.ts +0 -1
  297. package/lib/builder/buildScopedSegments.spec.js +0 -1062
  298. package/lib/builder/buildScopedSegments.spec.js.map +0 -1
  299. package/lib/builder/convertToV1.d.ts +0 -10
  300. package/lib/builder/convertToV1.js +0 -119
  301. package/lib/builder/convertToV1.js.map +0 -1
  302. package/lib/builder/mutateVariables.spec.d.ts +0 -1
  303. package/lib/builder/mutateVariables.spec.js +0 -1074
  304. package/lib/builder/mutateVariables.spec.js.map +0 -1
  305. package/lib/builder/mutator.spec.d.ts +0 -1
  306. package/lib/builder/mutator.spec.js +0 -368
  307. package/lib/builder/mutator.spec.js.map +0 -1
  308. package/lib/builder/revision.spec.d.ts +0 -1
  309. package/lib/builder/revision.spec.js +0 -21
  310. package/lib/builder/revision.spec.js.map +0 -1
  311. package/lib/builder/traffic.spec.d.ts +0 -1
  312. package/lib/builder/traffic.spec.js +0 -872
  313. package/lib/builder/traffic.spec.js.map +0 -1
  314. package/lib/config/projectConfig.spec.d.ts +0 -1
  315. package/lib/config/projectConfig.spec.js +0 -24
  316. package/lib/config/projectConfig.spec.js.map +0 -1
  317. package/lib/datasource/filesystemAdapter.spec.d.ts +0 -1
  318. package/lib/datasource/filesystemAdapter.spec.js +0 -88
  319. package/lib/datasource/filesystemAdapter.spec.js.map +0 -1
  320. package/lib/generate-code/typescript.spec.d.ts +0 -1
  321. package/lib/generate-code/typescript.spec.js +0 -78
  322. package/lib/generate-code/typescript.spec.js.map +0 -1
  323. package/lib/linter/attributeSchema.spec.d.ts +0 -1
  324. package/lib/linter/attributeSchema.spec.js +0 -266
  325. package/lib/linter/attributeSchema.spec.js.map +0 -1
  326. package/lib/linter/conditionSchema.spec.d.ts +0 -1
  327. package/lib/linter/conditionSchema.spec.js +0 -380
  328. package/lib/linter/conditionSchema.spec.js.map +0 -1
  329. package/lib/linter/featureSchema.spec.d.ts +0 -1
  330. package/lib/linter/featureSchema.spec.js +0 -1552
  331. package/lib/linter/featureSchema.spec.js.map +0 -1
  332. package/lib/linter/lintProject.spec.d.ts +0 -1
  333. package/lib/linter/lintProject.spec.js +0 -211
  334. package/lib/linter/lintProject.spec.js.map +0 -1
  335. package/lib/linter/mutationNotation.spec.d.ts +0 -1
  336. package/lib/linter/mutationNotation.spec.js +0 -598
  337. package/lib/linter/mutationNotation.spec.js.map +0 -1
  338. package/lib/linter/schema.spec.d.ts +0 -1
  339. package/lib/linter/schema.spec.js +0 -535
  340. package/lib/linter/schema.spec.js.map +0 -1
  341. package/lib/linter/segmentSchema.spec.d.ts +0 -1
  342. package/lib/linter/segmentSchema.spec.js +0 -303
  343. package/lib/linter/segmentSchema.spec.js.map +0 -1
  344. package/lib/linter/testSchema.spec.d.ts +0 -1
  345. package/lib/linter/testSchema.spec.js +0 -162
  346. package/lib/linter/testSchema.spec.js.map +0 -1
  347. package/lib/list/matrix.spec.d.ts +0 -1
  348. package/lib/list/matrix.spec.js +0 -42
  349. package/lib/list/matrix.spec.js.map +0 -1
  350. package/lib/site/exportSite.d.ts +0 -2
  351. package/lib/site/exportSite.js +0 -30
  352. package/lib/site/exportSite.js.map +0 -1
  353. package/lib/site/generateHistory.d.ts +0 -3
  354. package/lib/site/generateHistory.js +0 -31
  355. package/lib/site/generateHistory.js.map +0 -1
  356. package/lib/site/generateSiteSearchIndex.d.ts +0 -4
  357. package/lib/site/generateSiteSearchIndex.js +0 -195
  358. package/lib/site/generateSiteSearchIndex.js.map +0 -1
  359. package/lib/site/getLastModifiedFromHistory.d.ts +0 -2
  360. package/lib/site/getLastModifiedFromHistory.js +0 -18
  361. package/lib/site/getLastModifiedFromHistory.js.map +0 -1
  362. package/lib/site/getOwnerAndRepoFromUrl.d.ts +0 -4
  363. package/lib/site/getOwnerAndRepoFromUrl.js +0 -20
  364. package/lib/site/getOwnerAndRepoFromUrl.js.map +0 -1
  365. package/lib/site/getRelativePaths.d.ts +0 -6
  366. package/lib/site/getRelativePaths.js +0 -15
  367. package/lib/site/getRelativePaths.js.map +0 -1
  368. package/lib/site/getRepoDetails.d.ts +0 -8
  369. package/lib/site/getRepoDetails.js +0 -48
  370. package/lib/site/getRepoDetails.js.map +0 -1
  371. package/lib/site/index.d.ts +0 -2
  372. package/lib/site/index.js +0 -43
  373. package/lib/site/index.js.map +0 -1
  374. package/lib/site/serveSite.d.ts +0 -2
  375. package/lib/site/serveSite.js +0 -54
  376. package/lib/site/serveSite.js.map +0 -1
  377. package/lib/tester/helpers.spec.d.ts +0 -1
  378. package/lib/tester/helpers.spec.js +0 -115
  379. package/lib/tester/helpers.spec.js.map +0 -1
  380. package/src/builder/convertToV1.ts +0 -166
  381. package/src/site/exportSite.ts +0 -42
  382. package/src/site/generateHistory.ts +0 -40
  383. package/src/site/generateSiteSearchIndex.ts +0 -258
  384. package/src/site/getLastModifiedFromHistory.ts +0 -21
  385. package/src/site/getOwnerAndRepoFromUrl.ts +0 -17
  386. package/src/site/getRelativePaths.ts +0 -24
  387. package/src/site/getRepoDetails.ts +0 -62
  388. package/src/site/index.ts +0 -46
  389. 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
+ });