@featurevisor/core 2.17.0 → 2.18.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 (73) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/coverage/clover.xml +798 -764
  3. package/coverage/coverage-final.json +5 -5
  4. package/coverage/lcov-report/builder/allocator.ts.html +1 -1
  5. package/coverage/lcov-report/builder/buildScopedConditions.ts.html +1 -1
  6. package/coverage/lcov-report/builder/buildScopedDatafile.ts.html +1 -1
  7. package/coverage/lcov-report/builder/buildScopedSegments.ts.html +1 -1
  8. package/coverage/lcov-report/builder/index.html +1 -1
  9. package/coverage/lcov-report/builder/mutateVariables.ts.html +1 -1
  10. package/coverage/lcov-report/builder/mutator.ts.html +18 -18
  11. package/coverage/lcov-report/builder/revision.ts.html +1 -1
  12. package/coverage/lcov-report/builder/traffic.ts.html +1 -1
  13. package/coverage/lcov-report/config/index.html +1 -1
  14. package/coverage/lcov-report/config/index.ts.html +1 -1
  15. package/coverage/lcov-report/config/projectConfig.ts.html +1 -1
  16. package/coverage/lcov-report/datasource/adapter.ts.html +1 -1
  17. package/coverage/lcov-report/datasource/datasource.ts.html +1 -1
  18. package/coverage/lcov-report/datasource/filesystemAdapter.ts.html +1 -1
  19. package/coverage/lcov-report/datasource/index.html +1 -1
  20. package/coverage/lcov-report/datasource/index.ts.html +1 -1
  21. package/coverage/lcov-report/index.html +18 -18
  22. package/coverage/lcov-report/linter/attributeSchema.ts.html +1 -1
  23. package/coverage/lcov-report/linter/checkCircularDependency.ts.html +1 -1
  24. package/coverage/lcov-report/linter/checkPercentageExceedingSlot.ts.html +1 -1
  25. package/coverage/lcov-report/linter/conditionSchema.ts.html +7 -7
  26. package/coverage/lcov-report/linter/featureSchema.ts.html +365 -188
  27. package/coverage/lcov-report/linter/groupSchema.ts.html +1 -1
  28. package/coverage/lcov-report/linter/index.html +34 -34
  29. package/coverage/lcov-report/linter/lintProject.ts.html +1 -1
  30. package/coverage/lcov-report/linter/mutationNotation.ts.html +99 -66
  31. package/coverage/lcov-report/linter/printError.ts.html +1 -1
  32. package/coverage/lcov-report/linter/schema.ts.html +170 -80
  33. package/coverage/lcov-report/linter/segmentSchema.ts.html +1 -1
  34. package/coverage/lcov-report/linter/testSchema.ts.html +1 -1
  35. package/coverage/lcov-report/list/index.html +1 -1
  36. package/coverage/lcov-report/list/matrix.ts.html +1 -1
  37. package/coverage/lcov-report/parsers/index.html +1 -1
  38. package/coverage/lcov-report/parsers/index.ts.html +1 -1
  39. package/coverage/lcov-report/parsers/json.ts.html +1 -1
  40. package/coverage/lcov-report/parsers/yml.ts.html +1 -1
  41. package/coverage/lcov-report/tester/cliFormat.ts.html +1 -1
  42. package/coverage/lcov-report/tester/helpers.ts.html +1 -1
  43. package/coverage/lcov-report/tester/index.html +1 -1
  44. package/coverage/lcov-report/utils/git.ts.html +1 -1
  45. package/coverage/lcov-report/utils/index.html +1 -1
  46. package/coverage/lcov.info +1653 -1567
  47. package/json-schema/attribute.json +25 -9
  48. package/json-schema/feature.json +319 -238
  49. package/json-schema/segment.json +76 -45
  50. package/lib/generate-code/typescript.js +63 -20
  51. package/lib/generate-code/typescript.js.map +1 -1
  52. package/lib/linter/featureSchema.d.ts +9 -0
  53. package/lib/linter/featureSchema.js +38 -8
  54. package/lib/linter/featureSchema.js.map +1 -1
  55. package/lib/linter/featureSchema.spec.js +93 -0
  56. package/lib/linter/featureSchema.spec.js.map +1 -1
  57. package/lib/linter/mutationNotation.js +21 -11
  58. package/lib/linter/mutationNotation.js.map +1 -1
  59. package/lib/linter/mutationNotation.spec.js +18 -0
  60. package/lib/linter/mutationNotation.spec.js.map +1 -1
  61. package/lib/linter/schema.d.ts +1 -0
  62. package/lib/linter/schema.js +13 -0
  63. package/lib/linter/schema.js.map +1 -1
  64. package/lib/linter/schema.spec.js +51 -0
  65. package/lib/linter/schema.spec.js.map +1 -1
  66. package/package.json +5 -5
  67. package/src/generate-code/typescript.ts +87 -20
  68. package/src/linter/featureSchema.spec.ts +118 -0
  69. package/src/linter/featureSchema.ts +65 -6
  70. package/src/linter/mutationNotation.spec.ts +23 -0
  71. package/src/linter/mutationNotation.ts +18 -7
  72. package/src/linter/schema.spec.ts +72 -0
  73. package/src/linter/schema.ts +30 -0
@@ -211,7 +211,7 @@ export function getGroupZodSchema(
211
211
  <div class='footer quiet pad2 space-top1 center small'>
212
212
  Code coverage generated by
213
213
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
214
- at 2026-02-27T17:47:18.936Z
214
+ at 2026-02-27T20:35:38.828Z
215
215
  </div>
216
216
  <script src="../prettify.js"></script>
217
217
  <script>
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">76.18% </span>
26
+ <span class="strong">76.3% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>950/1247</span>
28
+ <span class='fraction'>976/1279</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">69.46% </span>
33
+ <span class="strong">70.02% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>628/904</span>
35
+ <span class='fraction'>668/954</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">74.84% </span>
40
+ <span class="strong">74.37% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>119/159</span>
42
+ <span class='fraction'>119/160</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">79.58% </span>
47
+ <span class="strong">79.57% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>916/1151</span>
49
+ <span class='fraction'>943/1185</span>
50
50
  </div>
51
51
 
52
52
 
@@ -140,17 +140,17 @@
140
140
 
141
141
  <tr>
142
142
  <td class="file medium" data-value="featureSchema.ts"><a href="featureSchema.ts.html">featureSchema.ts</a></td>
143
- <td data-value="70.96" class="pic medium">
144
- <div class="chart"><div class="cover-fill" style="width: 70%"></div><div class="cover-empty" style="width: 30%"></div></div>
143
+ <td data-value="71.64" class="pic medium">
144
+ <div class="chart"><div class="cover-fill" style="width: 71%"></div><div class="cover-empty" style="width: 29%"></div></div>
145
145
  </td>
146
- <td data-value="70.96" class="pct medium">70.96%</td>
147
- <td data-value="520" class="abs medium">369/520</td>
148
- <td data-value="61.49" class="pct medium">61.49%</td>
149
- <td data-value="361" class="abs medium">222/361</td>
150
- <td data-value="76.38" class="pct medium">76.38%</td>
151
- <td data-value="72" class="abs medium">55/72</td>
152
- <td data-value="75.1" class="pct medium">75.1%</td>
153
- <td data-value="474" class="abs medium">356/474</td>
146
+ <td data-value="71.64" class="pct medium">71.64%</td>
147
+ <td data-value="536" class="abs medium">384/536</td>
148
+ <td data-value="62.79" class="pct medium">62.79%</td>
149
+ <td data-value="387" class="abs medium">243/387</td>
150
+ <td data-value="75.34" class="pct medium">75.34%</td>
151
+ <td data-value="73" class="abs medium">55/73</td>
152
+ <td data-value="75.4" class="pct medium">75.4%</td>
153
+ <td data-value="492" class="abs medium">371/492</td>
154
154
  </tr>
155
155
 
156
156
  <tr>
@@ -185,17 +185,17 @@
185
185
 
186
186
  <tr>
187
187
  <td class="file high" data-value="mutationNotation.ts"><a href="mutationNotation.ts.html">mutationNotation.ts</a></td>
188
- <td data-value="88.96" class="pic high">
189
- <div class="chart"><div class="cover-fill" style="width: 88%"></div><div class="cover-empty" style="width: 12%"></div></div>
188
+ <td data-value="86.27" class="pic high">
189
+ <div class="chart"><div class="cover-fill" style="width: 86%"></div><div class="cover-empty" style="width: 14%"></div></div>
190
190
  </td>
191
- <td data-value="88.96" class="pct high">88.96%</td>
192
- <td data-value="145" class="abs high">129/145</td>
193
- <td data-value="78.62" class="pct medium">78.62%</td>
194
- <td data-value="131" class="abs medium">103/131</td>
191
+ <td data-value="86.27" class="pct high">86.27%</td>
192
+ <td data-value="153" class="abs high">132/153</td>
193
+ <td data-value="76.92" class="pct medium">76.92%</td>
194
+ <td data-value="143" class="abs medium">110/143</td>
195
195
  <td data-value="100" class="pct high">100%</td>
196
196
  <td data-value="8" class="abs high">8/8</td>
197
- <td data-value="95.96" class="pct high">95.96%</td>
198
- <td data-value="124" class="abs high">119/124</td>
197
+ <td data-value="93.18" class="pct high">93.18%</td>
198
+ <td data-value="132" class="abs high">123/132</td>
199
199
  </tr>
200
200
 
201
201
  <tr>
@@ -215,17 +215,17 @@
215
215
 
216
216
  <tr>
217
217
  <td class="file high" data-value="schema.ts"><a href="schema.ts.html">schema.ts</a></td>
218
- <td data-value="86.01" class="pic high">
218
+ <td data-value="86.56" class="pic high">
219
219
  <div class="chart"><div class="cover-fill" style="width: 86%"></div><div class="cover-empty" style="width: 14%"></div></div>
220
220
  </td>
221
- <td data-value="86.01" class="pct high">86.01%</td>
222
- <td data-value="193" class="abs high">166/193</td>
223
- <td data-value="85.39" class="pct high">85.39%</td>
224
- <td data-value="178" class="abs high">152/178</td>
221
+ <td data-value="86.56" class="pct high">86.56%</td>
222
+ <td data-value="201" class="abs high">174/201</td>
223
+ <td data-value="86.31" class="pct high">86.31%</td>
224
+ <td data-value="190" class="abs high">164/190</td>
225
225
  <td data-value="88" class="pct high">88%</td>
226
226
  <td data-value="25" class="abs high">22/25</td>
227
- <td data-value="90.22" class="pct high">90.22%</td>
228
- <td data-value="174" class="abs high">157/174</td>
227
+ <td data-value="90.65" class="pct high">90.65%</td>
228
+ <td data-value="182" class="abs high">165/182</td>
229
229
  </tr>
230
230
 
231
231
  <tr>
@@ -266,7 +266,7 @@
266
266
  <div class='footer quiet pad2 space-top1 center small'>
267
267
  Code coverage generated by
268
268
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
269
- at 2026-02-27T17:47:18.936Z
269
+ at 2026-02-27T20:35:38.828Z
270
270
  </div>
271
271
  <script src="../prettify.js"></script>
272
272
  <script>
@@ -2170,7 +2170,7 @@ export const lintPlugin: Plugin = {
2170
2170
  <div class='footer quiet pad2 space-top1 center small'>
2171
2171
  Code coverage generated by
2172
2172
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
2173
- at 2026-02-27T17:47:18.936Z
2173
+ at 2026-02-27T20:35:38.828Z
2174
2174
  </div>
2175
2175
  <script src="../prettify.js"></script>
2176
2176
  <script>
@@ -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">86.27% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>129/145</span>
28
+ <span class='fraction'>132/153</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">76.92% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>103/131</span>
35
+ <span class='fraction'>110/143</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.18% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>119/124</span>
49
+ <span class='fraction'>123/132</span>
50
50
  </div>
51
51
 
52
52
 
@@ -471,7 +471,18 @@
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></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
475
486
  <span class="cline-any cline-neutral">&nbsp;</span>
476
487
  <span class="cline-any cline-yes">3x</span>
477
488
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -491,8 +502,8 @@
491
502
  <span class="cline-any cline-neutral">&nbsp;</span>
492
503
  <span class="cline-any cline-neutral">&nbsp;</span>
493
504
  <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>
505
+ <span class="cline-any cline-yes">701x</span>
506
+ <span class="cline-any cline-yes">701x</span>
496
507
  <span class="cline-any cline-neutral">&nbsp;</span>
497
508
  <span class="cline-any cline-neutral">&nbsp;</span>
498
509
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -501,22 +512,22 @@
501
512
  <span class="cline-any cline-neutral">&nbsp;</span>
502
513
  <span class="cline-any cline-neutral">&nbsp;</span>
503
514
  <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>
515
+ <span class="cline-any cline-yes">161x</span>
516
+ <span class="cline-any cline-yes">161x</span>
506
517
  <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>
518
+ <span class="cline-any cline-yes">156x</span>
519
+ <span class="cline-any cline-yes">156x</span>
520
+ <span class="cline-any cline-yes">156x</span>
510
521
  <span class="cline-any cline-neutral">&nbsp;</span>
511
- <span class="cline-any cline-yes">155x</span>
522
+ <span class="cline-any cline-yes">156x</span>
512
523
  <span class="cline-any cline-neutral">&nbsp;</span>
513
524
  <span class="cline-any cline-neutral">&nbsp;</span>
514
525
  <span class="cline-any cline-neutral">&nbsp;</span>
515
526
  <span class="cline-any cline-neutral">&nbsp;</span>
516
527
  <span class="cline-any cline-neutral">&nbsp;</span>
517
528
  <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>
529
+ <span class="cline-any cline-yes">156x</span>
530
+ <span class="cline-any cline-yes">156x</span>
520
531
  <span class="cline-any cline-neutral">&nbsp;</span>
521
532
  <span class="cline-any cline-neutral">&nbsp;</span>
522
533
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -527,18 +538,18 @@
527
538
  <span class="cline-any cline-neutral">&nbsp;</span>
528
539
  <span class="cline-any cline-neutral">&nbsp;</span>
529
540
  <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>
541
+ <span class="cline-any cline-yes">708x</span>
542
+ <span class="cline-any cline-yes">706x</span>
532
543
  <span class="cline-any cline-yes">84x</span>
533
544
  <span class="cline-any cline-neutral">&nbsp;</span>
534
- <span class="cline-any cline-yes">615x</span>
545
+ <span class="cline-any cline-yes">622x</span>
535
546
  <span class="cline-any cline-neutral">&nbsp;</span>
536
547
  <span class="cline-any cline-neutral">&nbsp;</span>
537
548
  <span class="cline-any cline-neutral">&nbsp;</span>
538
549
  <span class="cline-any cline-neutral">&nbsp;</span>
539
550
  <span class="cline-any cline-neutral">&nbsp;</span>
540
551
  <span class="cline-any cline-neutral">&nbsp;</span>
541
- <span class="cline-any cline-yes">382x</span>
552
+ <span class="cline-any cline-yes">386x</span>
542
553
  <span class="cline-any cline-neutral">&nbsp;</span>
543
554
  <span class="cline-any cline-neutral">&nbsp;</span>
544
555
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -553,17 +564,22 @@
553
564
  <span class="cline-any cline-neutral">&nbsp;</span>
554
565
  <span class="cline-any cline-neutral">&nbsp;</span>
555
566
  <span class="cline-any cline-neutral">&nbsp;</span>
567
+ <span class="cline-any cline-yes">148x</span>
568
+ <span class="cline-any cline-yes">148x</span>
569
+ <span class="cline-any cline-neutral">&nbsp;</span>
556
570
  <span class="cline-any cline-yes">146x</span>
557
- <span class="cline-any cline-yes">146x</span>
571
+ <span class="cline-any cline-yes">184x</span>
572
+ <span class="cline-any cline-yes">183x</span>
573
+ <span class="cline-any cline-yes">156x</span>
574
+ <span class="cline-any cline-yes">153x</span>
575
+ <span class="cline-any cline-yes">153x</span>
576
+ <span class="cline-any cline-yes">153x</span>
577
+ <span class="cline-any cline-yes">153x</span>
578
+ <span class="cline-any cline-yes">14x</span>
579
+ <span class="cline-any cline-yes">2x</span>
580
+ <span class="cline-any cline-yes">2x</span>
581
+ <span class="cline-any cline-yes">2x</span>
558
582
  <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
583
  <span class="cline-any cline-yes">139x</span>
568
584
  <span class="cline-any cline-yes">139x</span>
569
585
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -575,7 +591,7 @@
575
591
  <span class="cline-any cline-yes">28x</span>
576
592
  <span class="cline-any cline-neutral">&nbsp;</span>
577
593
  <span class="cline-any cline-neutral">&nbsp;</span>
578
- <span class="cline-any cline-yes">127x</span>
594
+ <span class="cline-any cline-yes">129x</span>
579
595
  <span class="cline-any cline-neutral">&nbsp;</span>
580
596
  <span class="cline-any cline-neutral">&nbsp;</span>
581
597
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -588,17 +604,17 @@
588
604
  <span class="cline-any cline-neutral">&nbsp;</span>
589
605
  <span class="cline-any cline-neutral">&nbsp;</span>
590
606
  <span class="cline-any cline-neutral">&nbsp;</span>
591
- <span class="cline-any cline-yes">96x</span>
607
+ <span class="cline-any cline-yes">97x</span>
592
608
  <span class="cline-any cline-yes">10x</span>
593
609
  <span class="cline-any cline-yes">10x</span>
594
610
  <span class="cline-any cline-neutral">&nbsp;</span>
595
611
  <span class="cline-any cline-neutral">&nbsp;</span>
596
612
  <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>
613
+ <span class="cline-any cline-yes">87x</span>
614
+ <span class="cline-any cline-yes">87x</span>
615
+ <span class="cline-any cline-yes">87x</span>
616
+ <span class="cline-any cline-yes">87x</span>
617
+ <span class="cline-any cline-yes">87x</span>
602
618
  <span class="cline-any cline-yes">34x</span>
603
619
  <span class="cline-any cline-yes">34x</span>
604
620
  <span class="cline-any cline-yes">8x</span>
@@ -611,21 +627,27 @@
611
627
  <span class="cline-any cline-yes">26x</span>
612
628
  <span class="cline-any cline-yes">26x</span>
613
629
  <span class="cline-any cline-yes">26x</span>
630
+ <span class="cline-any cline-no">&nbsp;</span>
631
+ <span class="cline-any cline-no">&nbsp;</span>
632
+ <span class="cline-any cline-no">&nbsp;</span>
633
+ <span class="cline-any cline-no">&nbsp;</span>
634
+ <span class="cline-any cline-neutral">&nbsp;</span>
614
635
  <span class="cline-any cline-yes">26x</span>
615
636
  <span class="cline-any cline-neutral">&nbsp;</span>
616
637
  <span class="cline-any cline-yes">32x</span>
617
638
  <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>
639
+ <span class="cline-any cline-yes">85x</span>
640
+ <span class="cline-any cline-yes">85x</span>
641
+ <span class="cline-any cline-yes">85x</span>
621
642
  <span class="cline-any cline-yes">15x</span>
622
643
  <span class="cline-any cline-neutral">&nbsp;</span>
623
- <span class="cline-any cline-yes">69x</span>
624
644
  <span class="cline-any cline-neutral">&nbsp;</span>
625
- <span class="cline-any cline-yes">69x</span>
645
+ <span class="cline-any cline-yes">70x</span>
646
+ <span class="cline-any cline-neutral">&nbsp;</span>
647
+ <span class="cline-any cline-yes">70x</span>
626
648
  <span class="cline-any cline-neutral">&nbsp;</span>
627
649
  <span class="cline-any cline-neutral">&nbsp;</span>
628
- <span class="cline-any cline-yes">69x</span>
650
+ <span class="cline-any cline-yes">70x</span>
629
651
  <span class="cline-any cline-neutral">&nbsp;</span>
630
652
  <span class="cline-any cline-neutral">&nbsp;</span>
631
653
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -647,8 +669,8 @@
647
669
  <span class="cline-any cline-neutral">&nbsp;</span>
648
670
  <span class="cline-any cline-neutral">&nbsp;</span>
649
671
  <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>
672
+ <span class="cline-any cline-yes">102x</span>
673
+ <span class="cline-any cline-yes">102x</span>
652
674
  <span class="cline-any cline-yes">1x</span>
653
675
  <span class="cline-any cline-neutral">&nbsp;</span>
654
676
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -658,8 +680,8 @@
658
680
  <span class="cline-any cline-neutral">&nbsp;</span>
659
681
  <span class="cline-any cline-neutral">&nbsp;</span>
660
682
  <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>
683
+ <span class="cline-any cline-yes">101x</span>
684
+ <span class="cline-any cline-yes">101x</span>
663
685
  <span class="cline-any cline-yes">1x</span>
664
686
  <span class="cline-any cline-neutral">&nbsp;</span>
665
687
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -669,8 +691,8 @@
669
691
  <span class="cline-any cline-neutral">&nbsp;</span>
670
692
  <span class="cline-any cline-neutral">&nbsp;</span>
671
693
  <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>
694
+ <span class="cline-any cline-yes">100x</span>
695
+ <span class="cline-any cline-yes">100x</span>
674
696
  <span class="cline-any cline-yes">2x</span>
675
697
  <span class="cline-any cline-neutral">&nbsp;</span>
676
698
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -680,8 +702,8 @@
680
702
  <span class="cline-any cline-neutral">&nbsp;</span>
681
703
  <span class="cline-any cline-neutral">&nbsp;</span>
682
704
  <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>
705
+ <span class="cline-any cline-yes">98x</span>
706
+ <span class="cline-any cline-yes">98x</span>
685
707
  <span class="cline-any cline-neutral">&nbsp;</span>
686
708
  <span class="cline-any cline-no">&nbsp;</span>
687
709
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -698,7 +720,7 @@
698
720
  <span class="cline-any cline-neutral">&nbsp;</span>
699
721
  <span class="cline-any cline-neutral">&nbsp;</span>
700
722
  <span class="cline-any cline-neutral">&nbsp;</span>
701
- <span class="cline-any cline-yes">97x</span>
723
+ <span class="cline-any cline-yes">98x</span>
702
724
  <span class="cline-any cline-yes">1x</span>
703
725
  <span class="cline-any cline-neutral">&nbsp;</span>
704
726
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -709,10 +731,10 @@
709
731
  <span class="cline-any cline-neutral">&nbsp;</span>
710
732
  <span class="cline-any cline-neutral">&nbsp;</span>
711
733
  <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>
734
+ <span class="cline-any cline-yes">97x</span>
735
+ <span class="cline-any cline-yes">97x</span>
714
736
  <span class="cline-any cline-neutral">&nbsp;</span>
715
- <span class="cline-any cline-yes">96x</span>
737
+ <span class="cline-any cline-yes">97x</span>
716
738
  <span class="cline-any cline-neutral">&nbsp;</span>
717
739
  <span class="cline-any cline-neutral">&nbsp;</span>
718
740
  <span class="cline-any cline-yes">13x</span>
@@ -831,7 +853,7 @@
831
853
  <span class="cline-any cline-yes">1x</span>
832
854
  <span class="cline-any cline-neutral">&nbsp;</span>
833
855
  <span class="cline-any cline-neutral">&nbsp;</span>
834
- <span class="cline-any cline-yes">66x</span>
856
+ <span class="cline-any cline-yes">67x</span>
835
857
  <span class="cline-any cline-yes">4x</span>
836
858
  <span class="cline-any cline-neutral">&nbsp;</span>
837
859
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -841,7 +863,7 @@
841
863
  <span class="cline-any cline-neutral">&nbsp;</span>
842
864
  <span class="cline-any cline-neutral">&nbsp;</span>
843
865
  <span class="cline-any cline-neutral">&nbsp;</span>
844
- <span class="cline-any cline-yes">62x</span>
866
+ <span class="cline-any cline-yes">63x</span>
845
867
  <span class="cline-any cline-yes">1x</span>
846
868
  <span class="cline-any cline-neutral">&nbsp;</span>
847
869
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -851,7 +873,7 @@
851
873
  <span class="cline-any cline-neutral">&nbsp;</span>
852
874
  <span class="cline-any cline-neutral">&nbsp;</span>
853
875
  <span class="cline-any cline-neutral">&nbsp;</span>
854
- <span class="cline-any cline-yes">61x</span>
876
+ <span class="cline-any cline-yes">62x</span>
855
877
  <span class="cline-any cline-neutral">&nbsp;</span>
856
878
  <span class="cline-any cline-neutral">&nbsp;</span>
857
879
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -969,9 +991,14 @@ export function resolveSchemaAtPath(
969
991
  if (seg.key) {
970
992
  if (current.type !== "object") return null;
971
993
  const props = current.properties;
972
- if (!props || typeof props !== "object") return null;
973
- const next = props[seg.key];
974
- if (next === undefined) return null;
994
+ const additional = current.additionalProperties;
995
+ const next = props &amp;&amp; typeof props === "object" ? props[seg.key] : undefined;
996
+ if (next === undefined) {
997
+ if (!additional || typeof additional !== "object") return null;
998
+ current = resolveSchemaRef(additional, schemasByKey);
999
+ <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>
1000
+ continue;
1001
+ }
975
1002
  current = resolveSchemaRef(next, schemasByKey);
976
1003
  <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
1004
  }
@@ -1016,9 +1043,14 @@ function getContainerSchemaAtPath(
1016
1043
  } else {
1017
1044
  <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
1045
  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>
1046
+ const additional = current.additionalProperties;
1047
+ const next = props &amp;&amp; typeof props === "object" ? props[seg.key] : <span class="branch-1 cbranch-no" title="branch not covered" >undefined;</span>
1048
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (next === undefined) {
1049
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!additional || typeof additional !== "object") <span class="cstat-no" title="statement not covered" >return null;</span></span>
1050
+ <span class="cstat-no" title="statement not covered" > current = resolveSchemaRef(additional, schemasByKey);</span>
1051
+ <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>
1052
+ <span class="cstat-no" title="statement not covered" > continue;</span>
1053
+ }
1022
1054
  current = resolveSchemaRef(next, schemasByKey);
1023
1055
  }
1024
1056
  <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>
@@ -1028,7 +1060,8 @@ function getContainerSchemaAtPath(
1028
1060
  if ("index" in lastSegment || "selector" in lastSegment) {
1029
1061
  return { containerSchema: parentSchema, lastSegment, parentSchema };
1030
1062
  }
1031
- const propSchema = parentSchema.properties?.[lastSegment.key];
1063
+ const propSchema =
1064
+ parentSchema.properties?.[lastSegment.key] ?? parentSchema.additionalProperties;
1032
1065
  const resolvedProp =
1033
1066
  propSchema &amp;&amp; typeof propSchema === "object"
1034
1067
  ? resolveSchemaRef(propSchema, schemasByKey)
@@ -1294,7 +1327,7 @@ export function parsePathMapKey(relativePath: string): PathSegment[] | null {
1294
1327
  <div class='footer quiet pad2 space-top1 center small'>
1295
1328
  Code coverage generated by
1296
1329
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1297
- at 2026-02-27T17:47:18.936Z
1330
+ at 2026-02-27T20:35:38.828Z
1298
1331
  </div>
1299
1332
  <script src="../prettify.js"></script>
1300
1333
  <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-02-27T20:35:38.828Z
227
227
  </div>
228
228
  <script src="../prettify.js"></script>
229
229
  <script>