@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
@@ -0,0 +1,159 @@
1
+ import type { ProjectConfig } from "../config";
2
+ import { getTargetZodSchema } from "./targetSchema";
3
+
4
+ function minimalProjectConfig(overrides: Partial<ProjectConfig> = {}): ProjectConfig {
5
+ return {
6
+ featuresDirectoryPath: "",
7
+ segmentsDirectoryPath: "",
8
+ attributesDirectoryPath: "",
9
+ groupsDirectoryPath: "",
10
+ schemasDirectoryPath: "",
11
+ targetsDirectoryPath: "",
12
+ testsDirectoryPath: "",
13
+ stateDirectoryPath: "",
14
+ datafilesDirectoryPath: "",
15
+ datafileNamePattern: "",
16
+ revisionFileName: "",
17
+ catalogDirectoryPath: "",
18
+ setsDirectoryPath: "",
19
+ environments: ["staging", "production"],
20
+ sets: false,
21
+ namespaceCharacter: ".",
22
+ tags: ["all", "web", "mobile"],
23
+ adapter: {},
24
+ plugins: [],
25
+ defaultBucketBy: "userId",
26
+ parser: "yml",
27
+ prettyState: true,
28
+ prettyDatafile: false,
29
+ stringify: true,
30
+ ...overrides,
31
+ };
32
+ }
33
+
34
+ function parseTarget(input: unknown) {
35
+ return getTargetZodSchema(minimalProjectConfig()).safeParse(input);
36
+ }
37
+
38
+ describe("targetSchema.ts :: getTargetZodSchema", () => {
39
+ it("accepts a valid target", () => {
40
+ const result = parseTarget({
41
+ description: "Web target",
42
+ tags: { and: ["all", "web"] },
43
+ context: { device: "desktop" },
44
+ promotable: true,
45
+ });
46
+
47
+ expect(result.success).toBe(true);
48
+ });
49
+
50
+ it("accepts a single tag", () => {
51
+ const result = parseTarget({
52
+ description: "Web target",
53
+ tag: "web",
54
+ });
55
+
56
+ expect(result.success).toBe(true);
57
+ });
58
+
59
+ it("accepts feature patterns and the direct all-features wildcard", () => {
60
+ expect(
61
+ parseTarget({
62
+ description: "Selected features",
63
+ includeFeatures: ["checkout*", "account.profile"],
64
+ excludeFeatures: ["checkout.internal*"],
65
+ }).success,
66
+ ).toBe(true);
67
+
68
+ expect(
69
+ parseTarget({
70
+ description: "All features",
71
+ includeFeatures: "*",
72
+ }).success,
73
+ ).toBe(true);
74
+ });
75
+
76
+ it("rejects non-wildcard scalar feature selectors and empty pattern arrays", () => {
77
+ expect(
78
+ parseTarget({ description: "Scalar feature", includeFeatures: "checkout" }).success,
79
+ ).toBe(false);
80
+ expect(parseTarget({ description: "Empty include", includeFeatures: [] }).success).toBe(false);
81
+ expect(parseTarget({ description: "Empty exclude", excludeFeatures: [] }).success).toBe(false);
82
+ });
83
+
84
+ it("rejects empty tag selectors", () => {
85
+ expect(parseTarget({ description: "Empty tags", tags: [] }).success).toBe(false);
86
+ expect(parseTarget({ description: "Empty or", tags: { or: [] } }).success).toBe(false);
87
+ expect(parseTarget({ description: "Empty and", tags: { and: [] } }).success).toBe(false);
88
+ });
89
+
90
+ it("rejects malformed feature glob patterns", () => {
91
+ expect(parseTarget({ description: "Empty pattern", includeFeatures: [""] }).success).toBe(
92
+ false,
93
+ );
94
+ expect(parseTarget({ description: "Spaces", includeFeatures: [" checkout*"] }).success).toBe(
95
+ false,
96
+ );
97
+ expect(
98
+ parseTarget({ description: "Double wildcard", includeFeatures: ["checkout**"] }).success,
99
+ ).toBe(false);
100
+ });
101
+
102
+ it("rejects unknown single tag", () => {
103
+ const result = parseTarget({ description: "Unknown tag", tag: "unknown" });
104
+
105
+ expect(result.success).toBe(false);
106
+ if (!result.success) {
107
+ expect(result.error.issues.map((issue) => issue.message).join(" ")).toContain(
108
+ 'Unknown tag "unknown"',
109
+ );
110
+ }
111
+ });
112
+
113
+ it("rejects tag and tags together", () => {
114
+ const result = parseTarget({
115
+ description: "Too many tag selectors",
116
+ tag: "web",
117
+ tags: ["mobile"],
118
+ });
119
+
120
+ expect(result.success).toBe(false);
121
+ if (!result.success) {
122
+ expect(result.error.issues.map((issue) => issue.message).join(" ")).toContain(
123
+ 'Only one of "tag" or "tags" can be defined',
124
+ );
125
+ }
126
+ });
127
+
128
+ it("requires description", () => {
129
+ const result = parseTarget({ tags: ["all"] });
130
+
131
+ expect(result.success).toBe(false);
132
+ if (!result.success) {
133
+ expect(result.error.issues.map((issue) => issue.message).join(" ")).toContain("Required");
134
+ }
135
+ });
136
+
137
+ it("rejects unknown tags", () => {
138
+ const result = parseTarget({ description: "Unknown tag", tags: ["unknown"] });
139
+
140
+ expect(result.success).toBe(false);
141
+ if (!result.success) {
142
+ expect(result.error.issues.map((issue) => issue.message).join(" ")).toContain(
143
+ 'Unknown tag "unknown"',
144
+ );
145
+ }
146
+ });
147
+
148
+ it("rejects invalid tag shapes", () => {
149
+ const result = parseTarget({ description: "Invalid tags", tags: { xor: ["web"] } });
150
+
151
+ expect(result.success).toBe(false);
152
+ });
153
+
154
+ it("rejects non-boolean promotable", () => {
155
+ const result = parseTarget({ description: "Bad promotable", promotable: "no" });
156
+
157
+ expect(result.success).toBe(false);
158
+ });
159
+ });
@@ -0,0 +1,46 @@
1
+ import { z } from "zod";
2
+
3
+ import type { ProjectConfig } from "../config";
4
+ import { refineWithMessage } from "./zodHelpers";
5
+
6
+ const targetTagSchema = (projectConfig: ProjectConfig) =>
7
+ refineWithMessage(
8
+ z.string(),
9
+ (value) => projectConfig.tags.includes(value),
10
+ (value) => `Unknown tag "${value}"`,
11
+ );
12
+
13
+ export function getTargetZodSchema(projectConfig: ProjectConfig) {
14
+ const tagSchema = targetTagSchema(projectConfig);
15
+ const featurePatternSchema = z
16
+ .string()
17
+ .min(1)
18
+ .refine((value) => value.trim() === value, "Feature patterns cannot have surrounding spaces")
19
+ .refine((value) => !value.includes("**"), 'Use "*" for glob-like wildcard matching');
20
+ const featurePatternsSchema = z.union([z.literal("*"), z.array(featurePatternSchema).min(1)]);
21
+
22
+ return z
23
+ .object({
24
+ key: z.string().optional(),
25
+ promotable: z.boolean().optional(),
26
+ description: z.string({
27
+ error: (issue) => (issue.input === undefined ? "Required" : undefined),
28
+ }),
29
+ tag: tagSchema.optional(),
30
+ tags: z
31
+ .union([
32
+ z.array(tagSchema).min(1),
33
+ z.object({ or: z.array(tagSchema).min(1) }).strict(),
34
+ z.object({ and: z.array(tagSchema).min(1) }).strict(),
35
+ ])
36
+ .optional(),
37
+ includeFeatures: featurePatternsSchema.optional(),
38
+ excludeFeatures: featurePatternsSchema.optional(),
39
+ context: z.record(z.string(), z.unknown()).optional(),
40
+ })
41
+ .strict()
42
+ .refine((target) => !(target.tag && target.tags), {
43
+ message: 'Only one of "tag" or "tags" can be defined',
44
+ path: ["tags"],
45
+ });
46
+ }
@@ -11,15 +11,17 @@ function minimalProjectConfig(overrides: Partial<ProjectConfig> = {}): ProjectCo
11
11
  attributesDirectoryPath: "",
12
12
  groupsDirectoryPath: "",
13
13
  schemasDirectoryPath: "",
14
+ targetsDirectoryPath: "",
14
15
  testsDirectoryPath: "",
15
16
  stateDirectoryPath: "",
16
17
  datafilesDirectoryPath: "",
17
18
  datafileNamePattern: "",
18
19
  revisionFileName: "",
19
- siteExportDirectoryPath: "",
20
- environmentsDirectoryPath: "",
20
+ catalogDirectoryPath: "",
21
+ setsDirectoryPath: "",
21
22
  environments: ["staging", "production"],
22
- splitByEnvironment: false,
23
+ sets: false,
24
+ namespaceCharacter: ".",
23
25
  tags: ["all", "beta"],
24
26
  adapter: {},
25
27
  plugins: [],
@@ -33,7 +35,7 @@ function minimalProjectConfig(overrides: Partial<ProjectConfig> = {}): ProjectCo
33
35
  }
34
36
 
35
37
  function getSchema(projectConfig = minimalProjectConfig()) {
36
- return getTestsZodSchema(projectConfig, ["checkout"], ["desktop"]);
38
+ return getTestsZodSchema(projectConfig, ["checkout"], ["desktop"], ["web"]);
37
39
  }
38
40
 
39
41
  function parseTest(input: unknown): z.ZodSafeParseResult<unknown> {
@@ -77,7 +79,7 @@ describe("testSchema.ts :: getTestsZodSchema", () => {
77
79
  description: "feature assertion",
78
80
  at: "${{ score }}",
79
81
  environment: "staging",
80
- tag: "all",
82
+ target: "web",
81
83
  sticky: {
82
84
  flag: { checkout: "cached" },
83
85
  },
@@ -126,6 +128,38 @@ describe("testSchema.ts :: getTestsZodSchema", () => {
126
128
  });
127
129
  });
128
130
 
131
+ it("accepts matrix placeholders for target values", () => {
132
+ expectTestSuccess({
133
+ feature: "checkout",
134
+ assertions: [
135
+ {
136
+ matrix: {
137
+ target: ["web", "mobile"],
138
+ },
139
+ at: 1,
140
+ environment: "staging",
141
+ target: "${{ target }}",
142
+ },
143
+ ],
144
+ });
145
+ });
146
+
147
+ it("rejects unknown targets", () => {
148
+ expectTestFailure(
149
+ {
150
+ feature: "checkout",
151
+ assertions: [
152
+ {
153
+ at: 1,
154
+ environment: "staging",
155
+ target: "mobile",
156
+ },
157
+ ],
158
+ },
159
+ 'Unknown target "mobile"',
160
+ );
161
+ });
162
+
129
163
  it("rejects unknown environments with a precise path", () => {
130
164
  const error = expectTestFailure(
131
165
  {
@@ -145,6 +179,37 @@ describe("testSchema.ts :: getTestsZodSchema", () => {
145
179
  );
146
180
  });
147
181
 
182
+ it("rejects environment in assertions when environments are omitted", () => {
183
+ const schema = getSchema(minimalProjectConfig({ environments: undefined }));
184
+ const testSpec = {
185
+ feature: "checkout",
186
+ assertions: [
187
+ {
188
+ at: 1,
189
+ expectedToBeEnabled: true,
190
+ },
191
+ ],
192
+ };
193
+
194
+ expect(schema.safeParse(testSpec).success).toBe(true);
195
+
196
+ const result = schema.safeParse({
197
+ feature: "checkout",
198
+ assertions: [
199
+ {
200
+ at: 1,
201
+ environment: "staging",
202
+ expectedToBeEnabled: true,
203
+ },
204
+ ],
205
+ });
206
+
207
+ expect(result.success).toBe(false);
208
+ if (!result.success) {
209
+ expect(result.error.issues.length).toBeGreaterThan(0);
210
+ }
211
+ });
212
+
148
213
  it("rejects unknown feature and segment keys", () => {
149
214
  expectTestFailure(
150
215
  {
@@ -7,9 +7,8 @@ export function getTestsZodSchema(
7
7
  projectConfig: ProjectConfig,
8
8
  availableFeatureKeys: [string, ...string[]],
9
9
  availableSegmentKeys: [string, ...string[]],
10
+ availableTargetKeys: [string, ...string[]],
10
11
  ) {
11
- const scopeNames = projectConfig.scopes ? projectConfig.scopes.map((scope) => scope.name) : [];
12
-
13
12
  const matrixZodSchema = z.record(
14
13
  z.string(),
15
14
  z.array(
@@ -25,6 +24,7 @@ export function getTestsZodSchema(
25
24
 
26
25
  const segmentTestZodSchema = z
27
26
  .object({
27
+ promotable: z.boolean().optional(),
28
28
  segment: refineWithMessage(
29
29
  z.string(),
30
30
  (value) => availableSegmentKeys.includes(value),
@@ -45,6 +45,7 @@ export function getTestsZodSchema(
45
45
 
46
46
  const featureTestZodSchema = z
47
47
  .object({
48
+ promotable: z.boolean().optional(),
48
49
  feature: refineWithMessage(
49
50
  z.string(),
50
51
  (value) => availableFeatureKeys.includes(value),
@@ -83,15 +84,16 @@ export function getTestsZodSchema(
83
84
  (value) => `Unknown environment "${value}"`,
84
85
  )
85
86
  : z.never().optional(),
86
- tag: refineWithMessage(
87
- z.string(),
88
- (value) => projectConfig.tags.includes(value),
89
- (value) => `Unknown tag "${value}"`,
90
- ).optional(),
91
- scope: refineWithMessage(
87
+ target: refineWithMessage(
92
88
  z.string(),
93
- (value) => scopeNames.includes(value),
94
- (value) => `Unknown scope "${value}"`,
89
+ (value) => {
90
+ if (value.indexOf("${{") === 0) {
91
+ return true;
92
+ }
93
+
94
+ return availableTargetKeys.includes(value);
95
+ },
96
+ (value) => `Unknown target "${value}"`,
95
97
  ).optional(),
96
98
 
97
99
  // parent
@@ -0,0 +1,135 @@
1
+ import type { ParsedFeature } from "@featurevisor/types";
2
+
3
+ import { formatDatafileSize, listEntities, listProject } from "./index";
4
+
5
+ function createFeatureFixture(overrides: Partial<ParsedFeature> = {}): ParsedFeature {
6
+ return {
7
+ key: "untagged",
8
+ description: "Untagged feature",
9
+ bucketBy: "userId",
10
+ rules: {
11
+ staging: [{ key: "everyone", segments: "*", percentage: 100 }],
12
+ production: [{ key: "everyone", segments: "*", percentage: 100 }],
13
+ },
14
+ ...overrides,
15
+ };
16
+ }
17
+
18
+ describe("core: list", function () {
19
+ test("excludes features with missing tags when tag filter is provided", async function () {
20
+ const datasource = {
21
+ listFeatures: async () => ["untagged"],
22
+ readFeature: async () => createFeatureFixture(),
23
+ };
24
+
25
+ const result = await listEntities<ParsedFeature>(
26
+ {
27
+ rootDirectoryPath: "",
28
+ projectConfig: {} as any,
29
+ datasource: datasource as any,
30
+ options: {
31
+ tag: "all",
32
+ },
33
+ },
34
+ "feature",
35
+ );
36
+
37
+ expect(result).toEqual([]);
38
+ });
39
+
40
+ test("lists the union of features selected by repeated targets", async function () {
41
+ const featureFixtures = {
42
+ web: createFeatureFixture({ key: "web", tags: ["web"] }),
43
+ mobile: createFeatureFixture({ key: "mobile", tags: ["mobile"] }),
44
+ internal: createFeatureFixture({ key: "internal", tags: ["internal"] }),
45
+ };
46
+ const datasource = {
47
+ listFeatures: async () => Object.keys(featureFixtures),
48
+ readFeature: async (key: keyof typeof featureFixtures) => featureFixtures[key],
49
+ listTargets: async () => ["web", "mobile"],
50
+ readTarget: async (key: string) => ({ description: key, tag: key }),
51
+ };
52
+
53
+ const result = await listEntities<ParsedFeature>(
54
+ {
55
+ rootDirectoryPath: "",
56
+ projectConfig: {} as any,
57
+ datasource: datasource as any,
58
+ options: { target: ["web", "mobile"] },
59
+ },
60
+ "feature",
61
+ );
62
+
63
+ expect(result.map((feature) => feature.key).sort()).toEqual(["mobile", "web"]);
64
+ });
65
+
66
+ test("lists generated datafiles", async function () {
67
+ const log = jest.spyOn(console, "log").mockImplementation();
68
+ const datasource = {
69
+ listDatafiles: async () => [
70
+ { path: "production/featurevisor-all.json", size: 42, gzipSize: 62 },
71
+ ],
72
+ };
73
+
74
+ await listProject({
75
+ rootDirectoryPath: "",
76
+ projectConfig: {} as any,
77
+ datasource: datasource as any,
78
+ options: { datafiles: true, json: true },
79
+ });
80
+
81
+ expect(log).toHaveBeenCalledWith(
82
+ '[{"path":"production/featurevisor-all.json","size":42,"gzipSize":62}]',
83
+ );
84
+ log.mockRestore();
85
+ });
86
+
87
+ test("formats datafile sizes with colored units", function () {
88
+ expect(formatDatafileSize(42)).toBe("42.00 \u001b[33mB\u001b[0m");
89
+ expect(formatDatafileSize(1024)).toBe("1.00 \u001b[36mkB\u001b[0m");
90
+ expect(formatDatafileSize(1024 * 1024)).toBe("1.00 \u001b[32mmB\u001b[0m");
91
+ });
92
+
93
+ test("prints datafiles in aligned columns", async function () {
94
+ const log = jest.spyOn(console, "log").mockImplementation();
95
+ const datasource = {
96
+ listDatafiles: async () => [
97
+ { path: "production/featurevisor-all.json", size: 1024 * 1024, gzipSize: 1024 },
98
+ { path: "staging/featurevisor-checkout.json", size: 42, gzipSize: 24 },
99
+ { path: "development/featurevisor-all.json", size: 1024, gzipSize: 512 },
100
+ ],
101
+ };
102
+
103
+ await listProject({
104
+ rootDirectoryPath: "",
105
+ projectConfig: {} as any,
106
+ datasource: datasource as any,
107
+ options: { datafiles: true },
108
+ });
109
+
110
+ const output = log.mock.calls.map(([message]) => message).join("\n");
111
+ const uncoloredOutput = output.replace(/\u001b\[[0-9;]*m/g, "");
112
+
113
+ expect(uncoloredOutput).toContain("Datafile");
114
+ expect(uncoloredOutput).toContain("Size");
115
+ expect(uncoloredOutput).toContain("Gzip");
116
+ expect(uncoloredOutput).toContain("production/featurevisor-all.json");
117
+ expect(uncoloredOutput).toContain("staging/featurevisor-checkout.json");
118
+ expect(uncoloredOutput.indexOf("development/featurevisor-all.json")).toBeLessThan(
119
+ uncoloredOutput.indexOf("staging/featurevisor-checkout.json"),
120
+ );
121
+ expect(uncoloredOutput.indexOf("staging/featurevisor-checkout.json")).toBeLessThan(
122
+ uncoloredOutput.indexOf("production/featurevisor-all.json"),
123
+ );
124
+ expect(uncoloredOutput).toMatch(/development\/featurevisor-all\.json\s+1\.00 kB/);
125
+ expect(uncoloredOutput).toMatch(/development\/featurevisor-all\.json\s+1\.00 kB\s+512\.00 B/);
126
+ expect(uncoloredOutput).toMatch(/staging\/featurevisor-checkout\.json\s+42\.00 B/);
127
+ expect(uncoloredOutput).toMatch(/production\/featurevisor-all\.json\s+1\.00 mB/);
128
+ expect(uncoloredOutput).toContain("512.00 B\n\n staging/");
129
+ expect(uncoloredOutput).toContain("24.00 B\n\n production/");
130
+ expect(output).toContain("\u001b[36mkB\u001b[0m");
131
+ expect(output).toContain("\u001b[33mB\u001b[0m");
132
+ expect(output).toContain("\u001b[32mmB\u001b[0m");
133
+ log.mockRestore();
134
+ });
135
+ });