@featurevisor/core 2.17.0 → 2.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/coverage/clover.xml +1692 -1196
  3. package/coverage/coverage-final.json +29 -22
  4. package/coverage/lcov-report/builder/allocator.ts.html +26 -26
  5. package/coverage/lcov-report/builder/buildDatafile.ts.html +2017 -0
  6. package/coverage/lcov-report/builder/buildScopedConditions.ts.html +35 -35
  7. package/coverage/lcov-report/builder/buildScopedDatafile.ts.html +213 -45
  8. package/coverage/lcov-report/builder/buildScopedSegments.ts.html +28 -28
  9. package/coverage/lcov-report/builder/convertToV1.ts.html +583 -0
  10. package/coverage/lcov-report/builder/getFeatureRanges.ts.html +268 -0
  11. package/coverage/lcov-report/builder/hashes.ts.html +412 -0
  12. package/coverage/lcov-report/builder/index.html +90 -30
  13. package/coverage/lcov-report/builder/mutateVariables.ts.html +66 -45
  14. package/coverage/lcov-report/builder/mutator.ts.html +95 -95
  15. package/coverage/lcov-report/builder/revision.ts.html +1 -1
  16. package/coverage/lcov-report/builder/traffic.ts.html +60 -57
  17. package/coverage/lcov-report/config/index.html +1 -1
  18. package/coverage/lcov-report/config/index.ts.html +2 -2
  19. package/coverage/lcov-report/config/projectConfig.ts.html +28 -28
  20. package/coverage/lcov-report/datasource/adapter.ts.html +2 -2
  21. package/coverage/lcov-report/datasource/datasource.ts.html +4 -4
  22. package/coverage/lcov-report/datasource/filesystemAdapter.ts.html +34 -34
  23. package/coverage/lcov-report/datasource/index.html +1 -1
  24. package/coverage/lcov-report/datasource/index.ts.html +1 -1
  25. package/coverage/lcov-report/index.html +39 -39
  26. package/coverage/lcov-report/linter/attributeSchema.ts.html +1 -1
  27. package/coverage/lcov-report/linter/checkCircularDependency.ts.html +1 -1
  28. package/coverage/lcov-report/linter/checkPercentageExceedingSlot.ts.html +1 -1
  29. package/coverage/lcov-report/linter/conditionSchema.ts.html +17 -17
  30. package/coverage/lcov-report/linter/featureSchema.ts.html +879 -417
  31. package/coverage/lcov-report/linter/groupSchema.ts.html +1 -1
  32. package/coverage/lcov-report/linter/index.html +34 -34
  33. package/coverage/lcov-report/linter/lintProject.ts.html +25 -25
  34. package/coverage/lcov-report/linter/mutationNotation.ts.html +224 -122
  35. package/coverage/lcov-report/linter/printError.ts.html +1 -1
  36. package/coverage/lcov-report/linter/schema.ts.html +175 -85
  37. package/coverage/lcov-report/linter/segmentSchema.ts.html +1 -1
  38. package/coverage/lcov-report/linter/testSchema.ts.html +5 -5
  39. package/coverage/lcov-report/list/index.html +1 -1
  40. package/coverage/lcov-report/list/matrix.ts.html +1 -1
  41. package/coverage/lcov-report/parsers/index.html +1 -1
  42. package/coverage/lcov-report/parsers/index.ts.html +4 -4
  43. package/coverage/lcov-report/parsers/json.ts.html +2 -2
  44. package/coverage/lcov-report/parsers/yml.ts.html +6 -6
  45. package/coverage/lcov-report/tester/cliFormat.ts.html +1 -1
  46. package/coverage/lcov-report/tester/helpers.ts.html +1 -1
  47. package/coverage/lcov-report/tester/index.html +1 -1
  48. package/coverage/lcov-report/utils/extractKeys.ts.html +493 -0
  49. package/coverage/lcov-report/utils/git.ts.html +3 -3
  50. package/coverage/lcov-report/utils/index.html +54 -9
  51. package/coverage/lcov-report/utils/index.ts.html +94 -0
  52. package/coverage/lcov-report/utils/pretty.ts.html +121 -0
  53. package/coverage/lcov.info +3206 -2260
  54. package/json-schema/attribute.json +25 -9
  55. package/json-schema/feature.json +319 -238
  56. package/json-schema/segment.json +76 -45
  57. package/lib/builder/buildDatafile.js +50 -3
  58. package/lib/builder/buildDatafile.js.map +1 -1
  59. package/lib/builder/buildDatafile.spec.d.ts +1 -0
  60. package/lib/builder/buildDatafile.spec.js +233 -0
  61. package/lib/builder/buildDatafile.spec.js.map +1 -0
  62. package/lib/builder/buildScopedDatafile.js +37 -1
  63. package/lib/builder/buildScopedDatafile.js.map +1 -1
  64. package/lib/builder/buildScopedDatafile.spec.js +289 -0
  65. package/lib/builder/buildScopedDatafile.spec.js.map +1 -1
  66. package/lib/builder/mutateVariables.d.ts +1 -1
  67. package/lib/builder/mutateVariables.js +4 -1
  68. package/lib/builder/mutateVariables.js.map +1 -1
  69. package/lib/builder/mutateVariables.spec.js +29 -0
  70. package/lib/builder/mutateVariables.spec.js.map +1 -1
  71. package/lib/builder/traffic.js +1 -0
  72. package/lib/builder/traffic.js.map +1 -1
  73. package/lib/builder/traffic.spec.js +26 -0
  74. package/lib/builder/traffic.spec.js.map +1 -1
  75. package/lib/generate-code/typescript.js +63 -20
  76. package/lib/generate-code/typescript.js.map +1 -1
  77. package/lib/linter/featureSchema.d.ts +237 -22
  78. package/lib/linter/featureSchema.js +175 -84
  79. package/lib/linter/featureSchema.js.map +1 -1
  80. package/lib/linter/featureSchema.spec.js +268 -0
  81. package/lib/linter/featureSchema.spec.js.map +1 -1
  82. package/lib/linter/mutationNotation.js +54 -19
  83. package/lib/linter/mutationNotation.js.map +1 -1
  84. package/lib/linter/mutationNotation.spec.js +49 -0
  85. package/lib/linter/mutationNotation.spec.js.map +1 -1
  86. package/lib/linter/schema.d.ts +1 -0
  87. package/lib/linter/schema.js +13 -0
  88. package/lib/linter/schema.js.map +1 -1
  89. package/lib/linter/schema.spec.js +51 -0
  90. package/lib/linter/schema.spec.js.map +1 -1
  91. package/package.json +5 -5
  92. package/src/builder/buildDatafile.spec.ts +267 -0
  93. package/src/builder/buildDatafile.ts +85 -4
  94. package/src/builder/buildScopedDatafile.spec.ts +330 -0
  95. package/src/builder/buildScopedDatafile.ts +57 -1
  96. package/src/builder/mutateVariables.spec.ts +45 -0
  97. package/src/builder/mutateVariables.ts +7 -0
  98. package/src/builder/traffic.spec.ts +33 -0
  99. package/src/builder/traffic.ts +1 -0
  100. package/src/generate-code/typescript.ts +87 -20
  101. package/src/linter/featureSchema.spec.ts +315 -0
  102. package/src/linter/featureSchema.ts +269 -115
  103. package/src/linter/mutationNotation.spec.ts +62 -0
  104. package/src/linter/mutationNotation.ts +47 -13
  105. package/src/linter/schema.spec.ts +72 -0
  106. package/src/linter/schema.ts +30 -0
@@ -23,16 +23,16 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">88.96% </span>
26
+ <span class="strong">85.79% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>129/145</span>
28
+ <span class='fraction'>145/169</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">78.62% </span>
33
+ <span class="strong">77.07% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>103/131</span>
35
+ <span class='fraction'>121/157</span>
36
36
  </div>
37
37
 
38
38
 
@@ -44,9 +44,9 @@
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">95.96% </span>
47
+ <span class="strong">93.1% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>119/124</span>
49
+ <span class='fraction'>135/145</span>
50
50
  </div>
51
51
 
52
52
 
@@ -471,7 +471,41 @@
471
471
  <a name='L406'></a><a href='#L406'>406</a>
472
472
  <a name='L407'></a><a href='#L407'>407</a>
473
473
  <a name='L408'></a><a href='#L408'>408</a>
474
- <a name='L409'></a><a href='#L409'>409</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
474
+ <a name='L409'></a><a href='#L409'>409</a>
475
+ <a name='L410'></a><a href='#L410'>410</a>
476
+ <a name='L411'></a><a href='#L411'>411</a>
477
+ <a name='L412'></a><a href='#L412'>412</a>
478
+ <a name='L413'></a><a href='#L413'>413</a>
479
+ <a name='L414'></a><a href='#L414'>414</a>
480
+ <a name='L415'></a><a href='#L415'>415</a>
481
+ <a name='L416'></a><a href='#L416'>416</a>
482
+ <a name='L417'></a><a href='#L417'>417</a>
483
+ <a name='L418'></a><a href='#L418'>418</a>
484
+ <a name='L419'></a><a href='#L419'>419</a>
485
+ <a name='L420'></a><a href='#L420'>420</a>
486
+ <a name='L421'></a><a href='#L421'>421</a>
487
+ <a name='L422'></a><a href='#L422'>422</a>
488
+ <a name='L423'></a><a href='#L423'>423</a>
489
+ <a name='L424'></a><a href='#L424'>424</a>
490
+ <a name='L425'></a><a href='#L425'>425</a>
491
+ <a name='L426'></a><a href='#L426'>426</a>
492
+ <a name='L427'></a><a href='#L427'>427</a>
493
+ <a name='L428'></a><a href='#L428'>428</a>
494
+ <a name='L429'></a><a href='#L429'>429</a>
495
+ <a name='L430'></a><a href='#L430'>430</a>
496
+ <a name='L431'></a><a href='#L431'>431</a>
497
+ <a name='L432'></a><a href='#L432'>432</a>
498
+ <a name='L433'></a><a href='#L433'>433</a>
499
+ <a name='L434'></a><a href='#L434'>434</a>
500
+ <a name='L435'></a><a href='#L435'>435</a>
501
+ <a name='L436'></a><a href='#L436'>436</a>
502
+ <a name='L437'></a><a href='#L437'>437</a>
503
+ <a name='L438'></a><a href='#L438'>438</a>
504
+ <a name='L439'></a><a href='#L439'>439</a>
505
+ <a name='L440'></a><a href='#L440'>440</a>
506
+ <a name='L441'></a><a href='#L441'>441</a>
507
+ <a name='L442'></a><a href='#L442'>442</a>
508
+ <a name='L443'></a><a href='#L443'>443</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
475
509
  <span class="cline-any cline-neutral">&nbsp;</span>
476
510
  <span class="cline-any cline-yes">3x</span>
477
511
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -491,8 +525,8 @@
491
525
  <span class="cline-any cline-neutral">&nbsp;</span>
492
526
  <span class="cline-any cline-neutral">&nbsp;</span>
493
527
  <span class="cline-any cline-yes">3x</span>
494
- <span class="cline-any cline-yes">689x</span>
495
- <span class="cline-any cline-yes">689x</span>
528
+ <span class="cline-any cline-yes">858x</span>
529
+ <span class="cline-any cline-yes">858x</span>
496
530
  <span class="cline-any cline-neutral">&nbsp;</span>
497
531
  <span class="cline-any cline-neutral">&nbsp;</span>
498
532
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -501,22 +535,22 @@
501
535
  <span class="cline-any cline-neutral">&nbsp;</span>
502
536
  <span class="cline-any cline-neutral">&nbsp;</span>
503
537
  <span class="cline-any cline-yes">3x</span>
504
- <span class="cline-any cline-yes">160x</span>
505
- <span class="cline-any cline-yes">160x</span>
538
+ <span class="cline-any cline-yes">227x</span>
539
+ <span class="cline-any cline-yes">227x</span>
506
540
  <span class="cline-any cline-neutral">&nbsp;</span>
507
- <span class="cline-any cline-yes">155x</span>
508
- <span class="cline-any cline-yes">155x</span>
509
- <span class="cline-any cline-yes">155x</span>
541
+ <span class="cline-any cline-yes">222x</span>
542
+ <span class="cline-any cline-yes">222x</span>
543
+ <span class="cline-any cline-yes">222x</span>
510
544
  <span class="cline-any cline-neutral">&nbsp;</span>
511
- <span class="cline-any cline-yes">155x</span>
545
+ <span class="cline-any cline-yes">222x</span>
512
546
  <span class="cline-any cline-neutral">&nbsp;</span>
513
547
  <span class="cline-any cline-neutral">&nbsp;</span>
514
548
  <span class="cline-any cline-neutral">&nbsp;</span>
515
549
  <span class="cline-any cline-neutral">&nbsp;</span>
516
550
  <span class="cline-any cline-neutral">&nbsp;</span>
517
551
  <span class="cline-any cline-neutral">&nbsp;</span>
518
- <span class="cline-any cline-yes">155x</span>
519
- <span class="cline-any cline-yes">155x</span>
552
+ <span class="cline-any cline-yes">222x</span>
553
+ <span class="cline-any cline-yes">222x</span>
520
554
  <span class="cline-any cline-neutral">&nbsp;</span>
521
555
  <span class="cline-any cline-neutral">&nbsp;</span>
522
556
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -527,18 +561,18 @@
527
561
  <span class="cline-any cline-neutral">&nbsp;</span>
528
562
  <span class="cline-any cline-neutral">&nbsp;</span>
529
563
  <span class="cline-any cline-neutral">&nbsp;</span>
530
- <span class="cline-any cline-yes">701x</span>
531
- <span class="cline-any cline-yes">699x</span>
532
- <span class="cline-any cline-yes">84x</span>
564
+ <span class="cline-any cline-yes">1329x</span>
565
+ <span class="cline-any cline-yes">1327x</span>
566
+ <span class="cline-any cline-yes">104x</span>
533
567
  <span class="cline-any cline-neutral">&nbsp;</span>
534
- <span class="cline-any cline-yes">615x</span>
568
+ <span class="cline-any cline-yes">1223x</span>
535
569
  <span class="cline-any cline-neutral">&nbsp;</span>
536
570
  <span class="cline-any cline-neutral">&nbsp;</span>
537
571
  <span class="cline-any cline-neutral">&nbsp;</span>
538
572
  <span class="cline-any cline-neutral">&nbsp;</span>
539
573
  <span class="cline-any cline-neutral">&nbsp;</span>
540
574
  <span class="cline-any cline-neutral">&nbsp;</span>
541
- <span class="cline-any cline-yes">382x</span>
575
+ <span class="cline-any cline-yes">768x</span>
542
576
  <span class="cline-any cline-neutral">&nbsp;</span>
543
577
  <span class="cline-any cline-neutral">&nbsp;</span>
544
578
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -553,29 +587,34 @@
553
587
  <span class="cline-any cline-neutral">&nbsp;</span>
554
588
  <span class="cline-any cline-neutral">&nbsp;</span>
555
589
  <span class="cline-any cline-neutral">&nbsp;</span>
556
- <span class="cline-any cline-yes">146x</span>
557
- <span class="cline-any cline-yes">146x</span>
590
+ <span class="cline-any cline-yes">214x</span>
591
+ <span class="cline-any cline-yes">214x</span>
558
592
  <span class="cline-any cline-neutral">&nbsp;</span>
559
- <span class="cline-any cline-yes">144x</span>
560
- <span class="cline-any cline-yes">182x</span>
561
- <span class="cline-any cline-yes">181x</span>
562
- <span class="cline-any cline-yes">154x</span>
563
- <span class="cline-any cline-yes">151x</span>
564
- <span class="cline-any cline-yes">151x</span>
565
- <span class="cline-any cline-yes">145x</span>
566
- <span class="cline-any cline-yes">145x</span>
567
- <span class="cline-any cline-yes">139x</span>
568
- <span class="cline-any cline-yes">139x</span>
593
+ <span class="cline-any cline-yes">212x</span>
594
+ <span class="cline-any cline-yes">301x</span>
595
+ <span class="cline-any cline-yes">300x</span>
596
+ <span class="cline-any cline-yes">273x</span>
597
+ <span class="cline-any cline-yes">270x</span>
598
+ <span class="cline-any cline-yes">270x</span>
599
+ <span class="cline-any cline-yes">270x</span>
600
+ <span class="cline-any cline-yes">270x</span>
601
+ <span class="cline-any cline-yes">9x</span>
602
+ <span class="cline-any cline-yes">2x</span>
603
+ <span class="cline-any cline-yes">2x</span>
604
+ <span class="cline-any cline-yes">2x</span>
605
+ <span class="cline-any cline-neutral">&nbsp;</span>
606
+ <span class="cline-any cline-yes">261x</span>
607
+ <span class="cline-any cline-yes">261x</span>
569
608
  <span class="cline-any cline-neutral">&nbsp;</span>
570
- <span class="cline-any cline-yes">166x</span>
571
- <span class="cline-any cline-yes">29x</span>
572
- <span class="cline-any cline-yes">28x</span>
573
- <span class="cline-any cline-yes">28x</span>
574
- <span class="cline-any cline-yes">28x</span>
575
- <span class="cline-any cline-yes">28x</span>
609
+ <span class="cline-any cline-yes">288x</span>
610
+ <span class="cline-any cline-yes">43x</span>
611
+ <span class="cline-any cline-yes">42x</span>
612
+ <span class="cline-any cline-yes">42x</span>
613
+ <span class="cline-any cline-yes">42x</span>
614
+ <span class="cline-any cline-yes">42x</span>
576
615
  <span class="cline-any cline-neutral">&nbsp;</span>
577
616
  <span class="cline-any cline-neutral">&nbsp;</span>
578
- <span class="cline-any cline-yes">127x</span>
617
+ <span class="cline-any cline-yes">200x</span>
579
618
  <span class="cline-any cline-neutral">&nbsp;</span>
580
619
  <span class="cline-any cline-neutral">&nbsp;</span>
581
620
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -588,44 +627,73 @@
588
627
  <span class="cline-any cline-neutral">&nbsp;</span>
589
628
  <span class="cline-any cline-neutral">&nbsp;</span>
590
629
  <span class="cline-any cline-neutral">&nbsp;</span>
591
- <span class="cline-any cline-yes">96x</span>
630
+ <span class="cline-any cline-yes">199x</span>
592
631
  <span class="cline-any cline-yes">10x</span>
593
632
  <span class="cline-any cline-yes">10x</span>
594
633
  <span class="cline-any cline-neutral">&nbsp;</span>
595
634
  <span class="cline-any cline-neutral">&nbsp;</span>
596
635
  <span class="cline-any cline-neutral">&nbsp;</span>
597
- <span class="cline-any cline-yes">86x</span>
598
- <span class="cline-any cline-yes">86x</span>
599
- <span class="cline-any cline-yes">86x</span>
600
- <span class="cline-any cline-yes">86x</span>
601
- <span class="cline-any cline-yes">86x</span>
602
- <span class="cline-any cline-yes">34x</span>
603
- <span class="cline-any cline-yes">34x</span>
604
- <span class="cline-any cline-yes">8x</span>
605
- <span class="cline-any cline-yes">6x</span>
636
+ <span class="cline-any cline-yes">189x</span>
637
+ <span class="cline-any cline-yes">189x</span>
638
+ <span class="cline-any cline-yes">189x</span>
639
+ <span class="cline-any cline-yes">189x</span>
640
+ <span class="cline-any cline-yes">189x</span>
641
+ <span class="cline-any cline-yes">100x</span>
642
+ <span class="cline-any cline-yes">100x</span>
643
+ <span class="cline-any cline-yes">90x</span>
644
+ <span class="cline-any cline-yes">90x</span>
645
+ <span class="cline-any cline-yes">90x</span>
646
+ <span class="cline-any cline-yes">90x</span>
647
+ <span class="cline-any cline-yes">90x</span>
648
+ <span class="cline-any cline-yes">1x</span>
649
+ <span class="cline-any cline-no">&nbsp;</span>
650
+ <span class="cline-any cline-no">&nbsp;</span>
651
+ <span class="cline-any cline-no">&nbsp;</span>
652
+ <span class="cline-any cline-neutral">&nbsp;</span>
653
+ <span class="cline-any cline-yes">89x</span>
654
+ <span class="cline-any cline-neutral">&nbsp;</span>
655
+ <span class="cline-any cline-yes">99x</span>
656
+ <span class="cline-any cline-yes">20x</span>
657
+ <span class="cline-any cline-yes">20x</span>
658
+ <span class="cline-any cline-yes">20x</span>
659
+ <span class="cline-any cline-yes">20x</span>
660
+ <span class="cline-any cline-neutral">&nbsp;</span>
661
+ <span class="cline-any cline-yes">99x</span>
662
+ <span class="cline-any cline-neutral">&nbsp;</span>
663
+ <span class="cline-any cline-yes">188x</span>
664
+ <span class="cline-any cline-yes">188x</span>
665
+ <span class="cline-any cline-yes">188x</span>
666
+ <span class="cline-any cline-yes">21x</span>
667
+ <span class="cline-any cline-yes">21x</span>
668
+ <span class="cline-any cline-yes">7x</span>
669
+ <span class="cline-any cline-yes">7x</span>
670
+ <span class="cline-any cline-yes">7x</span>
671
+ <span class="cline-any cline-yes">7x</span>
672
+ <span class="cline-any cline-yes">7x</span>
673
+ <span class="cline-any cline-yes">1x</span>
674
+ <span class="cline-any cline-no">&nbsp;</span>
675
+ <span class="cline-any cline-neutral">&nbsp;</span>
606
676
  <span class="cline-any cline-yes">6x</span>
677
+ <span class="cline-any cline-neutral">&nbsp;</span>
607
678
  <span class="cline-any cline-yes">6x</span>
608
679
  <span class="cline-any cline-neutral">&nbsp;</span>
609
- <span class="cline-any cline-yes">26x</span>
610
- <span class="cline-any cline-yes">26x</span>
611
- <span class="cline-any cline-yes">26x</span>
612
- <span class="cline-any cline-yes">26x</span>
613
- <span class="cline-any cline-yes">26x</span>
614
- <span class="cline-any cline-yes">26x</span>
615
680
  <span class="cline-any cline-neutral">&nbsp;</span>
616
- <span class="cline-any cline-yes">32x</span>
681
+ <span class="cline-any cline-yes">20x</span>
617
682
  <span class="cline-any cline-neutral">&nbsp;</span>
618
- <span class="cline-any cline-yes">84x</span>
619
- <span class="cline-any cline-yes">84x</span>
620
- <span class="cline-any cline-yes">84x</span>
621
- <span class="cline-any cline-yes">15x</span>
622
683
  <span class="cline-any cline-neutral">&nbsp;</span>
623
- <span class="cline-any cline-yes">69x</span>
684
+ <span class="cline-any cline-yes">20x</span>
624
685
  <span class="cline-any cline-neutral">&nbsp;</span>
625
- <span class="cline-any cline-yes">69x</span>
626
686
  <span class="cline-any cline-neutral">&nbsp;</span>
627
687
  <span class="cline-any cline-neutral">&nbsp;</span>
628
- <span class="cline-any cline-yes">69x</span>
688
+ <span class="cline-any cline-neutral">&nbsp;</span>
689
+ <span class="cline-any cline-neutral">&nbsp;</span>
690
+ <span class="cline-any cline-neutral">&nbsp;</span>
691
+ <span class="cline-any cline-yes">167x</span>
692
+ <span class="cline-any cline-neutral">&nbsp;</span>
693
+ <span class="cline-any cline-yes">167x</span>
694
+ <span class="cline-any cline-neutral">&nbsp;</span>
695
+ <span class="cline-any cline-neutral">&nbsp;</span>
696
+ <span class="cline-any cline-yes">167x</span>
629
697
  <span class="cline-any cline-neutral">&nbsp;</span>
630
698
  <span class="cline-any cline-neutral">&nbsp;</span>
631
699
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -647,8 +715,8 @@
647
715
  <span class="cline-any cline-neutral">&nbsp;</span>
648
716
  <span class="cline-any cline-neutral">&nbsp;</span>
649
717
  <span class="cline-any cline-neutral">&nbsp;</span>
650
- <span class="cline-any cline-yes">101x</span>
651
- <span class="cline-any cline-yes">101x</span>
718
+ <span class="cline-any cline-yes">204x</span>
719
+ <span class="cline-any cline-yes">204x</span>
652
720
  <span class="cline-any cline-yes">1x</span>
653
721
  <span class="cline-any cline-neutral">&nbsp;</span>
654
722
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -658,8 +726,8 @@
658
726
  <span class="cline-any cline-neutral">&nbsp;</span>
659
727
  <span class="cline-any cline-neutral">&nbsp;</span>
660
728
  <span class="cline-any cline-neutral">&nbsp;</span>
661
- <span class="cline-any cline-yes">100x</span>
662
- <span class="cline-any cline-yes">100x</span>
729
+ <span class="cline-any cline-yes">203x</span>
730
+ <span class="cline-any cline-yes">203x</span>
663
731
  <span class="cline-any cline-yes">1x</span>
664
732
  <span class="cline-any cline-neutral">&nbsp;</span>
665
733
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -669,8 +737,8 @@
669
737
  <span class="cline-any cline-neutral">&nbsp;</span>
670
738
  <span class="cline-any cline-neutral">&nbsp;</span>
671
739
  <span class="cline-any cline-neutral">&nbsp;</span>
672
- <span class="cline-any cline-yes">99x</span>
673
- <span class="cline-any cline-yes">99x</span>
740
+ <span class="cline-any cline-yes">202x</span>
741
+ <span class="cline-any cline-yes">202x</span>
674
742
  <span class="cline-any cline-yes">2x</span>
675
743
  <span class="cline-any cline-neutral">&nbsp;</span>
676
744
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -680,8 +748,8 @@
680
748
  <span class="cline-any cline-neutral">&nbsp;</span>
681
749
  <span class="cline-any cline-neutral">&nbsp;</span>
682
750
  <span class="cline-any cline-neutral">&nbsp;</span>
683
- <span class="cline-any cline-yes">97x</span>
684
- <span class="cline-any cline-yes">97x</span>
751
+ <span class="cline-any cline-yes">200x</span>
752
+ <span class="cline-any cline-yes">200x</span>
685
753
  <span class="cline-any cline-neutral">&nbsp;</span>
686
754
  <span class="cline-any cline-no">&nbsp;</span>
687
755
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -698,7 +766,7 @@
698
766
  <span class="cline-any cline-neutral">&nbsp;</span>
699
767
  <span class="cline-any cline-neutral">&nbsp;</span>
700
768
  <span class="cline-any cline-neutral">&nbsp;</span>
701
- <span class="cline-any cline-yes">97x</span>
769
+ <span class="cline-any cline-yes">200x</span>
702
770
  <span class="cline-any cline-yes">1x</span>
703
771
  <span class="cline-any cline-neutral">&nbsp;</span>
704
772
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -709,13 +777,13 @@
709
777
  <span class="cline-any cline-neutral">&nbsp;</span>
710
778
  <span class="cline-any cline-neutral">&nbsp;</span>
711
779
  <span class="cline-any cline-neutral">&nbsp;</span>
712
- <span class="cline-any cline-yes">96x</span>
713
- <span class="cline-any cline-yes">96x</span>
780
+ <span class="cline-any cline-yes">199x</span>
781
+ <span class="cline-any cline-yes">199x</span>
714
782
  <span class="cline-any cline-neutral">&nbsp;</span>
715
- <span class="cline-any cline-yes">96x</span>
783
+ <span class="cline-any cline-yes">199x</span>
716
784
  <span class="cline-any cline-neutral">&nbsp;</span>
717
785
  <span class="cline-any cline-neutral">&nbsp;</span>
718
- <span class="cline-any cline-yes">13x</span>
786
+ <span class="cline-any cline-yes">25x</span>
719
787
  <span class="cline-any cline-yes">1x</span>
720
788
  <span class="cline-any cline-neutral">&nbsp;</span>
721
789
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -725,8 +793,8 @@
725
793
  <span class="cline-any cline-neutral">&nbsp;</span>
726
794
  <span class="cline-any cline-neutral">&nbsp;</span>
727
795
  <span class="cline-any cline-neutral">&nbsp;</span>
728
- <span class="cline-any cline-yes">12x</span>
729
- <span class="cline-any cline-yes">12x</span>
796
+ <span class="cline-any cline-yes">24x</span>
797
+ <span class="cline-any cline-yes">24x</span>
730
798
  <span class="cline-any cline-yes">2x</span>
731
799
  <span class="cline-any cline-neutral">&nbsp;</span>
732
800
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -736,7 +804,7 @@
736
804
  <span class="cline-any cline-neutral">&nbsp;</span>
737
805
  <span class="cline-any cline-neutral">&nbsp;</span>
738
806
  <span class="cline-any cline-neutral">&nbsp;</span>
739
- <span class="cline-any cline-yes">10x</span>
807
+ <span class="cline-any cline-yes">22x</span>
740
808
  <span class="cline-any cline-no">&nbsp;</span>
741
809
  <span class="cline-any cline-neutral">&nbsp;</span>
742
810
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -747,10 +815,10 @@
747
815
  <span class="cline-any cline-neutral">&nbsp;</span>
748
816
  <span class="cline-any cline-neutral">&nbsp;</span>
749
817
  <span class="cline-any cline-neutral">&nbsp;</span>
750
- <span class="cline-any cline-yes">10x</span>
818
+ <span class="cline-any cline-yes">22x</span>
751
819
  <span class="cline-any cline-neutral">&nbsp;</span>
752
820
  <span class="cline-any cline-neutral">&nbsp;</span>
753
- <span class="cline-any cline-yes">10x</span>
821
+ <span class="cline-any cline-yes">22x</span>
754
822
  <span class="cline-any cline-neutral">&nbsp;</span>
755
823
  <span class="cline-any cline-neutral">&nbsp;</span>
756
824
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -761,8 +829,8 @@
761
829
  <span class="cline-any cline-neutral">&nbsp;</span>
762
830
  <span class="cline-any cline-neutral">&nbsp;</span>
763
831
  <span class="cline-any cline-neutral">&nbsp;</span>
764
- <span class="cline-any cline-yes">17x</span>
765
- <span class="cline-any cline-yes">1x</span>
832
+ <span class="cline-any cline-yes">24x</span>
833
+ <span class="cline-any cline-yes">2x</span>
766
834
  <span class="cline-any cline-neutral">&nbsp;</span>
767
835
  <span class="cline-any cline-neutral">&nbsp;</span>
768
836
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -771,10 +839,10 @@
771
839
  <span class="cline-any cline-neutral">&nbsp;</span>
772
840
  <span class="cline-any cline-neutral">&nbsp;</span>
773
841
  <span class="cline-any cline-neutral">&nbsp;</span>
774
- <span class="cline-any cline-yes">16x</span>
775
- <span class="cline-any cline-yes">16x</span>
776
- <span class="cline-any cline-yes">12x</span>
777
- <span class="cline-any cline-yes">1x</span>
842
+ <span class="cline-any cline-yes">22x</span>
843
+ <span class="cline-any cline-yes">22x</span>
844
+ <span class="cline-any cline-yes">17x</span>
845
+ <span class="cline-any cline-no">&nbsp;</span>
778
846
  <span class="cline-any cline-neutral">&nbsp;</span>
779
847
  <span class="cline-any cline-neutral">&nbsp;</span>
780
848
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -783,9 +851,9 @@
783
851
  <span class="cline-any cline-neutral">&nbsp;</span>
784
852
  <span class="cline-any cline-neutral">&nbsp;</span>
785
853
  <span class="cline-any cline-neutral">&nbsp;</span>
786
- <span class="cline-any cline-yes">11x</span>
787
- <span class="cline-any cline-yes">7x</span>
788
- <span class="cline-any cline-yes">7x</span>
854
+ <span class="cline-any cline-yes">17x</span>
855
+ <span class="cline-any cline-yes">10x</span>
856
+ <span class="cline-any cline-yes">10x</span>
789
857
  <span class="cline-any cline-yes">1x</span>
790
858
  <span class="cline-any cline-neutral">&nbsp;</span>
791
859
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -796,14 +864,14 @@
796
864
  <span class="cline-any cline-neutral">&nbsp;</span>
797
865
  <span class="cline-any cline-neutral">&nbsp;</span>
798
866
  <span class="cline-any cline-neutral">&nbsp;</span>
799
- <span class="cline-any cline-yes">6x</span>
867
+ <span class="cline-any cline-yes">9x</span>
800
868
  <span class="cline-any cline-neutral">&nbsp;</span>
801
869
  <span class="cline-any cline-neutral">&nbsp;</span>
802
- <span class="cline-any cline-yes">6x</span>
870
+ <span class="cline-any cline-yes">9x</span>
803
871
  <span class="cline-any cline-neutral">&nbsp;</span>
804
- <span class="cline-any cline-yes">4x</span>
872
+ <span class="cline-any cline-yes">7x</span>
805
873
  <span class="cline-any cline-neutral">&nbsp;</span>
806
- <span class="cline-any cline-yes">4x</span>
874
+ <span class="cline-any cline-yes">5x</span>
807
875
  <span class="cline-any cline-no">&nbsp;</span>
808
876
  <span class="cline-any cline-neutral">&nbsp;</span>
809
877
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -813,8 +881,8 @@
813
881
  <span class="cline-any cline-neutral">&nbsp;</span>
814
882
  <span class="cline-any cline-neutral">&nbsp;</span>
815
883
  <span class="cline-any cline-neutral">&nbsp;</span>
816
- <span class="cline-any cline-yes">4x</span>
817
- <span class="cline-any cline-yes">4x</span>
884
+ <span class="cline-any cline-yes">5x</span>
885
+ <span class="cline-any cline-yes">5x</span>
818
886
  <span class="cline-any cline-neutral">&nbsp;</span>
819
887
  <span class="cline-any cline-neutral">&nbsp;</span>
820
888
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -828,11 +896,11 @@
828
896
  <span class="cline-any cline-neutral">&nbsp;</span>
829
897
  <span class="cline-any cline-neutral">&nbsp;</span>
830
898
  <span class="cline-any cline-neutral">&nbsp;</span>
831
- <span class="cline-any cline-yes">1x</span>
899
+ <span class="cline-any cline-yes">2x</span>
832
900
  <span class="cline-any cline-neutral">&nbsp;</span>
833
901
  <span class="cline-any cline-neutral">&nbsp;</span>
834
- <span class="cline-any cline-yes">66x</span>
835
- <span class="cline-any cline-yes">4x</span>
902
+ <span class="cline-any cline-yes">150x</span>
903
+ <span class="cline-any cline-yes">5x</span>
836
904
  <span class="cline-any cline-neutral">&nbsp;</span>
837
905
  <span class="cline-any cline-neutral">&nbsp;</span>
838
906
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -841,7 +909,7 @@
841
909
  <span class="cline-any cline-neutral">&nbsp;</span>
842
910
  <span class="cline-any cline-neutral">&nbsp;</span>
843
911
  <span class="cline-any cline-neutral">&nbsp;</span>
844
- <span class="cline-any cline-yes">62x</span>
912
+ <span class="cline-any cline-yes">145x</span>
845
913
  <span class="cline-any cline-yes">1x</span>
846
914
  <span class="cline-any cline-neutral">&nbsp;</span>
847
915
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -851,7 +919,7 @@
851
919
  <span class="cline-any cline-neutral">&nbsp;</span>
852
920
  <span class="cline-any cline-neutral">&nbsp;</span>
853
921
  <span class="cline-any cline-neutral">&nbsp;</span>
854
- <span class="cline-any cline-yes">61x</span>
922
+ <span class="cline-any cline-yes">144x</span>
855
923
  <span class="cline-any cline-neutral">&nbsp;</span>
856
924
  <span class="cline-any cline-neutral">&nbsp;</span>
857
925
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -875,9 +943,9 @@
875
943
  <span class="cline-any cline-neutral">&nbsp;</span>
876
944
  <span class="cline-any cline-neutral">&nbsp;</span>
877
945
  <span class="cline-any cline-yes">3x</span>
878
- <span class="cline-any cline-yes">43x</span>
879
- <span class="cline-any cline-yes">43x</span>
880
- <span class="cline-any cline-yes">41x</span>
946
+ <span class="cline-any cline-yes">7x</span>
947
+ <span class="cline-any cline-yes">7x</span>
948
+ <span class="cline-any cline-yes">5x</span>
881
949
  <span class="cline-any cline-neutral">&nbsp;</span>
882
950
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { Schema } from "@featurevisor/types";
883
951
  &nbsp;
@@ -969,9 +1037,14 @@ export function resolveSchemaAtPath(
969
1037
  if (seg.key) {
970
1038
  if (current.type !== "object") return null;
971
1039
  const props = current.properties;
972
- if (!props || typeof props !== "object") return null;
973
- const next = props[seg.key];
974
- if (next === undefined) return null;
1040
+ const additional = current.additionalProperties;
1041
+ const next = props &amp;&amp; typeof props === "object" ? props[seg.key] : undefined;
1042
+ if (next === undefined) {
1043
+ if (!additional || typeof additional !== "object") return null;
1044
+ current = resolveSchemaRef(additional, schemasByKey);
1045
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!current) <span class="cstat-no" title="statement not covered" >return null;</span>
1046
+ continue;
1047
+ }
975
1048
  current = resolveSchemaRef(next, schemasByKey);
976
1049
  <span class="missing-if-branch" title="if path not taken" >I</span>if (!current) <span class="cstat-no" title="statement not covered" >return null;</span>
977
1050
  }
@@ -1008,27 +1081,56 @@ function getContainerSchemaAtPath(
1008
1081
  const lastSegment = pathSegments[pathSegments.length - 1];
1009
1082
  for (const seg of pathWithoutLast) {
1010
1083
  <span class="missing-if-branch" title="if path not taken" >I</span>if (isOneOfSchema(current)) <span class="cstat-no" title="statement not covered" >return null;</span>
1084
+ if (seg.key) {
1085
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (current.type !== "object") <span class="cstat-no" title="statement not covered" >return null;</span>
1086
+ const props = current.properties;
1087
+ const additional = current.additionalProperties;
1088
+ const next = props &amp;&amp; typeof props === "object" ? props[seg.key] : <span class="branch-1 cbranch-no" title="branch not covered" >undefined;</span>
1089
+ if (next === undefined) {
1090
+ if (!additional || <span class="branch-1 cbranch-no" title="branch not covered" >typeof additional !== "object")</span> return null;
1091
+ <span class="cstat-no" title="statement not covered" > current = resolveSchemaRef(additional, schemasByKey);</span>
1092
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!current) <span class="cstat-no" title="statement not covered" >return null;</span></span>
1093
+ <span class="cstat-no" title="statement not covered" > continue;</span>
1094
+ }
1095
+ current = resolveSchemaRef(next, schemasByKey);
1096
+ }
1011
1097
  if ("index" in seg || "selector" in seg) {
1012
- if (current.type !== "array") return null;
1098
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (current?.type !== "array") <span class="cstat-no" title="statement not covered" >return null;</span>
1013
1099
  const itemSchema = current.items;
1014
1100
  <span class="missing-if-branch" title="if path not taken" >I</span>if (!itemSchema || typeof itemSchema !== "object") <span class="cstat-no" title="statement not covered" >return null;</span>
1015
1101
  current = resolveSchemaRef(itemSchema, schemasByKey);
1016
- } else {
1017
- <span class="missing-if-branch" title="if path not taken" >I</span>if (current.type !== "object") <span class="cstat-no" title="statement not covered" >return null;</span>
1018
- const props = current.properties;
1019
- <span class="missing-if-branch" title="if path not taken" >I</span>if (!props || typeof props !== "object") <span class="cstat-no" title="statement not covered" >return null;</span>
1020
- const next = props[seg.key];
1021
- <span class="missing-if-branch" title="if path not taken" >I</span>if (next === undefined) <span class="cstat-no" title="statement not covered" >return null;</span>
1022
- current = resolveSchemaRef(next, schemasByKey);
1023
1102
  }
1024
1103
  <span class="missing-if-branch" title="if path not taken" >I</span>if (!current) <span class="cstat-no" title="statement not covered" >return null;</span>
1025
1104
  }
1026
1105
  <span class="missing-if-branch" title="if path not taken" >I</span>if (!current) <span class="cstat-no" title="statement not covered" >return null;</span>
1027
1106
  const parentSchema = current;
1028
1107
  if ("index" in lastSegment || "selector" in lastSegment) {
1029
- return { containerSchema: parentSchema, lastSegment, parentSchema };
1108
+ let arraySchema: Schema | null = parentSchema;
1109
+ if (lastSegment.key) {
1110
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (arraySchema.type !== "object") <span class="cstat-no" title="statement not covered" >return null;</span>
1111
+ const props = arraySchema.properties;
1112
+ const additional = arraySchema.additionalProperties;
1113
+ const next = props &amp;&amp; typeof props === "object" ? props[lastSegment.key] : <span class="branch-1 cbranch-no" title="branch not covered" >undefined;</span>
1114
+ if (next === undefined) {
1115
+ if (!additional || <span class="branch-1 cbranch-no" title="branch not covered" >typeof additional !== "object")</span> return null;
1116
+ <span class="cstat-no" title="statement not covered" > arraySchema = resolveSchemaRef(additional, schemasByKey);</span>
1117
+ } else {
1118
+ arraySchema = resolveSchemaRef(next, schemasByKey);
1119
+ }
1120
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!arraySchema) <span class="cstat-no" title="statement not covered" >return null;</span>
1121
+ }
1122
+ const normalizedLastSegment =
1123
+ "index" in lastSegment
1124
+ ? ({ key: "", index: lastSegment.index } as PathSegment)
1125
+ : ({ key: "", selector: lastSegment.selector } as PathSegment);
1126
+ return {
1127
+ containerSchema: arraySchema,
1128
+ lastSegment: normalizedLastSegment,
1129
+ parentSchema: arraySchema,
1130
+ };
1030
1131
  }
1031
- const propSchema = parentSchema.properties?.[lastSegment.key];
1132
+ const propSchema =
1133
+ parentSchema.properties?.[lastSegment.key] ?? parentSchema.additionalProperties;
1032
1134
  const resolvedProp =
1033
1135
  propSchema &amp;&amp; typeof propSchema === "object"
1034
1136
  ? resolveSchemaRef(propSchema, schemasByKey)
@@ -1181,8 +1283,8 @@ export function validateMutationKey(
1181
1283
  }
1182
1284
  const last = container.lastSegment;
1183
1285
  if ("index" in last || "selector" in last) {
1184
- if (container.parentSchema.type !== "array") {
1185
- return {
1286
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (container.parentSchema.type !== "array") {
1287
+ <span class="cstat-no" title="statement not covered" > return {</span>
1186
1288
  valid: false,
1187
1289
  rootKey,
1188
1290
  pathSegments,
@@ -1294,7 +1396,7 @@ export function parsePathMapKey(relativePath: string): PathSegment[] | null {
1294
1396
  <div class='footer quiet pad2 space-top1 center small'>
1295
1397
  Code coverage generated by
1296
1398
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1297
- at 2026-02-27T17:47:18.936Z
1399
+ at 2026-03-01T20:34:15.761Z
1298
1400
  </div>
1299
1401
  <script src="../prettify.js"></script>
1300
1402
  <script>
@@ -223,7 +223,7 @@ export function <span class="fstat-no" title="function not covered" >printZodErr
223
223
  <div class='footer quiet pad2 space-top1 center small'>
224
224
  Code coverage generated by
225
225
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
226
- at 2026-02-27T17:47:18.936Z
226
+ at 2026-03-01T20:34:15.761Z
227
227
  </div>
228
228
  <script src="../prettify.js"></script>
229
229
  <script>