@featurevisor/core 2.13.0 → 2.14.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 (80) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/coverage/clover.xml +906 -557
  3. package/coverage/coverage-final.json +11 -8
  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 +38 -8
  9. package/coverage/lcov-report/builder/mutateVariables.ts.html +400 -0
  10. package/coverage/lcov-report/builder/mutator.ts.html +796 -0
  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/projectConfig.ts.html +1 -1
  15. package/coverage/lcov-report/datasource/adapter.ts.html +1 -1
  16. package/coverage/lcov-report/datasource/datasource.ts.html +4 -4
  17. package/coverage/lcov-report/datasource/filesystemAdapter.ts.html +23 -23
  18. package/coverage/lcov-report/datasource/index.html +1 -1
  19. package/coverage/lcov-report/datasource/index.ts.html +1 -1
  20. package/coverage/lcov-report/index.html +28 -28
  21. package/coverage/lcov-report/linter/attributeSchema.ts.html +1 -1
  22. package/coverage/lcov-report/linter/checkCircularDependency.ts.html +1 -1
  23. package/coverage/lcov-report/linter/checkPercentageExceedingSlot.ts.html +1 -1
  24. package/coverage/lcov-report/linter/conditionSchema.ts.html +7 -7
  25. package/coverage/lcov-report/linter/featureSchema.ts.html +789 -318
  26. package/coverage/lcov-report/linter/groupSchema.ts.html +1 -1
  27. package/coverage/lcov-report/linter/index.html +34 -19
  28. package/coverage/lcov-report/linter/lintProject.ts.html +25 -25
  29. package/coverage/lcov-report/linter/mutationNotation.ts.html +1309 -0
  30. package/coverage/lcov-report/linter/printError.ts.html +1 -1
  31. package/coverage/lcov-report/linter/schema.ts.html +69 -69
  32. package/coverage/lcov-report/linter/segmentSchema.ts.html +1 -1
  33. package/coverage/lcov-report/linter/testSchema.ts.html +5 -5
  34. package/coverage/lcov-report/list/index.html +1 -1
  35. package/coverage/lcov-report/list/matrix.ts.html +1 -1
  36. package/coverage/lcov-report/parsers/index.html +1 -1
  37. package/coverage/lcov-report/parsers/index.ts.html +1 -1
  38. package/coverage/lcov-report/parsers/json.ts.html +1 -1
  39. package/coverage/lcov-report/parsers/yml.ts.html +2 -2
  40. package/coverage/lcov-report/tester/cliFormat.ts.html +1 -1
  41. package/coverage/lcov-report/tester/helpers.ts.html +1 -1
  42. package/coverage/lcov-report/tester/index.html +1 -1
  43. package/coverage/lcov-report/utils/git.ts.html +1 -1
  44. package/coverage/lcov-report/utils/index.html +1 -1
  45. package/coverage/lcov.info +1839 -1120
  46. package/lib/builder/buildDatafile.js +8 -3
  47. package/lib/builder/buildDatafile.js.map +1 -1
  48. package/lib/builder/mutateVariables.d.ts +14 -0
  49. package/lib/builder/mutateVariables.js +90 -0
  50. package/lib/builder/mutateVariables.js.map +1 -0
  51. package/lib/builder/mutateVariables.spec.d.ts +1 -0
  52. package/lib/builder/mutateVariables.spec.js +1045 -0
  53. package/lib/builder/mutateVariables.spec.js.map +1 -0
  54. package/lib/builder/mutator.d.ts +20 -0
  55. package/lib/builder/mutator.js +223 -0
  56. package/lib/builder/mutator.js.map +1 -0
  57. package/lib/builder/mutator.spec.d.ts +1 -0
  58. package/lib/builder/mutator.spec.js +368 -0
  59. package/lib/builder/mutator.spec.js.map +1 -0
  60. package/lib/linter/featureSchema.d.ts +7 -7
  61. package/lib/linter/featureSchema.js +138 -62
  62. package/lib/linter/featureSchema.js.map +1 -1
  63. package/lib/linter/featureSchema.spec.js +150 -0
  64. package/lib/linter/featureSchema.spec.js.map +1 -1
  65. package/lib/linter/mutationNotation.d.ts +47 -0
  66. package/lib/linter/mutationNotation.js +381 -0
  67. package/lib/linter/mutationNotation.js.map +1 -0
  68. package/lib/linter/mutationNotation.spec.d.ts +1 -0
  69. package/lib/linter/mutationNotation.spec.js +549 -0
  70. package/lib/linter/mutationNotation.spec.js.map +1 -0
  71. package/package.json +2 -2
  72. package/src/builder/buildDatafile.ts +29 -3
  73. package/src/builder/mutateVariables.spec.ts +1134 -0
  74. package/src/builder/mutateVariables.ts +105 -0
  75. package/src/builder/mutator.spec.ts +413 -0
  76. package/src/builder/mutator.ts +237 -0
  77. package/src/linter/featureSchema.spec.ts +182 -0
  78. package/src/linter/featureSchema.ts +254 -97
  79. package/src/linter/mutationNotation.spec.ts +642 -0
  80. package/src/linter/mutationNotation.ts +408 -0
@@ -205,7 +205,7 @@ export function getUpdatedAvailableRangesAfterFilling(
205
205
  <div class='footer quiet pad2 space-top1 center small'>
206
206
  Code coverage generated by
207
207
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
208
- at 2026-02-23T20:40:14.947Z
208
+ at 2026-02-24T19:50:30.107Z
209
209
  </div>
210
210
  <script src="../prettify.js"></script>
211
211
  <script>
@@ -472,7 +472,7 @@ export function buildScopedCondition(
472
472
  <div class='footer quiet pad2 space-top1 center small'>
473
473
  Code coverage generated by
474
474
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
475
- at 2026-02-23T20:40:14.947Z
475
+ at 2026-02-24T19:50:30.107Z
476
476
  </div>
477
477
  <script src="../prettify.js"></script>
478
478
  <script>
@@ -589,7 +589,7 @@ export function buildScopedDatafile(
589
589
  <div class='footer quiet pad2 space-top1 center small'>
590
590
  Code coverage generated by
591
591
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
592
- at 2026-02-23T20:40:14.947Z
592
+ at 2026-02-24T19:50:30.107Z
593
593
  </div>
594
594
  <script src="../prettify.js"></script>
595
595
  <script>
@@ -529,7 +529,7 @@ export function buildScopedGroupSegments(
529
529
  <div class='footer quiet pad2 space-top1 center small'>
530
530
  Code coverage generated by
531
531
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
532
- at 2026-02-23T20:40:14.947Z
532
+ at 2026-02-24T19:50:30.107Z
533
533
  </div>
534
534
  <script src="../prettify.js"></script>
535
535
  <script>
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">97.28% </span>
26
+ <span class="strong">94.69% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>287/295</span>
28
+ <span class='fraction'>464/490</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">91.34% </span>
33
+ <span class="strong">83.65% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>95/104</span>
35
+ <span class='fraction'>220/263</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
40
  <span class="strong">100% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>46/46</span>
42
+ <span class='fraction'>57/57</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">97.1% </span>
47
+ <span class="strong">96.68% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>268/276</span>
49
+ <span class='fraction'>437/452</span>
50
50
  </div>
51
51
 
52
52
 
@@ -138,6 +138,36 @@
138
138
  <td data-value="59" class="abs high">59/59</td>
139
139
  </tr>
140
140
 
141
+ <tr>
142
+ <td class="file high" data-value="mutateVariables.ts"><a href="mutateVariables.ts.html">mutateVariables.ts</a></td>
143
+ <td data-value="100" class="pic high">
144
+ <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
145
+ </td>
146
+ <td data-value="100" class="pct high">100%</td>
147
+ <td data-value="43" class="abs high">43/43</td>
148
+ <td data-value="93.61" class="pct high">93.61%</td>
149
+ <td data-value="47" class="abs high">44/47</td>
150
+ <td data-value="100" class="pct high">100%</td>
151
+ <td data-value="5" class="abs high">5/5</td>
152
+ <td data-value="100" class="pct high">100%</td>
153
+ <td data-value="41" class="abs high">41/41</td>
154
+ </tr>
155
+
156
+ <tr>
157
+ <td class="file high" data-value="mutator.ts"><a href="mutator.ts.html">mutator.ts</a></td>
158
+ <td data-value="88.15" class="pic high">
159
+ <div class="chart"><div class="cover-fill" style="width: 88%"></div><div class="cover-empty" style="width: 12%"></div></div>
160
+ </td>
161
+ <td data-value="88.15" class="pct high">88.15%</td>
162
+ <td data-value="152" class="abs high">134/152</td>
163
+ <td data-value="72.32" class="pct medium">72.32%</td>
164
+ <td data-value="112" class="abs medium">81/112</td>
165
+ <td data-value="100" class="pct high">100%</td>
166
+ <td data-value="6" class="abs high">6/6</td>
167
+ <td data-value="94.81" class="pct high">94.81%</td>
168
+ <td data-value="135" class="abs high">128/135</td>
169
+ </tr>
170
+
141
171
  <tr>
142
172
  <td class="file high" data-value="revision.ts"><a href="revision.ts.html">revision.ts</a></td>
143
173
  <td data-value="90" class="pic high">
@@ -176,7 +206,7 @@
176
206
  <div class='footer quiet pad2 space-top1 center small'>
177
207
  Code coverage generated by
178
208
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
179
- at 2026-02-23T20:40:14.947Z
209
+ at 2026-02-24T19:50:30.107Z
180
210
  </div>
181
211
  <script src="../prettify.js"></script>
182
212
  <script>
@@ -0,0 +1,400 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for builder/mutateVariables.ts</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../prettify.css" />
9
+ <link rel="stylesheet" href="../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../index.html">All files</a> / <a href="index.html">builder</a> mutateVariables.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">100% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>43/43</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">93.61% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>44/47</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>5/5</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">100% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>41/41</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input oninput="onInput()" type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
172
+ <span class="cline-any cline-yes">1x</span>
173
+ <span class="cline-any cline-neutral">&nbsp;</span>
174
+ <span class="cline-any cline-yes">1x</span>
175
+ <span class="cline-any cline-neutral">&nbsp;</span>
176
+ <span class="cline-any cline-neutral">&nbsp;</span>
177
+ <span class="cline-any cline-neutral">&nbsp;</span>
178
+ <span class="cline-any cline-neutral">&nbsp;</span>
179
+ <span class="cline-any cline-neutral">&nbsp;</span>
180
+ <span class="cline-any cline-yes">215x</span>
181
+ <span class="cline-any cline-yes">215x</span>
182
+ <span class="cline-any cline-yes">215x</span>
183
+ <span class="cline-any cline-neutral">&nbsp;</span>
184
+ <span class="cline-any cline-neutral">&nbsp;</span>
185
+ <span class="cline-any cline-neutral">&nbsp;</span>
186
+ <span class="cline-any cline-neutral">&nbsp;</span>
187
+ <span class="cline-any cline-neutral">&nbsp;</span>
188
+ <span class="cline-any cline-neutral">&nbsp;</span>
189
+ <span class="cline-any cline-neutral">&nbsp;</span>
190
+ <span class="cline-any cline-neutral">&nbsp;</span>
191
+ <span class="cline-any cline-yes">1x</span>
192
+ <span class="cline-any cline-neutral">&nbsp;</span>
193
+ <span class="cline-any cline-neutral">&nbsp;</span>
194
+ <span class="cline-any cline-neutral">&nbsp;</span>
195
+ <span class="cline-any cline-yes">70x</span>
196
+ <span class="cline-any cline-yes">4x</span>
197
+ <span class="cline-any cline-neutral">&nbsp;</span>
198
+ <span class="cline-any cline-yes">66x</span>
199
+ <span class="cline-any cline-yes">2x</span>
200
+ <span class="cline-any cline-neutral">&nbsp;</span>
201
+ <span class="cline-any cline-neutral">&nbsp;</span>
202
+ <span class="cline-any cline-yes">64x</span>
203
+ <span class="cline-any cline-yes">64x</span>
204
+ <span class="cline-any cline-yes">101x</span>
205
+ <span class="cline-any cline-yes">101x</span>
206
+ <span class="cline-any cline-yes">95x</span>
207
+ <span class="cline-any cline-neutral">&nbsp;</span>
208
+ <span class="cline-any cline-neutral">&nbsp;</span>
209
+ <span class="cline-any cline-neutral">&nbsp;</span>
210
+ <span class="cline-any cline-yes">64x</span>
211
+ <span class="cline-any cline-neutral">&nbsp;</span>
212
+ <span class="cline-any cline-yes">64x</span>
213
+ <span class="cline-any cline-yes">68x</span>
214
+ <span class="cline-any cline-neutral">&nbsp;</span>
215
+ <span class="cline-any cline-yes">68x</span>
216
+ <span class="cline-any cline-neutral">&nbsp;</span>
217
+ <span class="cline-any cline-neutral">&nbsp;</span>
218
+ <span class="cline-any cline-neutral">&nbsp;</span>
219
+ <span class="cline-any cline-yes">68x</span>
220
+ <span class="cline-any cline-neutral">&nbsp;</span>
221
+ <span class="cline-any cline-neutral">&nbsp;</span>
222
+ <span class="cline-any cline-yes">114x</span>
223
+ <span class="cline-any cline-neutral">&nbsp;</span>
224
+ <span class="cline-any cline-neutral">&nbsp;</span>
225
+ <span class="cline-any cline-neutral">&nbsp;</span>
226
+ <span class="cline-any cline-neutral">&nbsp;</span>
227
+ <span class="cline-any cline-neutral">&nbsp;</span>
228
+ <span class="cline-any cline-yes">28x</span>
229
+ <span class="cline-any cline-neutral">&nbsp;</span>
230
+ <span class="cline-any cline-yes">68x</span>
231
+ <span class="cline-any cline-yes">95x</span>
232
+ <span class="cline-any cline-yes">95x</span>
233
+ <span class="cline-any cline-yes">25x</span>
234
+ <span class="cline-any cline-neutral">&nbsp;</span>
235
+ <span class="cline-any cline-neutral">&nbsp;</span>
236
+ <span class="cline-any cline-neutral">&nbsp;</span>
237
+ <span class="cline-any cline-neutral">&nbsp;</span>
238
+ <span class="cline-any cline-yes">70x</span>
239
+ <span class="cline-any cline-neutral">&nbsp;</span>
240
+ <span class="cline-any cline-neutral">&nbsp;</span>
241
+ <span class="cline-any cline-neutral">&nbsp;</span>
242
+ <span class="cline-any cline-neutral">&nbsp;</span>
243
+ <span class="cline-any cline-yes">70x</span>
244
+ <span class="cline-any cline-neutral">&nbsp;</span>
245
+ <span class="cline-any cline-neutral">&nbsp;</span>
246
+ <span class="cline-any cline-neutral">&nbsp;</span>
247
+ <span class="cline-any cline-yes">68x</span>
248
+ <span class="cline-any cline-neutral">&nbsp;</span>
249
+ <span class="cline-any cline-neutral">&nbsp;</span>
250
+ <span class="cline-any cline-yes">64x</span>
251
+ <span class="cline-any cline-neutral">&nbsp;</span>
252
+ <span class="cline-any cline-neutral">&nbsp;</span>
253
+ <span class="cline-any cline-neutral">&nbsp;</span>
254
+ <span class="cline-any cline-neutral">&nbsp;</span>
255
+ <span class="cline-any cline-neutral">&nbsp;</span>
256
+ <span class="cline-any cline-neutral">&nbsp;</span>
257
+ <span class="cline-any cline-neutral">&nbsp;</span>
258
+ <span class="cline-any cline-yes">1x</span>
259
+ <span class="cline-any cline-neutral">&nbsp;</span>
260
+ <span class="cline-any cline-neutral">&nbsp;</span>
261
+ <span class="cline-any cline-neutral">&nbsp;</span>
262
+ <span class="cline-any cline-neutral">&nbsp;</span>
263
+ <span class="cline-any cline-yes">31x</span>
264
+ <span class="cline-any cline-yes">26x</span>
265
+ <span class="cline-any cline-yes">24x</span>
266
+ <span class="cline-any cline-yes">5x</span>
267
+ <span class="cline-any cline-neutral">&nbsp;</span>
268
+ <span class="cline-any cline-yes">19x</span>
269
+ <span class="cline-any cline-yes">19x</span>
270
+ <span class="cline-any cline-yes">19x</span>
271
+ <span class="cline-any cline-yes">25x</span>
272
+ <span class="cline-any cline-neutral">&nbsp;</span>
273
+ <span class="cline-any cline-yes">19x</span>
274
+ <span class="cline-any cline-yes">19x</span>
275
+ <span class="cline-any cline-neutral">&nbsp;</span>
276
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { VariableSchema, VariableValue } from "@featurevisor/types";
277
+ import { mutate } from "./mutator";
278
+ &nbsp;
279
+ const MUTATION_OP_SUFFIX = /:((?:append|prepend|after|before|remove))$/;
280
+ &nbsp;
281
+ /**
282
+ * Get the root variable name from an override key (e.g. "tags:append" -&gt; "tags", "payload.rows:append" -&gt; "payload").
283
+ */
284
+ function rootVariableFromOverrideKey(overrideKey: string): string {
285
+ const withoutSuffix = overrideKey.replace(MUTATION_OP_SUFFIX, "").trim();
286
+ const firstSegment = withoutSuffix.includes(".") ? withoutSuffix.split(".")[0] : withoutSuffix;
287
+ return firstSegment.replace(/\s*\[.*\]\s*$/, "").trim();
288
+ }
289
+ &nbsp;
290
+ /**
291
+ * Resolve variable values from schema defaults and overrides.
292
+ * Override keys may be variable keys or dot-notation paths (e.g. "foo", "foo.a.b", "tags:append", "items[id=2]:after").
293
+ * Uses the mutator so nested paths and mutation notations are supported.
294
+ * Returns only variables that were desired to be overridden (i.e. appear in overrides).
295
+ */
296
+ export function resolveMutationsForMultipleVariables(
297
+ variablesSchema: Record&lt;string, VariableSchema&gt; | undefined,
298
+ overrides: Record&lt;string, VariableValue&gt; | undefined,
299
+ ): Record&lt;string, VariableValue&gt; | undefined {
300
+ if (!overrides || Object.keys(overrides).length === 0) {
301
+ return undefined;
302
+ }
303
+ if (!variablesSchema || Object.keys(variablesSchema).length === 0) {
304
+ return undefined;
305
+ }
306
+ &nbsp;
307
+ const variableKeysToOutput = new Set&lt;string&gt;();
308
+ for (const overrideKey of Object.keys(overrides)) {
309
+ const variableKey = rootVariableFromOverrideKey(overrideKey);
310
+ if (variableKey &amp;&amp; variablesSchema[variableKey]) {
311
+ variableKeysToOutput.add(variableKey);
312
+ }
313
+ }
314
+ &nbsp;
315
+ const result: Record&lt;string, VariableValue&gt; = {};
316
+ &nbsp;
317
+ for (const variableKey of variableKeysToOutput) {
318
+ const schema = variablesSchema[variableKey];
319
+ let value: VariableValue =
320
+ schema.defaultValue !== undefined &amp;&amp; schema.defaultValue !== null
321
+ ? (JSON.parse(JSON.stringify(schema.defaultValue)) as VariableValue)
322
+ : undefined;
323
+ &nbsp;
324
+ const keysForThisVariable = Object.keys(overrides)
325
+ .filter(
326
+ (k) =&gt;
327
+ rootVariableFromOverrideKey(k) === variableKey &amp;&amp;
328
+ (k === variableKey ||
329
+ k.startsWith(variableKey + ".") ||
330
+ k.startsWith(variableKey + "[") ||
331
+ <span class="branch-4 cbranch-no" title="branch not covered" > k.startsWith(variableKey + ":"))</span>,
332
+ )
333
+ .sort((a, b) =&gt; a.length - b.length);
334
+ &nbsp;
335
+ for (const overrideKey of keysForThisVariable) {
336
+ const overrideValue = overrides[overrideKey];
337
+ if (overrideKey === variableKey) {
338
+ value =
339
+ overrideValue !== undefined &amp;&amp; overrideValue !== null
340
+ ? (JSON.parse(JSON.stringify(overrideValue)) as VariableValue)
341
+ : <span class="branch-1 cbranch-no" title="branch not covered" >overrideValue;</span>
342
+ } else {
343
+ const notation = overrideKey.startsWith(variableKey + "[")
344
+ ? overrideKey.slice(variableKey.length)
345
+ : overrideKey.startsWith(variableKey + ":")
346
+ ? <span class="branch-0 cbranch-no" title="branch not covered" >overrideKey.slice(variableKey.length)</span>
347
+ : overrideKey.slice(variableKey.length + 1);
348
+ value = mutate(schema, value, notation, overrideValue);
349
+ }
350
+ }
351
+ &nbsp;
352
+ result[variableKey] = value;
353
+ }
354
+ &nbsp;
355
+ return Object.keys(result).length &gt; 0 ? result : undefined;
356
+ }
357
+ &nbsp;
358
+ /**
359
+ * Resolve a single variable's override value (e.g. from variableOverrides).
360
+ * If the value is a plain object with path-like keys, it is merged with the variable's default;
361
+ * otherwise the value is returned as-is (full replacement).
362
+ */
363
+ export function resolveMutationsForSingleVariable(
364
+ variablesSchema: Record&lt;string, VariableSchema&gt; | undefined,
365
+ variableKey: string,
366
+ overrideValue: VariableValue,
367
+ ): VariableValue {
368
+ if (!variablesSchema || !variablesSchema[variableKey]) return overrideValue;
369
+ if (overrideValue === null || overrideValue === undefined) return overrideValue;
370
+ if (typeof overrideValue !== "object" || Array.isArray(overrideValue)) {
371
+ return overrideValue;
372
+ }
373
+ const pathMap = overrideValue as Record&lt;string, VariableValue&gt;;
374
+ const flat: Record&lt;string, VariableValue&gt; = {};
375
+ for (const [k, v] of Object.entries(pathMap)) {
376
+ flat[k === variableKey ? variableKey : variableKey + "." + k] = v;
377
+ }
378
+ const resolved = resolveMutationsForMultipleVariables(variablesSchema, flat);
379
+ return resolved &amp;&amp; variableKey in resolved ? resolved[variableKey] : overrideValue;
380
+ }
381
+ &nbsp;</pre></td></tr></table></pre>
382
+
383
+ <div class='push'></div><!-- for sticky footer -->
384
+ </div><!-- /wrapper -->
385
+ <div class='footer quiet pad2 space-top1 center small'>
386
+ Code coverage generated by
387
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
388
+ at 2026-02-24T19:50:30.107Z
389
+ </div>
390
+ <script src="../prettify.js"></script>
391
+ <script>
392
+ window.onload = function () {
393
+ prettyPrint();
394
+ };
395
+ </script>
396
+ <script src="../sorter.js"></script>
397
+ <script src="../block-navigation.js"></script>
398
+ </body>
399
+ </html>
400
+