@featurevisor/core 2.20.0 → 2.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/coverage/clover.xml +1286 -515
  3. package/coverage/coverage-final.json +17 -16
  4. package/coverage/lcov-report/builder/allocator.ts.html +1 -1
  5. package/coverage/lcov-report/builder/buildDatafile.ts.html +1 -1
  6. package/coverage/lcov-report/builder/buildScopedConditions.ts.html +1 -1
  7. package/coverage/lcov-report/builder/buildScopedDatafile.ts.html +1 -1
  8. package/coverage/lcov-report/builder/buildScopedSegments.ts.html +1 -1
  9. package/coverage/lcov-report/builder/convertToV1.ts.html +1 -1
  10. package/coverage/lcov-report/builder/getFeatureRanges.ts.html +1 -1
  11. package/coverage/lcov-report/builder/hashes.ts.html +1 -1
  12. package/coverage/lcov-report/builder/index.html +1 -1
  13. package/coverage/lcov-report/builder/mutateVariables.ts.html +1 -1
  14. package/coverage/lcov-report/builder/mutator.ts.html +1 -1
  15. package/coverage/lcov-report/builder/revision.ts.html +1 -1
  16. package/coverage/lcov-report/builder/traffic.ts.html +1 -1
  17. package/coverage/lcov-report/config/index.html +1 -1
  18. package/coverage/lcov-report/config/index.ts.html +1 -1
  19. package/coverage/lcov-report/config/projectConfig.ts.html +42 -42
  20. package/coverage/lcov-report/datasource/adapter.ts.html +2 -2
  21. package/coverage/lcov-report/datasource/datasource.ts.html +43 -43
  22. package/coverage/lcov-report/datasource/filesystemAdapter.ts.html +48 -48
  23. package/coverage/lcov-report/datasource/index.html +19 -19
  24. package/coverage/lcov-report/datasource/index.ts.html +4 -4
  25. package/coverage/lcov-report/generate-code/index.html +116 -0
  26. package/coverage/lcov-report/generate-code/typescript.ts.html +3004 -0
  27. package/coverage/lcov-report/index.html +44 -29
  28. package/coverage/lcov-report/linter/attributeSchema.ts.html +1815 -30
  29. package/coverage/lcov-report/linter/checkCircularDependency.ts.html +1 -1
  30. package/coverage/lcov-report/linter/checkPercentageExceedingSlot.ts.html +1 -1
  31. package/coverage/lcov-report/linter/conditionSchema.ts.html +1606 -157
  32. package/coverage/lcov-report/linter/featureSchema.ts.html +56 -56
  33. package/coverage/lcov-report/linter/groupSchema.ts.html +1 -1
  34. package/coverage/lcov-report/linter/index.html +39 -39
  35. package/coverage/lcov-report/linter/lintProject.ts.html +189 -78
  36. package/coverage/lcov-report/linter/mutationNotation.ts.html +1 -1
  37. package/coverage/lcov-report/linter/printError.ts.html +1 -1
  38. package/coverage/lcov-report/linter/schema.ts.html +59 -59
  39. package/coverage/lcov-report/linter/segmentSchema.ts.html +3 -3
  40. package/coverage/lcov-report/linter/testSchema.ts.html +6 -6
  41. package/coverage/lcov-report/list/index.html +1 -1
  42. package/coverage/lcov-report/list/matrix.ts.html +1 -1
  43. package/coverage/lcov-report/parsers/index.html +1 -1
  44. package/coverage/lcov-report/parsers/index.ts.html +4 -4
  45. package/coverage/lcov-report/parsers/json.ts.html +2 -2
  46. package/coverage/lcov-report/parsers/yml.ts.html +6 -6
  47. package/coverage/lcov-report/tester/cliFormat.ts.html +1 -1
  48. package/coverage/lcov-report/tester/helpers.ts.html +1 -1
  49. package/coverage/lcov-report/tester/index.html +1 -1
  50. package/coverage/lcov-report/utils/extractKeys.ts.html +1 -1
  51. package/coverage/lcov-report/utils/git.ts.html +3 -3
  52. package/coverage/lcov-report/utils/index.html +1 -1
  53. package/coverage/lcov-report/utils/index.ts.html +1 -1
  54. package/coverage/lcov-report/utils/pretty.ts.html +1 -1
  55. package/coverage/lcov.info +2624 -926
  56. package/lib/generate-code/typescript.js +57 -29
  57. package/lib/generate-code/typescript.js.map +1 -1
  58. package/lib/generate-code/typescript.spec.d.ts +1 -0
  59. package/lib/generate-code/typescript.spec.js +78 -0
  60. package/lib/generate-code/typescript.spec.js.map +1 -0
  61. package/lib/linter/attributeSchema.d.ts +352 -20
  62. package/lib/linter/attributeSchema.js +426 -16
  63. package/lib/linter/attributeSchema.js.map +1 -1
  64. package/lib/linter/attributeSchema.spec.d.ts +1 -0
  65. package/lib/linter/attributeSchema.spec.js +266 -0
  66. package/lib/linter/attributeSchema.spec.js.map +1 -0
  67. package/lib/linter/conditionSchema.d.ts +2 -1
  68. package/lib/linter/conditionSchema.js +370 -100
  69. package/lib/linter/conditionSchema.js.map +1 -1
  70. package/lib/linter/conditionSchema.spec.js +200 -153
  71. package/lib/linter/conditionSchema.spec.js.map +1 -1
  72. package/lib/linter/featureSchema.spec.js +114 -3
  73. package/lib/linter/featureSchema.spec.js.map +1 -1
  74. package/lib/linter/lintProject.js +45 -14
  75. package/lib/linter/lintProject.js.map +1 -1
  76. package/lib/linter/segmentSchema.spec.js +71 -1
  77. package/lib/linter/segmentSchema.spec.js.map +1 -1
  78. package/package.json +5 -5
  79. package/src/generate-code/typescript.spec.ts +108 -0
  80. package/src/generate-code/typescript.ts +80 -34
  81. package/src/linter/attributeSchema.spec.ts +342 -0
  82. package/src/linter/attributeSchema.ts +613 -18
  83. package/src/linter/conditionSchema.spec.ts +231 -189
  84. package/src/linter/conditionSchema.ts +582 -99
  85. package/src/linter/featureSchema.spec.ts +129 -4
  86. package/src/linter/lintProject.ts +55 -18
  87. package/src/linter/segmentSchema.spec.ts +82 -1
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">72.38% </span>
26
+ <span class="strong">73.92% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>173/239</span>
28
+ <span class='fraction'>190/257</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">61.68% </span>
33
+ <span class="strong">62.11% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>95/154</span>
35
+ <span class='fraction'>100/161</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">52.63% </span>
40
+ <span class="strong">57.14% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>10/19</span>
42
+ <span class='fraction'>12/21</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">74.56% </span>
47
+ <span class="strong">76% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>173/232</span>
49
+ <span class='fraction'>190/250</span>
50
50
  </div>
51
51
 
52
52
 
@@ -763,7 +763,44 @@
763
763
  <a name='L698'></a><a href='#L698'>698</a>
764
764
  <a name='L699'></a><a href='#L699'>699</a>
765
765
  <a name='L700'></a><a href='#L700'>700</a>
766
- <a name='L701'></a><a href='#L701'>701</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
766
+ <a name='L701'></a><a href='#L701'>701</a>
767
+ <a name='L702'></a><a href='#L702'>702</a>
768
+ <a name='L703'></a><a href='#L703'>703</a>
769
+ <a name='L704'></a><a href='#L704'>704</a>
770
+ <a name='L705'></a><a href='#L705'>705</a>
771
+ <a name='L706'></a><a href='#L706'>706</a>
772
+ <a name='L707'></a><a href='#L707'>707</a>
773
+ <a name='L708'></a><a href='#L708'>708</a>
774
+ <a name='L709'></a><a href='#L709'>709</a>
775
+ <a name='L710'></a><a href='#L710'>710</a>
776
+ <a name='L711'></a><a href='#L711'>711</a>
777
+ <a name='L712'></a><a href='#L712'>712</a>
778
+ <a name='L713'></a><a href='#L713'>713</a>
779
+ <a name='L714'></a><a href='#L714'>714</a>
780
+ <a name='L715'></a><a href='#L715'>715</a>
781
+ <a name='L716'></a><a href='#L716'>716</a>
782
+ <a name='L717'></a><a href='#L717'>717</a>
783
+ <a name='L718'></a><a href='#L718'>718</a>
784
+ <a name='L719'></a><a href='#L719'>719</a>
785
+ <a name='L720'></a><a href='#L720'>720</a>
786
+ <a name='L721'></a><a href='#L721'>721</a>
787
+ <a name='L722'></a><a href='#L722'>722</a>
788
+ <a name='L723'></a><a href='#L723'>723</a>
789
+ <a name='L724'></a><a href='#L724'>724</a>
790
+ <a name='L725'></a><a href='#L725'>725</a>
791
+ <a name='L726'></a><a href='#L726'>726</a>
792
+ <a name='L727'></a><a href='#L727'>727</a>
793
+ <a name='L728'></a><a href='#L728'>728</a>
794
+ <a name='L729'></a><a href='#L729'>729</a>
795
+ <a name='L730'></a><a href='#L730'>730</a>
796
+ <a name='L731'></a><a href='#L731'>731</a>
797
+ <a name='L732'></a><a href='#L732'>732</a>
798
+ <a name='L733'></a><a href='#L733'>733</a>
799
+ <a name='L734'></a><a href='#L734'>734</a>
800
+ <a name='L735'></a><a href='#L735'>735</a>
801
+ <a name='L736'></a><a href='#L736'>736</a>
802
+ <a name='L737'></a><a href='#L737'>737</a>
803
+ <a name='L738'></a><a href='#L738'>738</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
767
804
  <span class="cline-any cline-yes">1x</span>
768
805
  <span class="cline-any cline-neutral">&nbsp;</span>
769
806
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -824,6 +861,28 @@
824
861
  <span class="cline-any cline-no">&nbsp;</span>
825
862
  <span class="cline-any cline-neutral">&nbsp;</span>
826
863
  <span class="cline-any cline-neutral">&nbsp;</span>
864
+ <span class="cline-any cline-neutral">&nbsp;</span>
865
+ <span class="cline-any cline-neutral">&nbsp;</span>
866
+ <span class="cline-any cline-neutral">&nbsp;</span>
867
+ <span class="cline-any cline-neutral">&nbsp;</span>
868
+ <span class="cline-any cline-neutral">&nbsp;</span>
869
+ <span class="cline-any cline-yes">69x</span>
870
+ <span class="cline-any cline-neutral">&nbsp;</span>
871
+ <span class="cline-any cline-neutral">&nbsp;</span>
872
+ <span class="cline-any cline-yes">85x</span>
873
+ <span class="cline-any cline-yes">77x</span>
874
+ <span class="cline-any cline-neutral">&nbsp;</span>
875
+ <span class="cline-any cline-neutral">&nbsp;</span>
876
+ <span class="cline-any cline-yes">8x</span>
877
+ <span class="cline-any cline-yes">16x</span>
878
+ <span class="cline-any cline-yes">16x</span>
879
+ <span class="cline-any cline-yes">16x</span>
880
+ <span class="cline-any cline-neutral">&nbsp;</span>
881
+ <span class="cline-any cline-neutral">&nbsp;</span>
882
+ <span class="cline-any cline-neutral">&nbsp;</span>
883
+ <span class="cline-any cline-yes">69x</span>
884
+ <span class="cline-any cline-neutral">&nbsp;</span>
885
+ <span class="cline-any cline-neutral">&nbsp;</span>
827
886
  <span class="cline-any cline-yes">1x</span>
828
887
  <span class="cline-any cline-neutral">&nbsp;</span>
829
888
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -840,28 +899,28 @@
840
899
  <span class="cline-any cline-neutral">&nbsp;</span>
841
900
  <span class="cline-any cline-neutral">&nbsp;</span>
842
901
  <span class="cline-any cline-neutral">&nbsp;</span>
843
- <span class="cline-any cline-yes">252x</span>
844
- <span class="cline-any cline-yes">252x</span>
902
+ <span class="cline-any cline-yes">304x</span>
903
+ <span class="cline-any cline-yes">304x</span>
845
904
  <span class="cline-any cline-neutral">&nbsp;</span>
905
+ <span class="cline-any cline-yes">304x</span>
906
+ <span class="cline-any cline-yes">52x</span>
846
907
  <span class="cline-any cline-yes">252x</span>
847
- <span class="cline-any cline-yes">34x</span>
848
- <span class="cline-any cline-yes">218x</span>
849
- <span class="cline-any cline-yes">32x</span>
850
- <span class="cline-any cline-yes">186x</span>
851
- <span class="cline-any cline-yes">56x</span>
852
- <span class="cline-any cline-yes">130x</span>
908
+ <span class="cline-any cline-yes">44x</span>
909
+ <span class="cline-any cline-yes">208x</span>
910
+ <span class="cline-any cline-yes">60x</span>
911
+ <span class="cline-any cline-yes">148x</span>
853
912
  <span class="cline-any cline-yes">2x</span>
854
- <span class="cline-any cline-yes">128x</span>
913
+ <span class="cline-any cline-yes">146x</span>
855
914
  <span class="cline-any cline-yes">40x</span>
856
915
  <span class="cline-any cline-neutral">&nbsp;</span>
857
- <span class="cline-any cline-yes">88x</span>
916
+ <span class="cline-any cline-yes">106x</span>
858
917
  <span class="cline-any cline-neutral">&nbsp;</span>
859
918
  <span class="cline-any cline-neutral">&nbsp;</span>
860
- <span class="cline-any cline-yes">252x</span>
919
+ <span class="cline-any cline-yes">304x</span>
861
920
  <span class="cline-any cline-no">&nbsp;</span>
862
921
  <span class="cline-any cline-neutral">&nbsp;</span>
863
922
  <span class="cline-any cline-neutral">&nbsp;</span>
864
- <span class="cline-any cline-yes">252x</span>
923
+ <span class="cline-any cline-yes">304x</span>
865
924
  <span class="cline-any cline-neutral">&nbsp;</span>
866
925
  <span class="cline-any cline-neutral">&nbsp;</span>
867
926
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1094,6 +1153,26 @@
1094
1153
  <span class="cline-any cline-neutral">&nbsp;</span>
1095
1154
  <span class="cline-any cline-yes">6x</span>
1096
1155
  <span class="cline-any cline-yes">6x</span>
1156
+ <span class="cline-any cline-yes">6x</span>
1157
+ <span class="cline-any cline-yes">80x</span>
1158
+ <span class="cline-any cline-yes">80x</span>
1159
+ <span class="cline-any cline-neutral">&nbsp;</span>
1160
+ <span class="cline-any cline-neutral">&nbsp;</span>
1161
+ <span class="cline-any cline-neutral">&nbsp;</span>
1162
+ <span class="cline-any cline-neutral">&nbsp;</span>
1163
+ <span class="cline-any cline-neutral">&nbsp;</span>
1164
+ <span class="cline-any cline-neutral">&nbsp;</span>
1165
+ <span class="cline-any cline-yes">6x</span>
1166
+ <span class="cline-any cline-yes">6x</span>
1167
+ <span class="cline-any cline-yes">6x</span>
1168
+ <span class="cline-any cline-neutral">&nbsp;</span>
1169
+ <span class="cline-any cline-yes">6x</span>
1170
+ <span class="cline-any cline-yes">69x</span>
1171
+ <span class="cline-any cline-yes">69x</span>
1172
+ <span class="cline-any cline-neutral">&nbsp;</span>
1173
+ <span class="cline-any cline-neutral">&nbsp;</span>
1174
+ <span class="cline-any cline-neutral">&nbsp;</span>
1175
+ <span class="cline-any cline-neutral">&nbsp;</span>
1097
1176
  <span class="cline-any cline-neutral">&nbsp;</span>
1098
1177
  <span class="cline-any cline-yes">6x</span>
1099
1178
  <span class="cline-any cline-yes">3x</span>
@@ -1105,9 +1184,9 @@
1105
1184
  <span class="cline-any cline-neutral">&nbsp;</span>
1106
1185
  <span class="cline-any cline-neutral">&nbsp;</span>
1107
1186
  <span class="cline-any cline-yes">3x</span>
1108
- <span class="cline-any cline-yes">34x</span>
1187
+ <span class="cline-any cline-yes">52x</span>
1109
1188
  <span class="cline-any cline-neutral">&nbsp;</span>
1110
- <span class="cline-any cline-yes">34x</span>
1189
+ <span class="cline-any cline-yes">52x</span>
1111
1190
  <span class="cline-any cline-yes">1x</span>
1112
1191
  <span class="cline-any cline-neutral">&nbsp;</span>
1113
1192
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1118,11 +1197,11 @@
1118
1197
  <span class="cline-any cline-neutral">&nbsp;</span>
1119
1198
  <span class="cline-any cline-neutral">&nbsp;</span>
1120
1199
  <span class="cline-any cline-neutral">&nbsp;</span>
1121
- <span class="cline-any cline-yes">34x</span>
1122
- <span class="cline-any cline-yes">34x</span>
1123
- <span class="cline-any cline-yes">34x</span>
1200
+ <span class="cline-any cline-yes">52x</span>
1201
+ <span class="cline-any cline-yes">52x</span>
1202
+ <span class="cline-any cline-yes">52x</span>
1124
1203
  <span class="cline-any cline-neutral">&nbsp;</span>
1125
- <span class="cline-any cline-yes">34x</span>
1204
+ <span class="cline-any cline-yes">52x</span>
1126
1205
  <span class="cline-any cline-no">&nbsp;</span>
1127
1206
  <span class="cline-any cline-neutral">&nbsp;</span>
1128
1207
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1132,14 +1211,20 @@
1132
1211
  <span class="cline-any cline-neutral">&nbsp;</span>
1133
1212
  <span class="cline-any cline-neutral">&nbsp;</span>
1134
1213
  <span class="cline-any cline-yes">6x</span>
1214
+ <span class="cline-any cline-yes">6x</span>
1215
+ <span class="cline-any cline-yes">69x</span>
1216
+ <span class="cline-any cline-yes">69x</span>
1217
+ <span class="cline-any cline-no">&nbsp;</span>
1135
1218
  <span class="cline-any cline-neutral">&nbsp;</span>
1136
1219
  <span class="cline-any cline-neutral">&nbsp;</span>
1137
- <span class="cline-any cline-yes">6x</span>
1138
- <span class="cline-any cline-yes">6x</span>
1220
+ <span class="cline-any cline-yes">69x</span>
1139
1221
  <span class="cline-any cline-neutral">&nbsp;</span>
1222
+ <span class="cline-any cline-yes">6x</span>
1140
1223
  <span class="cline-any cline-neutral">&nbsp;</span>
1141
1224
  <span class="cline-any cline-neutral">&nbsp;</span>
1142
1225
  <span class="cline-any cline-yes">6x</span>
1226
+ <span class="cline-any cline-yes">6x</span>
1227
+ <span class="cline-any cline-yes">6x</span>
1143
1228
  <span class="cline-any cline-neutral">&nbsp;</span>
1144
1229
  <span class="cline-any cline-yes">6x</span>
1145
1230
  <span class="cline-any cline-yes">2x</span>
@@ -1149,9 +1234,9 @@
1149
1234
  <span class="cline-any cline-neutral">&nbsp;</span>
1150
1235
  <span class="cline-any cline-neutral">&nbsp;</span>
1151
1236
  <span class="cline-any cline-yes">2x</span>
1152
- <span class="cline-any cline-yes">32x</span>
1237
+ <span class="cline-any cline-yes">44x</span>
1153
1238
  <span class="cline-any cline-neutral">&nbsp;</span>
1154
- <span class="cline-any cline-yes">32x</span>
1239
+ <span class="cline-any cline-yes">44x</span>
1155
1240
  <span class="cline-any cline-no">&nbsp;</span>
1156
1241
  <span class="cline-any cline-neutral">&nbsp;</span>
1157
1242
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1162,11 +1247,11 @@
1162
1247
  <span class="cline-any cline-neutral">&nbsp;</span>
1163
1248
  <span class="cline-any cline-neutral">&nbsp;</span>
1164
1249
  <span class="cline-any cline-neutral">&nbsp;</span>
1165
- <span class="cline-any cline-yes">32x</span>
1166
- <span class="cline-any cline-yes">32x</span>
1167
- <span class="cline-any cline-yes">32x</span>
1250
+ <span class="cline-any cline-yes">44x</span>
1251
+ <span class="cline-any cline-yes">44x</span>
1252
+ <span class="cline-any cline-yes">44x</span>
1168
1253
  <span class="cline-any cline-neutral">&nbsp;</span>
1169
- <span class="cline-any cline-yes">32x</span>
1254
+ <span class="cline-any cline-yes">44x</span>
1170
1255
  <span class="cline-any cline-no">&nbsp;</span>
1171
1256
  <span class="cline-any cline-neutral">&nbsp;</span>
1172
1257
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1178,17 +1263,6 @@
1178
1263
  <span class="cline-any cline-neutral">&nbsp;</span>
1179
1264
  <span class="cline-any cline-yes">6x</span>
1180
1265
  <span class="cline-any cline-yes">6x</span>
1181
- <span class="cline-any cline-yes">6x</span>
1182
- <span class="cline-any cline-yes">80x</span>
1183
- <span class="cline-any cline-yes">80x</span>
1184
- <span class="cline-any cline-neutral">&nbsp;</span>
1185
- <span class="cline-any cline-neutral">&nbsp;</span>
1186
- <span class="cline-any cline-neutral">&nbsp;</span>
1187
- <span class="cline-any cline-neutral">&nbsp;</span>
1188
- <span class="cline-any cline-neutral">&nbsp;</span>
1189
- <span class="cline-any cline-neutral">&nbsp;</span>
1190
- <span class="cline-any cline-yes">6x</span>
1191
- <span class="cline-any cline-yes">6x</span>
1192
1266
  <span class="cline-any cline-neutral">&nbsp;</span>
1193
1267
  <span class="cline-any cline-neutral">&nbsp;</span>
1194
1268
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1206,9 +1280,9 @@
1206
1280
  <span class="cline-any cline-neutral">&nbsp;</span>
1207
1281
  <span class="cline-any cline-neutral">&nbsp;</span>
1208
1282
  <span class="cline-any cline-yes">4x</span>
1209
- <span class="cline-any cline-yes">52x</span>
1283
+ <span class="cline-any cline-yes">56x</span>
1210
1284
  <span class="cline-any cline-neutral">&nbsp;</span>
1211
- <span class="cline-any cline-yes">52x</span>
1285
+ <span class="cline-any cline-yes">56x</span>
1212
1286
  <span class="cline-any cline-no">&nbsp;</span>
1213
1287
  <span class="cline-any cline-neutral">&nbsp;</span>
1214
1288
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1221,19 +1295,19 @@
1221
1295
  <span class="cline-any cline-neutral">&nbsp;</span>
1222
1296
  <span class="cline-any cline-neutral">&nbsp;</span>
1223
1297
  <span class="cline-any cline-neutral">&nbsp;</span>
1224
- <span class="cline-any cline-yes">52x</span>
1225
- <span class="cline-any cline-yes">52x</span>
1298
+ <span class="cline-any cline-yes">56x</span>
1299
+ <span class="cline-any cline-yes">56x</span>
1226
1300
  <span class="cline-any cline-neutral">&nbsp;</span>
1227
- <span class="cline-any cline-yes">51x</span>
1301
+ <span class="cline-any cline-yes">55x</span>
1228
1302
  <span class="cline-any cline-neutral">&nbsp;</span>
1229
- <span class="cline-any cline-yes">51x</span>
1303
+ <span class="cline-any cline-yes">55x</span>
1230
1304
  <span class="cline-any cline-yes">1x</span>
1231
1305
  <span class="cline-any cline-neutral">&nbsp;</span>
1232
1306
  <span class="cline-any cline-neutral">&nbsp;</span>
1233
1307
  <span class="cline-any cline-yes">1x</span>
1234
1308
  <span class="cline-any cline-neutral">&nbsp;</span>
1235
1309
  <span class="cline-any cline-neutral">&nbsp;</span>
1236
- <span class="cline-any cline-yes">52x</span>
1310
+ <span class="cline-any cline-yes">56x</span>
1237
1311
  <span class="cline-any cline-yes">2x</span>
1238
1312
  <span class="cline-any cline-yes">2x</span>
1239
1313
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1361,9 +1435,9 @@
1361
1435
  <span class="cline-any cline-neutral">&nbsp;</span>
1362
1436
  <span class="cline-any cline-neutral">&nbsp;</span>
1363
1437
  <span class="cline-any cline-yes">3x</span>
1364
- <span class="cline-any cline-yes">88x</span>
1438
+ <span class="cline-any cline-yes">106x</span>
1365
1439
  <span class="cline-any cline-neutral">&nbsp;</span>
1366
- <span class="cline-any cline-yes">88x</span>
1440
+ <span class="cline-any cline-yes">106x</span>
1367
1441
  <span class="cline-any cline-no">&nbsp;</span>
1368
1442
  <span class="cline-any cline-neutral">&nbsp;</span>
1369
1443
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1374,12 +1448,12 @@
1374
1448
  <span class="cline-any cline-neutral">&nbsp;</span>
1375
1449
  <span class="cline-any cline-neutral">&nbsp;</span>
1376
1450
  <span class="cline-any cline-neutral">&nbsp;</span>
1377
- <span class="cline-any cline-yes">88x</span>
1378
- <span class="cline-any cline-yes">88x</span>
1451
+ <span class="cline-any cline-yes">106x</span>
1452
+ <span class="cline-any cline-yes">106x</span>
1379
1453
  <span class="cline-any cline-neutral">&nbsp;</span>
1380
- <span class="cline-any cline-yes">88x</span>
1454
+ <span class="cline-any cline-yes">106x</span>
1381
1455
  <span class="cline-any cline-neutral">&nbsp;</span>
1382
- <span class="cline-any cline-yes">88x</span>
1456
+ <span class="cline-any cline-yes">106x</span>
1383
1457
  <span class="cline-any cline-yes">1x</span>
1384
1458
  <span class="cline-any cline-neutral">&nbsp;</span>
1385
1459
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -1466,7 +1540,7 @@
1466
1540
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">// for use in node only
1467
1541
  import * as path from "path";
1468
1542
  &nbsp;
1469
- import type { Schema } from "@featurevisor/types";
1543
+ import type { Attribute, Schema } from "@featurevisor/types";
1470
1544
  import type { ZodError } from "zod";
1471
1545
  &nbsp;
1472
1546
  import { getAttributeZodSchema } from "./attributeSchema";
@@ -1524,6 +1598,28 @@ async function <span class="fstat-no" title="function not covered" >getAuthorsOf
1524
1598
  <span class="cstat-no" title="statement not covered" > return authors;</span>
1525
1599
  }
1526
1600
  &nbsp;
1601
+ function collectExplicitAttributePaths(
1602
+ attributeKey: string,
1603
+ attribute: Attribute,
1604
+ result: Set&lt;string&gt;,
1605
+ ): void {
1606
+ result.add(attributeKey);
1607
+ &nbsp;
1608
+ function visit(prefix: string, schema: Attribute | Attribute["properties"][string]) {
1609
+ if (!schema || schema.type !== "object" || !schema.properties) {
1610
+ return;
1611
+ }
1612
+ &nbsp;
1613
+ for (const propertyKey of Object.keys(schema.properties)) {
1614
+ const propertyPath = `${prefix}.${propertyKey}`;
1615
+ result.add(propertyPath);
1616
+ visit(propertyPath, schema.properties[propertyKey]);
1617
+ }
1618
+ }
1619
+ &nbsp;
1620
+ visit(attributeKey, attribute);
1621
+ }
1622
+ &nbsp;
1527
1623
  export async function lintProject(
1528
1624
  deps: Dependencies,
1529
1625
  options: LintProjectOptions = <span class="branch-0 cbranch-no" title="branch not covered" >{},</span>
@@ -1790,10 +1886,30 @@ export async function lintProject(
1790
1886
  <span class="cstat-no" title="statement not covered" > log(`Linting only keys matching pattern: ${keyPattern}`);</span>
1791
1887
  <span class="cstat-no" title="statement not covered" > log("");</span>
1792
1888
  }
1889
+ &nbsp;
1890
+ // List schemas and load parsed schemas for attribute and feature validation.
1891
+ const schemas = await datasource.listSchemas();
1892
+ const schemasByKey: Record&lt;string, Schema&gt; = {};
1893
+ for (const key of schemas) {
1894
+ try {
1895
+ schemasByKey[key] = await datasource.readSchema(key);
1896
+ } catch {
1897
+ // Schema file may be invalid; skip for cross-entity resolution and let schema linting report it.
1898
+ }
1899
+ }
1793
1900
  &nbsp;
1794
1901
  // lint attributes
1795
1902
  const attributes = await datasource.listAttributes();
1796
1903
  const attributeZodSchema = getAttributeZodSchema();
1904
+ const attributesByKey: Record&lt;string, Attribute&gt; = {};
1905
+ &nbsp;
1906
+ for (const key of attributes) {
1907
+ try {
1908
+ attributesByKey[key] = await datasource.readAttribute(key);
1909
+ } catch {
1910
+ // Attribute read failures are reported during attribute linting below.
1911
+ }
1912
+ }
1797
1913
  &nbsp;
1798
1914
  if (!options.entityType || options.entityType === "attribute") {
1799
1915
  const filteredKeys = !keyPattern
@@ -1819,7 +1935,7 @@ export async function lintProject(
1819
1935
  }
1820
1936
  &nbsp;
1821
1937
  try {
1822
- const parsed = await datasource.readAttribute(key);
1938
+ const parsed = attributesByKey[key] ?? (<span class="branch-1 cbranch-no" title="branch not covered" >await datasource.readAttribute(key))</span>;
1823
1939
  const result = attributeZodSchema.safeParse(parsed);
1824
1940
  &nbsp;
1825
1941
  <span class="missing-if-branch" title="if path not taken" >I</span>if (!result.success &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >"error" in result)</span> {
@@ -1831,14 +1947,20 @@ export async function lintProject(
1831
1947
  }
1832
1948
  }
1833
1949
  &nbsp;
1834
- const flattenedAttributes = await datasource.listFlattenedAttributes();
1950
+ const explicitAttributePaths = new Set&lt;string&gt;();
1951
+ for (const key of attributes) {
1952
+ const parsed = attributesByKey[key];
1953
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!parsed) {
1954
+ <span class="cstat-no" title="statement not covered" > continue;</span>
1955
+ }
1956
+ &nbsp;
1957
+ collectExplicitAttributePaths(key, parsed, explicitAttributePaths);
1958
+ }
1959
+ const flattenedAttributes = Array.from(explicitAttributePaths);
1835
1960
  &nbsp;
1836
1961
  // lint segments
1837
1962
  const segments = await datasource.listSegments();
1838
- const conditionsZodSchema = getConditionsZodSchema(
1839
- projectConfig,
1840
- flattenedAttributes as [string, ...string[]],
1841
- );
1963
+ const conditionsZodSchema = getConditionsZodSchema(projectConfig, attributesByKey, schemasByKey);
1842
1964
  const segmentZodSchema = getSegmentZodSchema(projectConfig, conditionsZodSchema);
1843
1965
  &nbsp;
1844
1966
  if (!options.entityType || options.entityType === "segment") {
@@ -1874,17 +1996,6 @@ export async function lintProject(
1874
1996
  }
1875
1997
  }
1876
1998
  }
1877
- &nbsp;
1878
- // List schemas and load parsed schemas for feature variable validation (schema references)
1879
- const schemas = await datasource.listSchemas();
1880
- const schemasByKey: Record&lt;string, Schema&gt; = {};
1881
- for (const key of schemas) {
1882
- try {
1883
- schemasByKey[key] = await datasource.readSchema(key);
1884
- } catch {
1885
- // Schema file may be invalid; skip for feature variable resolution
1886
- }
1887
- }
1888
1999
  &nbsp;
1889
2000
  // lint features
1890
2001
  const features = await datasource.listFeatures();
@@ -2170,7 +2281,7 @@ export const lintPlugin: Plugin = {
2170
2281
  <div class='footer quiet pad2 space-top1 center small'>
2171
2282
  Code coverage generated by
2172
2283
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
2173
- at 2026-03-01T23:08:13.696Z
2284
+ at 2026-04-08T20:42:08.360Z
2174
2285
  </div>
2175
2286
  <script src="../prettify.js"></script>
2176
2287
  <script>
@@ -1396,7 +1396,7 @@ export function parsePathMapKey(relativePath: string): PathSegment[] | null {
1396
1396
  <div class='footer quiet pad2 space-top1 center small'>
1397
1397
  Code coverage generated by
1398
1398
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1399
- at 2026-03-01T23:08:13.696Z
1399
+ at 2026-04-08T20:42:08.360Z
1400
1400
  </div>
1401
1401
  <script src="../prettify.js"></script>
1402
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-03-01T23:08:13.696Z
226
+ at 2026-04-08T20:42:08.360Z
227
227
  </div>
228
228
  <script src="../prettify.js"></script>
229
229
  <script>