@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">86.79% </span>
26
+ <span class="strong">60.76% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>46/53</span>
28
+ <span class='fraction'>175/288</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">83.33% </span>
33
+ <span class="strong">58.94% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>35/42</span>
35
+ <span class='fraction'>145/246</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">100% </span>
40
+ <span class="strong">73.8% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>9/9</span>
42
+ <span class='fraction'>31/42</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">86.79% </span>
47
+ <span class="strong">64.15% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>46/53</span>
49
+ <span class='fraction'>170/265</span>
50
50
  </div>
51
51
 
52
52
 
@@ -61,7 +61,7 @@
61
61
  </div>
62
62
  </template>
63
63
  </div>
64
- <div class='status-line high'></div>
64
+ <div class='status-line medium'></div>
65
65
  <pre><table class="coverage">
66
66
  <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
67
  <a name='L2'></a><a href='#L2'>2</a>
@@ -293,48 +293,903 @@
293
293
  <a name='L228'></a><a href='#L228'>228</a>
294
294
  <a name='L229'></a><a href='#L229'>229</a>
295
295
  <a name='L230'></a><a href='#L230'>230</a>
296
- <a name='L231'></a><a href='#L231'>231</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">4x</span>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a>
381
+ <a name='L316'></a><a href='#L316'>316</a>
382
+ <a name='L317'></a><a href='#L317'>317</a>
383
+ <a name='L318'></a><a href='#L318'>318</a>
384
+ <a name='L319'></a><a href='#L319'>319</a>
385
+ <a name='L320'></a><a href='#L320'>320</a>
386
+ <a name='L321'></a><a href='#L321'>321</a>
387
+ <a name='L322'></a><a href='#L322'>322</a>
388
+ <a name='L323'></a><a href='#L323'>323</a>
389
+ <a name='L324'></a><a href='#L324'>324</a>
390
+ <a name='L325'></a><a href='#L325'>325</a>
391
+ <a name='L326'></a><a href='#L326'>326</a>
392
+ <a name='L327'></a><a href='#L327'>327</a>
393
+ <a name='L328'></a><a href='#L328'>328</a>
394
+ <a name='L329'></a><a href='#L329'>329</a>
395
+ <a name='L330'></a><a href='#L330'>330</a>
396
+ <a name='L331'></a><a href='#L331'>331</a>
397
+ <a name='L332'></a><a href='#L332'>332</a>
398
+ <a name='L333'></a><a href='#L333'>333</a>
399
+ <a name='L334'></a><a href='#L334'>334</a>
400
+ <a name='L335'></a><a href='#L335'>335</a>
401
+ <a name='L336'></a><a href='#L336'>336</a>
402
+ <a name='L337'></a><a href='#L337'>337</a>
403
+ <a name='L338'></a><a href='#L338'>338</a>
404
+ <a name='L339'></a><a href='#L339'>339</a>
405
+ <a name='L340'></a><a href='#L340'>340</a>
406
+ <a name='L341'></a><a href='#L341'>341</a>
407
+ <a name='L342'></a><a href='#L342'>342</a>
408
+ <a name='L343'></a><a href='#L343'>343</a>
409
+ <a name='L344'></a><a href='#L344'>344</a>
410
+ <a name='L345'></a><a href='#L345'>345</a>
411
+ <a name='L346'></a><a href='#L346'>346</a>
412
+ <a name='L347'></a><a href='#L347'>347</a>
413
+ <a name='L348'></a><a href='#L348'>348</a>
414
+ <a name='L349'></a><a href='#L349'>349</a>
415
+ <a name='L350'></a><a href='#L350'>350</a>
416
+ <a name='L351'></a><a href='#L351'>351</a>
417
+ <a name='L352'></a><a href='#L352'>352</a>
418
+ <a name='L353'></a><a href='#L353'>353</a>
419
+ <a name='L354'></a><a href='#L354'>354</a>
420
+ <a name='L355'></a><a href='#L355'>355</a>
421
+ <a name='L356'></a><a href='#L356'>356</a>
422
+ <a name='L357'></a><a href='#L357'>357</a>
423
+ <a name='L358'></a><a href='#L358'>358</a>
424
+ <a name='L359'></a><a href='#L359'>359</a>
425
+ <a name='L360'></a><a href='#L360'>360</a>
426
+ <a name='L361'></a><a href='#L361'>361</a>
427
+ <a name='L362'></a><a href='#L362'>362</a>
428
+ <a name='L363'></a><a href='#L363'>363</a>
429
+ <a name='L364'></a><a href='#L364'>364</a>
430
+ <a name='L365'></a><a href='#L365'>365</a>
431
+ <a name='L366'></a><a href='#L366'>366</a>
432
+ <a name='L367'></a><a href='#L367'>367</a>
433
+ <a name='L368'></a><a href='#L368'>368</a>
434
+ <a name='L369'></a><a href='#L369'>369</a>
435
+ <a name='L370'></a><a href='#L370'>370</a>
436
+ <a name='L371'></a><a href='#L371'>371</a>
437
+ <a name='L372'></a><a href='#L372'>372</a>
438
+ <a name='L373'></a><a href='#L373'>373</a>
439
+ <a name='L374'></a><a href='#L374'>374</a>
440
+ <a name='L375'></a><a href='#L375'>375</a>
441
+ <a name='L376'></a><a href='#L376'>376</a>
442
+ <a name='L377'></a><a href='#L377'>377</a>
443
+ <a name='L378'></a><a href='#L378'>378</a>
444
+ <a name='L379'></a><a href='#L379'>379</a>
445
+ <a name='L380'></a><a href='#L380'>380</a>
446
+ <a name='L381'></a><a href='#L381'>381</a>
447
+ <a name='L382'></a><a href='#L382'>382</a>
448
+ <a name='L383'></a><a href='#L383'>383</a>
449
+ <a name='L384'></a><a href='#L384'>384</a>
450
+ <a name='L385'></a><a href='#L385'>385</a>
451
+ <a name='L386'></a><a href='#L386'>386</a>
452
+ <a name='L387'></a><a href='#L387'>387</a>
453
+ <a name='L388'></a><a href='#L388'>388</a>
454
+ <a name='L389'></a><a href='#L389'>389</a>
455
+ <a name='L390'></a><a href='#L390'>390</a>
456
+ <a name='L391'></a><a href='#L391'>391</a>
457
+ <a name='L392'></a><a href='#L392'>392</a>
458
+ <a name='L393'></a><a href='#L393'>393</a>
459
+ <a name='L394'></a><a href='#L394'>394</a>
460
+ <a name='L395'></a><a href='#L395'>395</a>
461
+ <a name='L396'></a><a href='#L396'>396</a>
462
+ <a name='L397'></a><a href='#L397'>397</a>
463
+ <a name='L398'></a><a href='#L398'>398</a>
464
+ <a name='L399'></a><a href='#L399'>399</a>
465
+ <a name='L400'></a><a href='#L400'>400</a>
466
+ <a name='L401'></a><a href='#L401'>401</a>
467
+ <a name='L402'></a><a href='#L402'>402</a>
468
+ <a name='L403'></a><a href='#L403'>403</a>
469
+ <a name='L404'></a><a href='#L404'>404</a>
470
+ <a name='L405'></a><a href='#L405'>405</a>
471
+ <a name='L406'></a><a href='#L406'>406</a>
472
+ <a name='L407'></a><a href='#L407'>407</a>
473
+ <a name='L408'></a><a href='#L408'>408</a>
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>
509
+ <a name='L444'></a><a href='#L444'>444</a>
510
+ <a name='L445'></a><a href='#L445'>445</a>
511
+ <a name='L446'></a><a href='#L446'>446</a>
512
+ <a name='L447'></a><a href='#L447'>447</a>
513
+ <a name='L448'></a><a href='#L448'>448</a>
514
+ <a name='L449'></a><a href='#L449'>449</a>
515
+ <a name='L450'></a><a href='#L450'>450</a>
516
+ <a name='L451'></a><a href='#L451'>451</a>
517
+ <a name='L452'></a><a href='#L452'>452</a>
518
+ <a name='L453'></a><a href='#L453'>453</a>
519
+ <a name='L454'></a><a href='#L454'>454</a>
520
+ <a name='L455'></a><a href='#L455'>455</a>
521
+ <a name='L456'></a><a href='#L456'>456</a>
522
+ <a name='L457'></a><a href='#L457'>457</a>
523
+ <a name='L458'></a><a href='#L458'>458</a>
524
+ <a name='L459'></a><a href='#L459'>459</a>
525
+ <a name='L460'></a><a href='#L460'>460</a>
526
+ <a name='L461'></a><a href='#L461'>461</a>
527
+ <a name='L462'></a><a href='#L462'>462</a>
528
+ <a name='L463'></a><a href='#L463'>463</a>
529
+ <a name='L464'></a><a href='#L464'>464</a>
530
+ <a name='L465'></a><a href='#L465'>465</a>
531
+ <a name='L466'></a><a href='#L466'>466</a>
532
+ <a name='L467'></a><a href='#L467'>467</a>
533
+ <a name='L468'></a><a href='#L468'>468</a>
534
+ <a name='L469'></a><a href='#L469'>469</a>
535
+ <a name='L470'></a><a href='#L470'>470</a>
536
+ <a name='L471'></a><a href='#L471'>471</a>
537
+ <a name='L472'></a><a href='#L472'>472</a>
538
+ <a name='L473'></a><a href='#L473'>473</a>
539
+ <a name='L474'></a><a href='#L474'>474</a>
540
+ <a name='L475'></a><a href='#L475'>475</a>
541
+ <a name='L476'></a><a href='#L476'>476</a>
542
+ <a name='L477'></a><a href='#L477'>477</a>
543
+ <a name='L478'></a><a href='#L478'>478</a>
544
+ <a name='L479'></a><a href='#L479'>479</a>
545
+ <a name='L480'></a><a href='#L480'>480</a>
546
+ <a name='L481'></a><a href='#L481'>481</a>
547
+ <a name='L482'></a><a href='#L482'>482</a>
548
+ <a name='L483'></a><a href='#L483'>483</a>
549
+ <a name='L484'></a><a href='#L484'>484</a>
550
+ <a name='L485'></a><a href='#L485'>485</a>
551
+ <a name='L486'></a><a href='#L486'>486</a>
552
+ <a name='L487'></a><a href='#L487'>487</a>
553
+ <a name='L488'></a><a href='#L488'>488</a>
554
+ <a name='L489'></a><a href='#L489'>489</a>
555
+ <a name='L490'></a><a href='#L490'>490</a>
556
+ <a name='L491'></a><a href='#L491'>491</a>
557
+ <a name='L492'></a><a href='#L492'>492</a>
558
+ <a name='L493'></a><a href='#L493'>493</a>
559
+ <a name='L494'></a><a href='#L494'>494</a>
560
+ <a name='L495'></a><a href='#L495'>495</a>
561
+ <a name='L496'></a><a href='#L496'>496</a>
562
+ <a name='L497'></a><a href='#L497'>497</a>
563
+ <a name='L498'></a><a href='#L498'>498</a>
564
+ <a name='L499'></a><a href='#L499'>499</a>
565
+ <a name='L500'></a><a href='#L500'>500</a>
566
+ <a name='L501'></a><a href='#L501'>501</a>
567
+ <a name='L502'></a><a href='#L502'>502</a>
568
+ <a name='L503'></a><a href='#L503'>503</a>
569
+ <a name='L504'></a><a href='#L504'>504</a>
570
+ <a name='L505'></a><a href='#L505'>505</a>
571
+ <a name='L506'></a><a href='#L506'>506</a>
572
+ <a name='L507'></a><a href='#L507'>507</a>
573
+ <a name='L508'></a><a href='#L508'>508</a>
574
+ <a name='L509'></a><a href='#L509'>509</a>
575
+ <a name='L510'></a><a href='#L510'>510</a>
576
+ <a name='L511'></a><a href='#L511'>511</a>
577
+ <a name='L512'></a><a href='#L512'>512</a>
578
+ <a name='L513'></a><a href='#L513'>513</a>
579
+ <a name='L514'></a><a href='#L514'>514</a>
580
+ <a name='L515'></a><a href='#L515'>515</a>
581
+ <a name='L516'></a><a href='#L516'>516</a>
582
+ <a name='L517'></a><a href='#L517'>517</a>
583
+ <a name='L518'></a><a href='#L518'>518</a>
584
+ <a name='L519'></a><a href='#L519'>519</a>
585
+ <a name='L520'></a><a href='#L520'>520</a>
586
+ <a name='L521'></a><a href='#L521'>521</a>
587
+ <a name='L522'></a><a href='#L522'>522</a>
588
+ <a name='L523'></a><a href='#L523'>523</a>
589
+ <a name='L524'></a><a href='#L524'>524</a>
590
+ <a name='L525'></a><a href='#L525'>525</a>
591
+ <a name='L526'></a><a href='#L526'>526</a>
592
+ <a name='L527'></a><a href='#L527'>527</a>
593
+ <a name='L528'></a><a href='#L528'>528</a>
594
+ <a name='L529'></a><a href='#L529'>529</a>
595
+ <a name='L530'></a><a href='#L530'>530</a>
596
+ <a name='L531'></a><a href='#L531'>531</a>
597
+ <a name='L532'></a><a href='#L532'>532</a>
598
+ <a name='L533'></a><a href='#L533'>533</a>
599
+ <a name='L534'></a><a href='#L534'>534</a>
600
+ <a name='L535'></a><a href='#L535'>535</a>
601
+ <a name='L536'></a><a href='#L536'>536</a>
602
+ <a name='L537'></a><a href='#L537'>537</a>
603
+ <a name='L538'></a><a href='#L538'>538</a>
604
+ <a name='L539'></a><a href='#L539'>539</a>
605
+ <a name='L540'></a><a href='#L540'>540</a>
606
+ <a name='L541'></a><a href='#L541'>541</a>
607
+ <a name='L542'></a><a href='#L542'>542</a>
608
+ <a name='L543'></a><a href='#L543'>543</a>
609
+ <a name='L544'></a><a href='#L544'>544</a>
610
+ <a name='L545'></a><a href='#L545'>545</a>
611
+ <a name='L546'></a><a href='#L546'>546</a>
612
+ <a name='L547'></a><a href='#L547'>547</a>
613
+ <a name='L548'></a><a href='#L548'>548</a>
614
+ <a name='L549'></a><a href='#L549'>549</a>
615
+ <a name='L550'></a><a href='#L550'>550</a>
616
+ <a name='L551'></a><a href='#L551'>551</a>
617
+ <a name='L552'></a><a href='#L552'>552</a>
618
+ <a name='L553'></a><a href='#L553'>553</a>
619
+ <a name='L554'></a><a href='#L554'>554</a>
620
+ <a name='L555'></a><a href='#L555'>555</a>
621
+ <a name='L556'></a><a href='#L556'>556</a>
622
+ <a name='L557'></a><a href='#L557'>557</a>
623
+ <a name='L558'></a><a href='#L558'>558</a>
624
+ <a name='L559'></a><a href='#L559'>559</a>
625
+ <a name='L560'></a><a href='#L560'>560</a>
626
+ <a name='L561'></a><a href='#L561'>561</a>
627
+ <a name='L562'></a><a href='#L562'>562</a>
628
+ <a name='L563'></a><a href='#L563'>563</a>
629
+ <a name='L564'></a><a href='#L564'>564</a>
630
+ <a name='L565'></a><a href='#L565'>565</a>
631
+ <a name='L566'></a><a href='#L566'>566</a>
632
+ <a name='L567'></a><a href='#L567'>567</a>
633
+ <a name='L568'></a><a href='#L568'>568</a>
634
+ <a name='L569'></a><a href='#L569'>569</a>
635
+ <a name='L570'></a><a href='#L570'>570</a>
636
+ <a name='L571'></a><a href='#L571'>571</a>
637
+ <a name='L572'></a><a href='#L572'>572</a>
638
+ <a name='L573'></a><a href='#L573'>573</a>
639
+ <a name='L574'></a><a href='#L574'>574</a>
640
+ <a name='L575'></a><a href='#L575'>575</a>
641
+ <a name='L576'></a><a href='#L576'>576</a>
642
+ <a name='L577'></a><a href='#L577'>577</a>
643
+ <a name='L578'></a><a href='#L578'>578</a>
644
+ <a name='L579'></a><a href='#L579'>579</a>
645
+ <a name='L580'></a><a href='#L580'>580</a>
646
+ <a name='L581'></a><a href='#L581'>581</a>
647
+ <a name='L582'></a><a href='#L582'>582</a>
648
+ <a name='L583'></a><a href='#L583'>583</a>
649
+ <a name='L584'></a><a href='#L584'>584</a>
650
+ <a name='L585'></a><a href='#L585'>585</a>
651
+ <a name='L586'></a><a href='#L586'>586</a>
652
+ <a name='L587'></a><a href='#L587'>587</a>
653
+ <a name='L588'></a><a href='#L588'>588</a>
654
+ <a name='L589'></a><a href='#L589'>589</a>
655
+ <a name='L590'></a><a href='#L590'>590</a>
656
+ <a name='L591'></a><a href='#L591'>591</a>
657
+ <a name='L592'></a><a href='#L592'>592</a>
658
+ <a name='L593'></a><a href='#L593'>593</a>
659
+ <a name='L594'></a><a href='#L594'>594</a>
660
+ <a name='L595'></a><a href='#L595'>595</a>
661
+ <a name='L596'></a><a href='#L596'>596</a>
662
+ <a name='L597'></a><a href='#L597'>597</a>
663
+ <a name='L598'></a><a href='#L598'>598</a>
664
+ <a name='L599'></a><a href='#L599'>599</a>
665
+ <a name='L600'></a><a href='#L600'>600</a>
666
+ <a name='L601'></a><a href='#L601'>601</a>
667
+ <a name='L602'></a><a href='#L602'>602</a>
668
+ <a name='L603'></a><a href='#L603'>603</a>
669
+ <a name='L604'></a><a href='#L604'>604</a>
670
+ <a name='L605'></a><a href='#L605'>605</a>
671
+ <a name='L606'></a><a href='#L606'>606</a>
672
+ <a name='L607'></a><a href='#L607'>607</a>
673
+ <a name='L608'></a><a href='#L608'>608</a>
674
+ <a name='L609'></a><a href='#L609'>609</a>
675
+ <a name='L610'></a><a href='#L610'>610</a>
676
+ <a name='L611'></a><a href='#L611'>611</a>
677
+ <a name='L612'></a><a href='#L612'>612</a>
678
+ <a name='L613'></a><a href='#L613'>613</a>
679
+ <a name='L614'></a><a href='#L614'>614</a>
680
+ <a name='L615'></a><a href='#L615'>615</a>
681
+ <a name='L616'></a><a href='#L616'>616</a>
682
+ <a name='L617'></a><a href='#L617'>617</a>
683
+ <a name='L618'></a><a href='#L618'>618</a>
684
+ <a name='L619'></a><a href='#L619'>619</a>
685
+ <a name='L620'></a><a href='#L620'>620</a>
686
+ <a name='L621'></a><a href='#L621'>621</a>
687
+ <a name='L622'></a><a href='#L622'>622</a>
688
+ <a name='L623'></a><a href='#L623'>623</a>
689
+ <a name='L624'></a><a href='#L624'>624</a>
690
+ <a name='L625'></a><a href='#L625'>625</a>
691
+ <a name='L626'></a><a href='#L626'>626</a>
692
+ <a name='L627'></a><a href='#L627'>627</a>
693
+ <a name='L628'></a><a href='#L628'>628</a>
694
+ <a name='L629'></a><a href='#L629'>629</a>
695
+ <a name='L630'></a><a href='#L630'>630</a>
696
+ <a name='L631'></a><a href='#L631'>631</a>
697
+ <a name='L632'></a><a href='#L632'>632</a>
698
+ <a name='L633'></a><a href='#L633'>633</a>
699
+ <a name='L634'></a><a href='#L634'>634</a>
700
+ <a name='L635'></a><a href='#L635'>635</a>
701
+ <a name='L636'></a><a href='#L636'>636</a>
702
+ <a name='L637'></a><a href='#L637'>637</a>
703
+ <a name='L638'></a><a href='#L638'>638</a>
704
+ <a name='L639'></a><a href='#L639'>639</a>
705
+ <a name='L640'></a><a href='#L640'>640</a>
706
+ <a name='L641'></a><a href='#L641'>641</a>
707
+ <a name='L642'></a><a href='#L642'>642</a>
708
+ <a name='L643'></a><a href='#L643'>643</a>
709
+ <a name='L644'></a><a href='#L644'>644</a>
710
+ <a name='L645'></a><a href='#L645'>645</a>
711
+ <a name='L646'></a><a href='#L646'>646</a>
712
+ <a name='L647'></a><a href='#L647'>647</a>
713
+ <a name='L648'></a><a href='#L648'>648</a>
714
+ <a name='L649'></a><a href='#L649'>649</a>
715
+ <a name='L650'></a><a href='#L650'>650</a>
716
+ <a name='L651'></a><a href='#L651'>651</a>
717
+ <a name='L652'></a><a href='#L652'>652</a>
718
+ <a name='L653'></a><a href='#L653'>653</a>
719
+ <a name='L654'></a><a href='#L654'>654</a>
720
+ <a name='L655'></a><a href='#L655'>655</a>
721
+ <a name='L656'></a><a href='#L656'>656</a>
722
+ <a name='L657'></a><a href='#L657'>657</a>
723
+ <a name='L658'></a><a href='#L658'>658</a>
724
+ <a name='L659'></a><a href='#L659'>659</a>
725
+ <a name='L660'></a><a href='#L660'>660</a>
726
+ <a name='L661'></a><a href='#L661'>661</a>
727
+ <a name='L662'></a><a href='#L662'>662</a>
728
+ <a name='L663'></a><a href='#L663'>663</a>
729
+ <a name='L664'></a><a href='#L664'>664</a>
730
+ <a name='L665'></a><a href='#L665'>665</a>
731
+ <a name='L666'></a><a href='#L666'>666</a>
732
+ <a name='L667'></a><a href='#L667'>667</a>
733
+ <a name='L668'></a><a href='#L668'>668</a>
734
+ <a name='L669'></a><a href='#L669'>669</a>
735
+ <a name='L670'></a><a href='#L670'>670</a>
736
+ <a name='L671'></a><a href='#L671'>671</a>
737
+ <a name='L672'></a><a href='#L672'>672</a>
738
+ <a name='L673'></a><a href='#L673'>673</a>
739
+ <a name='L674'></a><a href='#L674'>674</a>
740
+ <a name='L675'></a><a href='#L675'>675</a>
741
+ <a name='L676'></a><a href='#L676'>676</a>
742
+ <a name='L677'></a><a href='#L677'>677</a>
743
+ <a name='L678'></a><a href='#L678'>678</a>
744
+ <a name='L679'></a><a href='#L679'>679</a>
745
+ <a name='L680'></a><a href='#L680'>680</a>
746
+ <a name='L681'></a><a href='#L681'>681</a>
747
+ <a name='L682'></a><a href='#L682'>682</a>
748
+ <a name='L683'></a><a href='#L683'>683</a>
749
+ <a name='L684'></a><a href='#L684'>684</a>
750
+ <a name='L685'></a><a href='#L685'>685</a>
751
+ <a name='L686'></a><a href='#L686'>686</a>
752
+ <a name='L687'></a><a href='#L687'>687</a>
753
+ <a name='L688'></a><a href='#L688'>688</a>
754
+ <a name='L689'></a><a href='#L689'>689</a>
755
+ <a name='L690'></a><a href='#L690'>690</a>
756
+ <a name='L691'></a><a href='#L691'>691</a>
757
+ <a name='L692'></a><a href='#L692'>692</a>
758
+ <a name='L693'></a><a href='#L693'>693</a>
759
+ <a name='L694'></a><a href='#L694'>694</a>
760
+ <a name='L695'></a><a href='#L695'>695</a>
761
+ <a name='L696'></a><a href='#L696'>696</a>
762
+ <a name='L697'></a><a href='#L697'>697</a>
763
+ <a name='L698'></a><a href='#L698'>698</a>
764
+ <a name='L699'></a><a href='#L699'>699</a>
765
+ <a name='L700'></a><a href='#L700'>700</a>
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></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
780
+ <span class="cline-any cline-yes">4x</span>
781
+ <span class="cline-any cline-neutral">&nbsp;</span>
782
+ <span class="cline-any cline-neutral">&nbsp;</span>
783
+ <span class="cline-any cline-neutral">&nbsp;</span>
784
+ <span class="cline-any cline-yes">4x</span>
785
+ <span class="cline-any cline-yes">4x</span>
786
+ <span class="cline-any cline-yes">4x</span>
787
+ <span class="cline-any cline-neutral">&nbsp;</span>
788
+ <span class="cline-any cline-neutral">&nbsp;</span>
789
+ <span class="cline-any cline-neutral">&nbsp;</span>
790
+ <span class="cline-any cline-neutral">&nbsp;</span>
791
+ <span class="cline-any cline-neutral">&nbsp;</span>
792
+ <span class="cline-any cline-neutral">&nbsp;</span>
793
+ <span class="cline-any cline-neutral">&nbsp;</span>
794
+ <span class="cline-any cline-yes">4x</span>
795
+ <span class="cline-any cline-neutral">&nbsp;</span>
796
+ <span class="cline-any cline-neutral">&nbsp;</span>
797
+ <span class="cline-any cline-neutral">&nbsp;</span>
798
+ <span class="cline-any cline-neutral">&nbsp;</span>
799
+ <span class="cline-any cline-neutral">&nbsp;</span>
800
+ <span class="cline-any cline-neutral">&nbsp;</span>
801
+ <span class="cline-any cline-neutral">&nbsp;</span>
802
+ <span class="cline-any cline-yes">4x</span>
803
+ <span class="cline-any cline-yes">4x</span>
804
+ <span class="cline-any cline-yes">4x</span>
805
+ <span class="cline-any cline-yes">4x</span>
806
+ <span class="cline-any cline-neutral">&nbsp;</span>
807
+ <span class="cline-any cline-yes">4x</span>
808
+ <span class="cline-any cline-neutral">&nbsp;</span>
809
+ <span class="cline-any cline-neutral">&nbsp;</span>
810
+ <span class="cline-any cline-neutral">&nbsp;</span>
811
+ <span class="cline-any cline-neutral">&nbsp;</span>
812
+ <span class="cline-any cline-neutral">&nbsp;</span>
813
+ <span class="cline-any cline-neutral">&nbsp;</span>
814
+ <span class="cline-any cline-neutral">&nbsp;</span>
815
+ <span class="cline-any cline-neutral">&nbsp;</span>
816
+ <span class="cline-any cline-yes">6x</span>
817
+ <span class="cline-any cline-neutral">&nbsp;</span>
818
+ <span class="cline-any cline-neutral">&nbsp;</span>
819
+ <span class="cline-any cline-neutral">&nbsp;</span>
820
+ <span class="cline-any cline-yes">5x</span>
821
+ <span class="cline-any cline-neutral">&nbsp;</span>
822
+ <span class="cline-any cline-neutral">&nbsp;</span>
823
+ <span class="cline-any cline-neutral">&nbsp;</span>
824
+ <span class="cline-any cline-neutral">&nbsp;</span>
825
+ <span class="cline-any cline-neutral">&nbsp;</span>
826
+ <span class="cline-any cline-neutral">&nbsp;</span>
827
+ <span class="cline-any cline-neutral">&nbsp;</span>
828
+ <span class="cline-any cline-neutral">&nbsp;</span>
829
+ <span class="cline-any cline-yes">13x</span>
830
+ <span class="cline-any cline-neutral">&nbsp;</span>
831
+ <span class="cline-any cline-neutral">&nbsp;</span>
832
+ <span class="cline-any cline-neutral">&nbsp;</span>
833
+ <span class="cline-any cline-yes">63x</span>
834
+ <span class="cline-any cline-yes">45x</span>
835
+ <span class="cline-any cline-yes">42x</span>
836
+ <span class="cline-any cline-neutral">&nbsp;</span>
837
+ <span class="cline-any cline-yes">42x</span>
838
+ <span class="cline-any cline-no">&nbsp;</span>
839
+ <span class="cline-any cline-no">&nbsp;</span>
840
+ <span class="cline-any cline-no">&nbsp;</span>
841
+ <span class="cline-any cline-no">&nbsp;</span>
842
+ <span class="cline-any cline-neutral">&nbsp;</span>
843
+ <span class="cline-any cline-neutral">&nbsp;</span>
844
+ <span class="cline-any cline-no">&nbsp;</span>
845
+ <span class="cline-any cline-no">&nbsp;</span>
846
+ <span class="cline-any cline-no">&nbsp;</span>
847
+ <span class="cline-any cline-no">&nbsp;</span>
848
+ <span class="cline-any cline-neutral">&nbsp;</span>
849
+ <span class="cline-any cline-neutral">&nbsp;</span>
850
+ <span class="cline-any cline-no">&nbsp;</span>
851
+ <span class="cline-any cline-no">&nbsp;</span>
852
+ <span class="cline-any cline-neutral">&nbsp;</span>
853
+ <span class="cline-any cline-neutral">&nbsp;</span>
854
+ <span class="cline-any cline-neutral">&nbsp;</span>
855
+ <span class="cline-any cline-yes">42x</span>
856
+ <span class="cline-any cline-neutral">&nbsp;</span>
857
+ <span class="cline-any cline-neutral">&nbsp;</span>
858
+ <span class="cline-any cline-neutral">&nbsp;</span>
859
+ <span class="cline-any cline-yes">650x</span>
860
+ <span class="cline-any cline-no">&nbsp;</span>
861
+ <span class="cline-any cline-neutral">&nbsp;</span>
862
+ <span class="cline-any cline-neutral">&nbsp;</span>
863
+ <span class="cline-any cline-yes">650x</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-yes">157x</span>
868
+ <span class="cline-any cline-yes">7x</span>
869
+ <span class="cline-any cline-neutral">&nbsp;</span>
870
+ <span class="cline-any cline-neutral">&nbsp;</span>
871
+ <span class="cline-any cline-yes">150x</span>
872
+ <span class="cline-any cline-neutral">&nbsp;</span>
873
+ <span class="cline-any cline-neutral">&nbsp;</span>
874
+ <span class="cline-any cline-neutral">&nbsp;</span>
875
+ <span class="cline-any cline-yes">169x</span>
876
+ <span class="cline-any cline-yes">5x</span>
877
+ <span class="cline-any cline-neutral">&nbsp;</span>
878
+ <span class="cline-any cline-neutral">&nbsp;</span>
879
+ <span class="cline-any cline-yes">164x</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-neutral">&nbsp;</span>
884
+ <span class="cline-any cline-yes">164x</span>
885
+ <span class="cline-any cline-yes">12x</span>
886
+ <span class="cline-any cline-neutral">&nbsp;</span>
887
+ <span class="cline-any cline-neutral">&nbsp;</span>
888
+ <span class="cline-any cline-yes">24x</span>
889
+ <span class="cline-any cline-neutral">&nbsp;</span>
890
+ <span class="cline-any cline-neutral">&nbsp;</span>
891
+ <span class="cline-any cline-neutral">&nbsp;</span>
892
+ <span class="cline-any cline-neutral">&nbsp;</span>
893
+ <span class="cline-any cline-neutral">&nbsp;</span>
894
+ <span class="cline-any cline-yes">152x</span>
895
+ <span class="cline-any cline-neutral">&nbsp;</span>
896
+ <span class="cline-any cline-neutral">&nbsp;</span>
897
+ <span class="cline-any cline-neutral">&nbsp;</span>
898
+ <span class="cline-any cline-neutral">&nbsp;</span>
899
+ <span class="cline-any cline-neutral">&nbsp;</span>
900
+ <span class="cline-any cline-neutral">&nbsp;</span>
901
+ <span class="cline-any cline-neutral">&nbsp;</span>
902
+ <span class="cline-any cline-yes">300x</span>
903
+ <span class="cline-any cline-yes">300x</span>
904
+ <span class="cline-any cline-neutral">&nbsp;</span>
905
+ <span class="cline-any cline-yes">300x</span>
906
+ <span class="cline-any cline-yes">8x</span>
907
+ <span class="cline-any cline-neutral">&nbsp;</span>
908
+ <span class="cline-any cline-neutral">&nbsp;</span>
909
+ <span class="cline-any cline-yes">292x</span>
910
+ <span class="cline-any cline-neutral">&nbsp;</span>
911
+ <span class="cline-any cline-yes">292x</span>
912
+ <span class="cline-any cline-yes">236x</span>
913
+ <span class="cline-any cline-neutral">&nbsp;</span>
914
+ <span class="cline-any cline-neutral">&nbsp;</span>
915
+ <span class="cline-any cline-yes">56x</span>
916
+ <span class="cline-any cline-yes">56x</span>
917
+ <span class="cline-any cline-yes">56x</span>
918
+ <span class="cline-any cline-yes">56x</span>
919
+ <span class="cline-any cline-neutral">&nbsp;</span>
920
+ <span class="cline-any cline-yes">56x</span>
921
+ <span class="cline-any cline-no">&nbsp;</span>
922
+ <span class="cline-any cline-neutral">&nbsp;</span>
923
+ <span class="cline-any cline-neutral">&nbsp;</span>
924
+ <span class="cline-any cline-yes">56x</span>
925
+ <span class="cline-any cline-no">&nbsp;</span>
926
+ <span class="cline-any cline-neutral">&nbsp;</span>
927
+ <span class="cline-any cline-neutral">&nbsp;</span>
928
+ <span class="cline-any cline-yes">56x</span>
929
+ <span class="cline-any cline-neutral">&nbsp;</span>
930
+ <span class="cline-any cline-yes">56x</span>
931
+ <span class="cline-any cline-neutral">&nbsp;</span>
932
+ <span class="cline-any cline-yes">56x</span>
933
+ <span class="cline-any cline-yes">42x</span>
934
+ <span class="cline-any cline-yes">42x</span>
935
+ <span class="cline-any cline-neutral">&nbsp;</span>
936
+ <span class="cline-any cline-neutral">&nbsp;</span>
937
+ <span class="cline-any cline-yes">14x</span>
938
+ <span class="cline-any cline-yes">2x</span>
939
+ <span class="cline-any cline-yes">2x</span>
940
+ <span class="cline-any cline-neutral">&nbsp;</span>
941
+ <span class="cline-any cline-neutral">&nbsp;</span>
942
+ <span class="cline-any cline-yes">12x</span>
943
+ <span class="cline-any cline-yes">12x</span>
944
+ <span class="cline-any cline-neutral">&nbsp;</span>
945
+ <span class="cline-any cline-neutral">&nbsp;</span>
946
+ <span class="cline-any cline-no">&nbsp;</span>
947
+ <span class="cline-any cline-neutral">&nbsp;</span>
948
+ <span class="cline-any cline-neutral">&nbsp;</span>
949
+ <span class="cline-any cline-yes">44x</span>
950
+ <span class="cline-any cline-neutral">&nbsp;</span>
951
+ <span class="cline-any cline-neutral">&nbsp;</span>
952
+ <span class="cline-any cline-neutral">&nbsp;</span>
953
+ <span class="cline-any cline-neutral">&nbsp;</span>
954
+ <span class="cline-any cline-neutral">&nbsp;</span>
955
+ <span class="cline-any cline-neutral">&nbsp;</span>
956
+ <span class="cline-any cline-neutral">&nbsp;</span>
957
+ <span class="cline-any cline-yes">128x</span>
958
+ <span class="cline-any cline-neutral">&nbsp;</span>
959
+ <span class="cline-any cline-neutral">&nbsp;</span>
960
+ <span class="cline-any cline-neutral">&nbsp;</span>
961
+ <span class="cline-any cline-neutral">&nbsp;</span>
962
+ <span class="cline-any cline-neutral">&nbsp;</span>
963
+ <span class="cline-any cline-neutral">&nbsp;</span>
964
+ <span class="cline-any cline-neutral">&nbsp;</span>
965
+ <span class="cline-any cline-neutral">&nbsp;</span>
966
+ <span class="cline-any cline-neutral">&nbsp;</span>
967
+ <span class="cline-any cline-neutral">&nbsp;</span>
968
+ <span class="cline-any cline-neutral">&nbsp;</span>
969
+ <span class="cline-any cline-neutral">&nbsp;</span>
970
+ <span class="cline-any cline-neutral">&nbsp;</span>
971
+ <span class="cline-any cline-neutral">&nbsp;</span>
972
+ <span class="cline-any cline-neutral">&nbsp;</span>
973
+ <span class="cline-any cline-neutral">&nbsp;</span>
974
+ <span class="cline-any cline-neutral">&nbsp;</span>
975
+ <span class="cline-any cline-neutral">&nbsp;</span>
976
+ <span class="cline-any cline-yes">128x</span>
977
+ <span class="cline-any cline-yes">7x</span>
978
+ <span class="cline-any cline-yes">14x</span>
979
+ <span class="cline-any cline-neutral">&nbsp;</span>
980
+ <span class="cline-any cline-yes">7x</span>
981
+ <span class="cline-any cline-neutral">&nbsp;</span>
982
+ <span class="cline-any cline-neutral">&nbsp;</span>
983
+ <span class="cline-any cline-yes">121x</span>
984
+ <span class="cline-any cline-no">&nbsp;</span>
985
+ <span class="cline-any cline-neutral">&nbsp;</span>
986
+ <span class="cline-any cline-neutral">&nbsp;</span>
987
+ <span class="cline-any cline-yes">121x</span>
988
+ <span class="cline-any cline-yes">63x</span>
989
+ <span class="cline-any cline-neutral">&nbsp;</span>
990
+ <span class="cline-any cline-neutral">&nbsp;</span>
991
+ <span class="cline-any cline-yes">94x</span>
992
+ <span class="cline-any cline-yes">94x</span>
993
+ <span class="cline-any cline-no">&nbsp;</span>
994
+ <span class="cline-any cline-neutral">&nbsp;</span>
995
+ <span class="cline-any cline-neutral">&nbsp;</span>
996
+ <span class="cline-any cline-yes">94x</span>
997
+ <span class="cline-any cline-no">&nbsp;</span>
998
+ <span class="cline-any cline-neutral">&nbsp;</span>
999
+ <span class="cline-any cline-neutral">&nbsp;</span>
1000
+ <span class="cline-any cline-yes">94x</span>
1001
+ <span class="cline-any cline-yes">86x</span>
1002
+ <span class="cline-any cline-yes">6x</span>
1003
+ <span class="cline-any cline-neutral">&nbsp;</span>
1004
+ <span class="cline-any cline-neutral">&nbsp;</span>
1005
+ <span class="cline-any cline-yes">80x</span>
1006
+ <span class="cline-any cline-yes">80x</span>
1007
+ <span class="cline-any cline-neutral">&nbsp;</span>
1008
+ <span class="cline-any cline-yes">80x</span>
1009
+ <span class="cline-any cline-yes">2x</span>
1010
+ <span class="cline-any cline-yes">2x</span>
1011
+ <span class="cline-any cline-neutral">&nbsp;</span>
1012
+ <span class="cline-any cline-no">&nbsp;</span>
1013
+ <span class="cline-any cline-neutral">&nbsp;</span>
1014
+ <span class="cline-any cline-neutral">&nbsp;</span>
1015
+ <span class="cline-any cline-neutral">&nbsp;</span>
1016
+ <span class="cline-any cline-yes">80x</span>
1017
+ <span class="cline-any cline-no">&nbsp;</span>
1018
+ <span class="cline-any cline-neutral">&nbsp;</span>
1019
+ <span class="cline-any cline-neutral">&nbsp;</span>
1020
+ <span class="cline-any cline-yes">80x</span>
1021
+ <span class="cline-any cline-neutral">&nbsp;</span>
1022
+ <span class="cline-any cline-neutral">&nbsp;</span>
1023
+ <span class="cline-any cline-yes">8x</span>
1024
+ <span class="cline-any cline-yes">8x</span>
1025
+ <span class="cline-any cline-yes">4x</span>
1026
+ <span class="cline-any cline-neutral">&nbsp;</span>
1027
+ <span class="cline-any cline-neutral">&nbsp;</span>
1028
+ <span class="cline-any cline-yes">4x</span>
1029
+ <span class="cline-any cline-no">&nbsp;</span>
1030
+ <span class="cline-any cline-neutral">&nbsp;</span>
1031
+ <span class="cline-any cline-neutral">&nbsp;</span>
1032
+ <span class="cline-any cline-yes">4x</span>
1033
+ <span class="cline-any cline-yes">4x</span>
1034
+ <span class="cline-any cline-yes">4x</span>
1035
+ <span class="cline-any cline-neutral">&nbsp;</span>
1036
+ <span class="cline-any cline-neutral">&nbsp;</span>
1037
+ <span class="cline-any cline-no">&nbsp;</span>
1038
+ <span class="cline-any cline-no">&nbsp;</span>
1039
+ <span class="cline-any cline-no">&nbsp;</span>
1040
+ <span class="cline-any cline-neutral">&nbsp;</span>
1041
+ <span class="cline-any cline-neutral">&nbsp;</span>
1042
+ <span class="cline-any cline-no">&nbsp;</span>
1043
+ <span class="cline-any cline-no">&nbsp;</span>
1044
+ <span class="cline-any cline-no">&nbsp;</span>
1045
+ <span class="cline-any cline-neutral">&nbsp;</span>
1046
+ <span class="cline-any cline-no">&nbsp;</span>
1047
+ <span class="cline-any cline-no">&nbsp;</span>
1048
+ <span class="cline-any cline-neutral">&nbsp;</span>
1049
+ <span class="cline-any cline-neutral">&nbsp;</span>
1050
+ <span class="cline-any cline-no">&nbsp;</span>
1051
+ <span class="cline-any cline-no">&nbsp;</span>
1052
+ <span class="cline-any cline-no">&nbsp;</span>
1053
+ <span class="cline-any cline-no">&nbsp;</span>
1054
+ <span class="cline-any cline-no">&nbsp;</span>
1055
+ <span class="cline-any cline-neutral">&nbsp;</span>
1056
+ <span class="cline-any cline-neutral">&nbsp;</span>
1057
+ <span class="cline-any cline-neutral">&nbsp;</span>
1058
+ <span class="cline-any cline-no">&nbsp;</span>
1059
+ <span class="cline-any cline-no">&nbsp;</span>
1060
+ <span class="cline-any cline-no">&nbsp;</span>
1061
+ <span class="cline-any cline-no">&nbsp;</span>
1062
+ <span class="cline-any cline-neutral">&nbsp;</span>
1063
+ <span class="cline-any cline-no">&nbsp;</span>
1064
+ <span class="cline-any cline-neutral">&nbsp;</span>
1065
+ <span class="cline-any cline-neutral">&nbsp;</span>
1066
+ <span class="cline-any cline-no">&nbsp;</span>
1067
+ <span class="cline-any cline-no">&nbsp;</span>
1068
+ <span class="cline-any cline-neutral">&nbsp;</span>
1069
+ <span class="cline-any cline-neutral">&nbsp;</span>
1070
+ <span class="cline-any cline-no">&nbsp;</span>
1071
+ <span class="cline-any cline-neutral">&nbsp;</span>
1072
+ <span class="cline-any cline-no">&nbsp;</span>
1073
+ <span class="cline-any cline-neutral">&nbsp;</span>
1074
+ <span class="cline-any cline-neutral">&nbsp;</span>
1075
+ <span class="cline-any cline-no">&nbsp;</span>
1076
+ <span class="cline-any cline-neutral">&nbsp;</span>
1077
+ <span class="cline-any cline-neutral">&nbsp;</span>
1078
+ <span class="cline-any cline-no">&nbsp;</span>
1079
+ <span class="cline-any cline-neutral">&nbsp;</span>
1080
+ <span class="cline-any cline-neutral">&nbsp;</span>
1081
+ <span class="cline-any cline-no">&nbsp;</span>
1082
+ <span class="cline-any cline-no">&nbsp;</span>
1083
+ <span class="cline-any cline-no">&nbsp;</span>
1084
+ <span class="cline-any cline-neutral">&nbsp;</span>
1085
+ <span class="cline-any cline-neutral">&nbsp;</span>
1086
+ <span class="cline-any cline-neutral">&nbsp;</span>
1087
+ <span class="cline-any cline-no">&nbsp;</span>
1088
+ <span class="cline-any cline-neutral">&nbsp;</span>
1089
+ <span class="cline-any cline-neutral">&nbsp;</span>
1090
+ <span class="cline-any cline-no">&nbsp;</span>
1091
+ <span class="cline-any cline-no">&nbsp;</span>
1092
+ <span class="cline-any cline-no">&nbsp;</span>
1093
+ <span class="cline-any cline-neutral">&nbsp;</span>
1094
+ <span class="cline-any cline-neutral">&nbsp;</span>
1095
+ <span class="cline-any cline-no">&nbsp;</span>
1096
+ <span class="cline-any cline-no">&nbsp;</span>
1097
+ <span class="cline-any cline-neutral">&nbsp;</span>
1098
+ <span class="cline-any cline-no">&nbsp;</span>
1099
+ <span class="cline-any cline-no">&nbsp;</span>
1100
+ <span class="cline-any cline-no">&nbsp;</span>
1101
+ <span class="cline-any cline-no">&nbsp;</span>
1102
+ <span class="cline-any cline-neutral">&nbsp;</span>
1103
+ <span class="cline-any cline-neutral">&nbsp;</span>
1104
+ <span class="cline-any cline-neutral">&nbsp;</span>
1105
+ <span class="cline-any cline-neutral">&nbsp;</span>
1106
+ <span class="cline-any cline-no">&nbsp;</span>
1107
+ <span class="cline-any cline-no">&nbsp;</span>
1108
+ <span class="cline-any cline-neutral">&nbsp;</span>
1109
+ <span class="cline-any cline-neutral">&nbsp;</span>
1110
+ <span class="cline-any cline-no">&nbsp;</span>
1111
+ <span class="cline-any cline-no">&nbsp;</span>
1112
+ <span class="cline-any cline-neutral">&nbsp;</span>
1113
+ <span class="cline-any cline-neutral">&nbsp;</span>
1114
+ <span class="cline-any cline-neutral">&nbsp;</span>
1115
+ <span class="cline-any cline-no">&nbsp;</span>
1116
+ <span class="cline-any cline-neutral">&nbsp;</span>
1117
+ <span class="cline-any cline-neutral">&nbsp;</span>
1118
+ <span class="cline-any cline-neutral">&nbsp;</span>
1119
+ <span class="cline-any cline-neutral">&nbsp;</span>
1120
+ <span class="cline-any cline-neutral">&nbsp;</span>
1121
+ <span class="cline-any cline-neutral">&nbsp;</span>
1122
+ <span class="cline-any cline-neutral">&nbsp;</span>
1123
+ <span class="cline-any cline-yes">121x</span>
1124
+ <span class="cline-any cline-yes">7x</span>
1125
+ <span class="cline-any cline-neutral">&nbsp;</span>
1126
+ <span class="cline-any cline-neutral">&nbsp;</span>
1127
+ <span class="cline-any cline-neutral">&nbsp;</span>
1128
+ <span class="cline-any cline-neutral">&nbsp;</span>
1129
+ <span class="cline-any cline-yes">114x</span>
1130
+ <span class="cline-any cline-neutral">&nbsp;</span>
1131
+ <span class="cline-any cline-neutral">&nbsp;</span>
1132
+ <span class="cline-any cline-neutral">&nbsp;</span>
1133
+ <span class="cline-any cline-neutral">&nbsp;</span>
1134
+ <span class="cline-any cline-neutral">&nbsp;</span>
1135
+ <span class="cline-any cline-neutral">&nbsp;</span>
1136
+ <span class="cline-any cline-yes">12x</span>
1137
+ <span class="cline-any cline-no">&nbsp;</span>
1138
+ <span class="cline-any cline-neutral">&nbsp;</span>
1139
+ <span class="cline-any cline-neutral">&nbsp;</span>
1140
+ <span class="cline-any cline-yes">12x</span>
1141
+ <span class="cline-any cline-yes">12x</span>
1142
+ <span class="cline-any cline-no">&nbsp;</span>
1143
+ <span class="cline-any cline-neutral">&nbsp;</span>
1144
+ <span class="cline-any cline-no">&nbsp;</span>
1145
+ <span class="cline-any cline-neutral">&nbsp;</span>
1146
+ <span class="cline-any cline-no">&nbsp;</span>
1147
+ <span class="cline-any cline-neutral">&nbsp;</span>
1148
+ <span class="cline-any cline-no">&nbsp;</span>
1149
+ <span class="cline-any cline-no">&nbsp;</span>
1150
+ <span class="cline-any cline-neutral">&nbsp;</span>
1151
+ <span class="cline-any cline-neutral">&nbsp;</span>
1152
+ <span class="cline-any cline-no">&nbsp;</span>
1153
+ <span class="cline-any cline-no">&nbsp;</span>
1154
+ <span class="cline-any cline-neutral">&nbsp;</span>
1155
+ <span class="cline-any cline-neutral">&nbsp;</span>
1156
+ <span class="cline-any cline-no">&nbsp;</span>
1157
+ <span class="cline-any cline-neutral">&nbsp;</span>
297
1158
  <span class="cline-any cline-neutral">&nbsp;</span>
298
1159
  <span class="cline-any cline-neutral">&nbsp;</span>
1160
+ <span class="cline-any cline-no">&nbsp;</span>
299
1161
  <span class="cline-any cline-neutral">&nbsp;</span>
300
- <span class="cline-any cline-yes">4x</span>
301
- <span class="cline-any cline-yes">4x</span>
302
- <span class="cline-any cline-yes">4x</span>
303
1162
  <span class="cline-any cline-neutral">&nbsp;</span>
304
1163
  <span class="cline-any cline-neutral">&nbsp;</span>
305
1164
  <span class="cline-any cline-neutral">&nbsp;</span>
306
1165
  <span class="cline-any cline-neutral">&nbsp;</span>
1166
+ <span class="cline-any cline-yes">12x</span>
1167
+ <span class="cline-any cline-no">&nbsp;</span>
307
1168
  <span class="cline-any cline-neutral">&nbsp;</span>
308
1169
  <span class="cline-any cline-neutral">&nbsp;</span>
1170
+ <span class="cline-any cline-yes">12x</span>
1171
+ <span class="cline-any cline-yes">10x</span>
309
1172
  <span class="cline-any cline-neutral">&nbsp;</span>
310
- <span class="cline-any cline-yes">4x</span>
311
1173
  <span class="cline-any cline-neutral">&nbsp;</span>
312
1174
  <span class="cline-any cline-neutral">&nbsp;</span>
313
1175
  <span class="cline-any cline-neutral">&nbsp;</span>
314
1176
  <span class="cline-any cline-neutral">&nbsp;</span>
1177
+ <span class="cline-any cline-yes">2x</span>
315
1178
  <span class="cline-any cline-neutral">&nbsp;</span>
316
1179
  <span class="cline-any cline-neutral">&nbsp;</span>
317
1180
  <span class="cline-any cline-neutral">&nbsp;</span>
318
- <span class="cline-any cline-yes">4x</span>
319
- <span class="cline-any cline-yes">4x</span>
320
- <span class="cline-any cline-yes">4x</span>
321
- <span class="cline-any cline-yes">4x</span>
322
1181
  <span class="cline-any cline-neutral">&nbsp;</span>
323
- <span class="cline-any cline-yes">4x</span>
324
1182
  <span class="cline-any cline-neutral">&nbsp;</span>
325
1183
  <span class="cline-any cline-neutral">&nbsp;</span>
326
- <span class="cline-any cline-yes">7x</span>
1184
+ <span class="cline-any cline-neutral">&nbsp;</span>
1185
+ <span class="cline-any cline-yes">20x</span>
327
1186
  <span class="cline-any cline-neutral">&nbsp;</span>
328
1187
  <span class="cline-any cline-neutral">&nbsp;</span>
329
- <span class="cline-any cline-yes">4x</span>
330
1188
  <span class="cline-any cline-neutral">&nbsp;</span>
331
1189
  <span class="cline-any cline-neutral">&nbsp;</span>
332
1190
  <span class="cline-any cline-neutral">&nbsp;</span>
333
- <span class="cline-any cline-yes">147x</span>
334
1191
  <span class="cline-any cline-neutral">&nbsp;</span>
335
1192
  <span class="cline-any cline-neutral">&nbsp;</span>
336
- <span class="cline-any cline-yes">136x</span>
337
- <span class="cline-any cline-yes">7x</span>
338
1193
  <span class="cline-any cline-neutral">&nbsp;</span>
339
1194
  <span class="cline-any cline-neutral">&nbsp;</span>
340
1195
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -345,60 +1200,142 @@
345
1200
  <span class="cline-any cline-neutral">&nbsp;</span>
346
1201
  <span class="cline-any cline-neutral">&nbsp;</span>
347
1202
  <span class="cline-any cline-neutral">&nbsp;</span>
1203
+ <span class="cline-any cline-yes">150x</span>
1204
+ <span class="cline-any cline-yes">150x</span>
1205
+ <span class="cline-any cline-yes">5x</span>
1206
+ <span class="cline-any cline-neutral">&nbsp;</span>
1207
+ <span class="cline-any cline-neutral">&nbsp;</span>
1208
+ <span class="cline-any cline-yes">145x</span>
1209
+ <span class="cline-any cline-yes">145x</span>
1210
+ <span class="cline-any cline-neutral">&nbsp;</span>
1211
+ <span class="cline-any cline-yes">145x</span>
1212
+ <span class="cline-any cline-yes">4x</span>
1213
+ <span class="cline-any cline-neutral">&nbsp;</span>
1214
+ <span class="cline-any cline-neutral">&nbsp;</span>
1215
+ <span class="cline-any cline-yes">141x</span>
1216
+ <span class="cline-any cline-no">&nbsp;</span>
348
1217
  <span class="cline-any cline-neutral">&nbsp;</span>
349
1218
  <span class="cline-any cline-neutral">&nbsp;</span>
350
1219
  <span class="cline-any cline-neutral">&nbsp;</span>
1220
+ <span class="cline-any cline-no">&nbsp;</span>
1221
+ <span class="cline-any cline-neutral">&nbsp;</span>
1222
+ <span class="cline-any cline-neutral">&nbsp;</span>
1223
+ <span class="cline-any cline-yes">141x</span>
1224
+ <span class="cline-any cline-neutral">&nbsp;</span>
1225
+ <span class="cline-any cline-yes">4x</span>
351
1226
  <span class="cline-any cline-neutral">&nbsp;</span>
1227
+ <span class="cline-any cline-yes">1x</span>
352
1228
  <span class="cline-any cline-neutral">&nbsp;</span>
353
1229
  <span class="cline-any cline-neutral">&nbsp;</span>
354
1230
  <span class="cline-any cline-neutral">&nbsp;</span>
1231
+ <span class="cline-any cline-yes">1x</span>
355
1232
  <span class="cline-any cline-neutral">&nbsp;</span>
356
1233
  <span class="cline-any cline-neutral">&nbsp;</span>
1234
+ <span class="cline-any cline-yes">140x</span>
357
1235
  <span class="cline-any cline-neutral">&nbsp;</span>
358
1236
  <span class="cline-any cline-yes">6x</span>
359
- <span class="cline-any cline-no">&nbsp;</span>
360
1237
  <span class="cline-any cline-neutral">&nbsp;</span>
1238
+ <span class="cline-any cline-yes">1x</span>
1239
+ <span class="cline-any cline-yes">1x</span>
1240
+ <span class="cline-any cline-neutral">&nbsp;</span>
1241
+ <span class="cline-any cline-neutral">&nbsp;</span>
1242
+ <span class="cline-any cline-yes">139x</span>
361
1243
  <span class="cline-any cline-neutral">&nbsp;</span>
362
1244
  <span class="cline-any cline-yes">6x</span>
363
1245
  <span class="cline-any cline-neutral">&nbsp;</span>
1246
+ <span class="cline-any cline-no">&nbsp;</span>
1247
+ <span class="cline-any cline-neutral">&nbsp;</span>
1248
+ <span class="cline-any cline-neutral">&nbsp;</span>
1249
+ <span class="cline-any cline-neutral">&nbsp;</span>
1250
+ <span class="cline-any cline-no">&nbsp;</span>
364
1251
  <span class="cline-any cline-neutral">&nbsp;</span>
365
1252
  <span class="cline-any cline-neutral">&nbsp;</span>
1253
+ <span class="cline-any cline-yes">139x</span>
366
1254
  <span class="cline-any cline-neutral">&nbsp;</span>
1255
+ <span class="cline-any cline-yes">6x</span>
367
1256
  <span class="cline-any cline-neutral">&nbsp;</span>
1257
+ <span class="cline-any cline-no">&nbsp;</span>
368
1258
  <span class="cline-any cline-neutral">&nbsp;</span>
369
1259
  <span class="cline-any cline-neutral">&nbsp;</span>
370
1260
  <span class="cline-any cline-neutral">&nbsp;</span>
1261
+ <span class="cline-any cline-no">&nbsp;</span>
371
1262
  <span class="cline-any cline-neutral">&nbsp;</span>
372
- <span class="cline-any cline-yes">135x</span>
373
1263
  <span class="cline-any cline-neutral">&nbsp;</span>
1264
+ <span class="cline-any cline-yes">139x</span>
1265
+ <span class="cline-any cline-yes">8x</span>
374
1266
  <span class="cline-any cline-neutral">&nbsp;</span>
375
1267
  <span class="cline-any cline-neutral">&nbsp;</span>
376
1268
  <span class="cline-any cline-neutral">&nbsp;</span>
377
1269
  <span class="cline-any cline-neutral">&nbsp;</span>
1270
+ <span class="cline-any cline-no">&nbsp;</span>
378
1271
  <span class="cline-any cline-neutral">&nbsp;</span>
379
1272
  <span class="cline-any cline-neutral">&nbsp;</span>
380
1273
  <span class="cline-any cline-neutral">&nbsp;</span>
1274
+ <span class="cline-any cline-no">&nbsp;</span>
381
1275
  <span class="cline-any cline-neutral">&nbsp;</span>
382
1276
  <span class="cline-any cline-neutral">&nbsp;</span>
1277
+ <span class="cline-any cline-yes">8x</span>
383
1278
  <span class="cline-any cline-yes">1x</span>
384
1279
  <span class="cline-any cline-neutral">&nbsp;</span>
385
1280
  <span class="cline-any cline-neutral">&nbsp;</span>
1281
+ <span class="cline-any cline-yes">7x</span>
1282
+ <span class="cline-any cline-yes">13x</span>
1283
+ <span class="cline-any cline-yes">2x</span>
1284
+ <span class="cline-any cline-neutral">&nbsp;</span>
1285
+ <span class="cline-any cline-neutral">&nbsp;</span>
1286
+ <span class="cline-any cline-neutral">&nbsp;</span>
1287
+ <span class="cline-any cline-neutral">&nbsp;</span>
1288
+ <span class="cline-any cline-neutral">&nbsp;</span>
1289
+ <span class="cline-any cline-neutral">&nbsp;</span>
1290
+ <span class="cline-any cline-neutral">&nbsp;</span>
1291
+ <span class="cline-any cline-yes">7x</span>
1292
+ <span class="cline-any cline-neutral">&nbsp;</span>
1293
+ <span class="cline-any cline-neutral">&nbsp;</span>
1294
+ <span class="cline-any cline-yes">131x</span>
1295
+ <span class="cline-any cline-yes">12x</span>
1296
+ <span class="cline-any cline-yes">12x</span>
1297
+ <span class="cline-any cline-no">&nbsp;</span>
1298
+ <span class="cline-any cline-no">&nbsp;</span>
1299
+ <span class="cline-any cline-neutral">&nbsp;</span>
1300
+ <span class="cline-any cline-neutral">&nbsp;</span>
1301
+ <span class="cline-any cline-yes">12x</span>
1302
+ <span class="cline-any cline-yes">12x</span>
1303
+ <span class="cline-any cline-no">&nbsp;</span>
1304
+ <span class="cline-any cline-no">&nbsp;</span>
1305
+ <span class="cline-any cline-neutral">&nbsp;</span>
1306
+ <span class="cline-any cline-neutral">&nbsp;</span>
1307
+ <span class="cline-any cline-yes">12x</span>
1308
+ <span class="cline-any cline-yes">4x</span>
1309
+ <span class="cline-any cline-neutral">&nbsp;</span>
1310
+ <span class="cline-any cline-neutral">&nbsp;</span>
1311
+ <span class="cline-any cline-yes">12x</span>
1312
+ <span class="cline-any cline-neutral">&nbsp;</span>
386
1313
  <span class="cline-any cline-neutral">&nbsp;</span>
1314
+ <span class="cline-any cline-yes">119x</span>
1315
+ <span class="cline-any cline-yes">99x</span>
1316
+ <span class="cline-any cline-yes">3x</span>
1317
+ <span class="cline-any cline-neutral">&nbsp;</span>
1318
+ <span class="cline-any cline-neutral">&nbsp;</span>
1319
+ <span class="cline-any cline-yes">96x</span>
1320
+ <span class="cline-any cline-yes">6x</span>
387
1321
  <span class="cline-any cline-neutral">&nbsp;</span>
388
1322
  <span class="cline-any cline-neutral">&nbsp;</span>
389
1323
  <span class="cline-any cline-neutral">&nbsp;</span>
390
1324
  <span class="cline-any cline-neutral">&nbsp;</span>
391
- <span class="cline-any cline-yes">135x</span>
392
1325
  <span class="cline-any cline-yes">4x</span>
393
1326
  <span class="cline-any cline-neutral">&nbsp;</span>
394
1327
  <span class="cline-any cline-neutral">&nbsp;</span>
395
1328
  <span class="cline-any cline-neutral">&nbsp;</span>
396
1329
  <span class="cline-any cline-neutral">&nbsp;</span>
1330
+ <span class="cline-any cline-yes">150x</span>
1331
+ <span class="cline-any cline-neutral">&nbsp;</span>
1332
+ <span class="cline-any cline-neutral">&nbsp;</span>
1333
+ <span class="cline-any cline-yes">150x</span>
1334
+ <span class="cline-any cline-yes">5x</span>
1335
+ <span class="cline-any cline-neutral">&nbsp;</span>
397
1336
  <span class="cline-any cline-neutral">&nbsp;</span>
398
1337
  <span class="cline-any cline-neutral">&nbsp;</span>
399
1338
  <span class="cline-any cline-neutral">&nbsp;</span>
400
- <span class="cline-any cline-yes">135x</span>
401
- <span class="cline-any cline-yes">1x</span>
402
1339
  <span class="cline-any cline-neutral">&nbsp;</span>
403
1340
  <span class="cline-any cline-neutral">&nbsp;</span>
404
1341
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -406,27 +1343,32 @@
406
1343
  <span class="cline-any cline-neutral">&nbsp;</span>
407
1344
  <span class="cline-any cline-neutral">&nbsp;</span>
408
1345
  <span class="cline-any cline-neutral">&nbsp;</span>
409
- <span class="cline-any cline-yes">135x</span>
1346
+ <span class="cline-any cline-neutral">&nbsp;</span>
1347
+ <span class="cline-any cline-neutral">&nbsp;</span>
1348
+ <span class="cline-any cline-neutral">&nbsp;</span>
1349
+ <span class="cline-any cline-neutral">&nbsp;</span>
1350
+ <span class="cline-any cline-neutral">&nbsp;</span>
1351
+ <span class="cline-any cline-neutral">&nbsp;</span>
1352
+ <span class="cline-any cline-neutral">&nbsp;</span>
1353
+ <span class="cline-any cline-neutral">&nbsp;</span>
1354
+ <span class="cline-any cline-neutral">&nbsp;</span>
1355
+ <span class="cline-any cline-yes">5x</span>
410
1356
  <span class="cline-any cline-no">&nbsp;</span>
411
1357
  <span class="cline-any cline-neutral">&nbsp;</span>
412
1358
  <span class="cline-any cline-neutral">&nbsp;</span>
1359
+ <span class="cline-any cline-yes">5x</span>
413
1360
  <span class="cline-any cline-neutral">&nbsp;</span>
414
1361
  <span class="cline-any cline-neutral">&nbsp;</span>
415
1362
  <span class="cline-any cline-neutral">&nbsp;</span>
416
1363
  <span class="cline-any cline-neutral">&nbsp;</span>
417
1364
  <span class="cline-any cline-neutral">&nbsp;</span>
418
- <span class="cline-any cline-yes">135x</span>
419
1365
  <span class="cline-any cline-neutral">&nbsp;</span>
420
- <span class="cline-any cline-yes">8x</span>
421
- <span class="cline-any cline-yes">1x</span>
422
1366
  <span class="cline-any cline-neutral">&nbsp;</span>
423
1367
  <span class="cline-any cline-neutral">&nbsp;</span>
1368
+ <span class="cline-any cline-yes">150x</span>
424
1369
  <span class="cline-any cline-neutral">&nbsp;</span>
425
1370
  <span class="cline-any cline-neutral">&nbsp;</span>
426
- <span class="cline-any cline-yes">7x</span>
427
1371
  <span class="cline-any cline-neutral">&nbsp;</span>
428
- <span class="cline-any cline-yes">7x</span>
429
- <span class="cline-any cline-yes">2x</span>
430
1372
  <span class="cline-any cline-neutral">&nbsp;</span>
431
1373
  <span class="cline-any cline-neutral">&nbsp;</span>
432
1374
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -434,58 +1376,82 @@
434
1376
  <span class="cline-any cline-neutral">&nbsp;</span>
435
1377
  <span class="cline-any cline-neutral">&nbsp;</span>
436
1378
  <span class="cline-any cline-neutral">&nbsp;</span>
437
- <span class="cline-any cline-no">&nbsp;</span>
1379
+ <span class="cline-any cline-yes">1x</span>
438
1380
  <span class="cline-any cline-neutral">&nbsp;</span>
1381
+ <span class="cline-any cline-neutral">&nbsp;</span>
1382
+ <span class="cline-any cline-neutral">&nbsp;</span>
1383
+ <span class="cline-any cline-neutral">&nbsp;</span>
1384
+ <span class="cline-any cline-neutral">&nbsp;</span>
1385
+ <span class="cline-any cline-yes">150x</span>
439
1386
  <span class="cline-any cline-no">&nbsp;</span>
440
- <span class="cline-any cline-no">&nbsp;</span>
441
1387
  <span class="cline-any cline-neutral">&nbsp;</span>
442
1388
  <span class="cline-any cline-neutral">&nbsp;</span>
1389
+ <span class="cline-any cline-yes">150x</span>
1390
+ <span class="cline-any cline-neutral">&nbsp;</span>
443
1391
  <span class="cline-any cline-neutral">&nbsp;</span>
444
1392
  <span class="cline-any cline-neutral">&nbsp;</span>
1393
+ <span class="cline-any cline-no">&nbsp;</span>
1394
+ <span class="cline-any cline-neutral">&nbsp;</span>
1395
+ <span class="cline-any cline-neutral">&nbsp;</span>
1396
+ <span class="cline-any cline-yes">150x</span>
1397
+ <span class="cline-any cline-yes">6x</span>
1398
+ <span class="cline-any cline-no">&nbsp;</span>
1399
+ <span class="cline-any cline-yes">6x</span>
1400
+ <span class="cline-any cline-yes">6x</span>
1401
+ <span class="cline-any cline-yes">1x</span>
445
1402
  <span class="cline-any cline-neutral">&nbsp;</span>
446
1403
  <span class="cline-any cline-neutral">&nbsp;</span>
447
1404
  <span class="cline-any cline-neutral">&nbsp;</span>
448
1405
  <span class="cline-any cline-neutral">&nbsp;</span>
449
1406
  <span class="cline-any cline-no">&nbsp;</span>
1407
+ <span class="cline-any cline-no">&nbsp;</span>
1408
+ <span class="cline-any cline-no">&nbsp;</span>
450
1409
  <span class="cline-any cline-neutral">&nbsp;</span>
451
1410
  <span class="cline-any cline-neutral">&nbsp;</span>
1411
+ <span class="cline-any cline-no">&nbsp;</span>
452
1412
  <span class="cline-any cline-neutral">&nbsp;</span>
453
1413
  <span class="cline-any cline-neutral">&nbsp;</span>
454
1414
  <span class="cline-any cline-neutral">&nbsp;</span>
455
1415
  <span class="cline-any cline-neutral">&nbsp;</span>
456
1416
  <span class="cline-any cline-neutral">&nbsp;</span>
457
1417
  <span class="cline-any cline-neutral">&nbsp;</span>
458
- <span class="cline-any cline-yes">135x</span>
1418
+ <span class="cline-any cline-yes">150x</span>
459
1419
  <span class="cline-any cline-yes">1x</span>
460
1420
  <span class="cline-any cline-neutral">&nbsp;</span>
461
1421
  <span class="cline-any cline-neutral">&nbsp;</span>
1422
+ <span class="cline-any cline-yes">150x</span>
462
1423
  <span class="cline-any cline-neutral">&nbsp;</span>
463
1424
  <span class="cline-any cline-neutral">&nbsp;</span>
464
1425
  <span class="cline-any cline-neutral">&nbsp;</span>
465
1426
  <span class="cline-any cline-neutral">&nbsp;</span>
466
- <span class="cline-any cline-neutral">&nbsp;</span>
467
- <span class="cline-any cline-yes">135x</span>
468
- <span class="cline-any cline-yes">5x</span>
469
1427
  <span class="cline-any cline-no">&nbsp;</span>
470
1428
  <span class="cline-any cline-neutral">&nbsp;</span>
471
1429
  <span class="cline-any cline-neutral">&nbsp;</span>
1430
+ <span class="cline-any cline-yes">150x</span>
1431
+ <span class="cline-any cline-yes">1x</span>
1432
+ <span class="cline-any cline-yes">1x</span>
1433
+ <span class="cline-any cline-neutral">&nbsp;</span>
472
1434
  <span class="cline-any cline-neutral">&nbsp;</span>
473
1435
  <span class="cline-any cline-neutral">&nbsp;</span>
1436
+ <span class="cline-any cline-yes">150x</span>
1437
+ <span class="cline-any cline-yes">4x</span>
1438
+ <span class="cline-any cline-no">&nbsp;</span>
474
1439
  <span class="cline-any cline-neutral">&nbsp;</span>
1440
+ <span class="cline-any cline-yes">146x</span>
1441
+ <span class="cline-any cline-yes">1x</span>
475
1442
  <span class="cline-any cline-neutral">&nbsp;</span>
476
1443
  <span class="cline-any cline-neutral">&nbsp;</span>
477
- <span class="cline-any cline-yes">130x</span>
478
- <span class="cline-any cline-yes">2x</span>
479
1444
  <span class="cline-any cline-neutral">&nbsp;</span>
480
1445
  <span class="cline-any cline-neutral">&nbsp;</span>
481
1446
  <span class="cline-any cline-neutral">&nbsp;</span>
482
1447
  <span class="cline-any cline-neutral">&nbsp;</span>
1448
+ <span class="cline-any cline-yes">150x</span>
1449
+ <span class="cline-any cline-yes">1x</span>
483
1450
  <span class="cline-any cline-neutral">&nbsp;</span>
484
1451
  <span class="cline-any cline-neutral">&nbsp;</span>
1452
+ <span class="cline-any cline-yes">150x</span>
485
1453
  <span class="cline-any cline-neutral">&nbsp;</span>
486
1454
  <span class="cline-any cline-neutral">&nbsp;</span>
487
- <span class="cline-any cline-yes">135x</span>
488
- <span class="cline-any cline-yes">2x</span>
489
1455
  <span class="cline-any cline-neutral">&nbsp;</span>
490
1456
  <span class="cline-any cline-neutral">&nbsp;</span>
491
1457
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -493,37 +1459,38 @@
493
1459
  <span class="cline-any cline-neutral">&nbsp;</span>
494
1460
  <span class="cline-any cline-neutral">&nbsp;</span>
495
1461
  <span class="cline-any cline-neutral">&nbsp;</span>
496
- <span class="cline-any cline-yes">147x</span>
497
1462
  <span class="cline-any cline-neutral">&nbsp;</span>
498
1463
  <span class="cline-any cline-neutral">&nbsp;</span>
499
- <span class="cline-any cline-yes">31x</span>
500
1464
  <span class="cline-any cline-neutral">&nbsp;</span>
1465
+ <span class="cline-any cline-yes">150x</span>
501
1466
  <span class="cline-any cline-neutral">&nbsp;</span>
502
1467
  <span class="cline-any cline-neutral">&nbsp;</span>
1468
+ <span class="cline-any cline-yes">33x</span>
503
1469
  <span class="cline-any cline-neutral">&nbsp;</span>
504
- <span class="cline-any cline-yes">11x</span>
505
1470
  <span class="cline-any cline-neutral">&nbsp;</span>
506
1471
  <span class="cline-any cline-neutral">&nbsp;</span>
507
1472
  <span class="cline-any cline-neutral">&nbsp;</span>
1473
+ <span class="cline-any cline-yes">8x</span>
508
1474
  <span class="cline-any cline-neutral">&nbsp;</span>
509
- <span class="cline-any cline-yes">6x</span>
510
1475
  <span class="cline-any cline-neutral">&nbsp;</span>
511
1476
  <span class="cline-any cline-neutral">&nbsp;</span>
512
1477
  <span class="cline-any cline-neutral">&nbsp;</span>
1478
+ <span class="cline-any cline-yes">5x</span>
513
1479
  <span class="cline-any cline-neutral">&nbsp;</span>
514
- <span class="cline-any cline-yes">147x</span>
515
1480
  <span class="cline-any cline-neutral">&nbsp;</span>
516
- <span class="cline-any cline-yes">147x</span>
517
1481
  <span class="cline-any cline-neutral">&nbsp;</span>
518
- <span class="cline-any cline-yes">147x</span>
519
1482
  <span class="cline-any cline-neutral">&nbsp;</span>
1483
+ <span class="cline-any cline-yes">150x</span>
1484
+ <span class="cline-any cline-yes">150x</span>
520
1485
  <span class="cline-any cline-neutral">&nbsp;</span>
1486
+ <span class="cline-any cline-yes">150x</span>
521
1487
  <span class="cline-any cline-neutral">&nbsp;</span>
522
1488
  <span class="cline-any cline-neutral">&nbsp;</span>
523
1489
  <span class="cline-any cline-neutral">&nbsp;</span>
524
- <span class="cline-any cline-yes">147x</span>
1490
+ <span class="cline-any cline-yes">150x</span>
525
1491
  <span class="cline-any cline-neutral">&nbsp;</span>
526
- <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { z } from "zod";
1492
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { Attribute, AttributeProperty, Schema } from "@featurevisor/types";
1493
+ import { z } from "zod";
527
1494
  &nbsp;
528
1495
  import { ProjectConfig } from "../config";
529
1496
  &nbsp;
@@ -534,8 +1501,8 @@ const stringOperators = [
534
1501
  "notContains",
535
1502
  "startsWith",
536
1503
  "endsWith",
537
- "includes",
538
- "notIncludes",
1504
+ "matches",
1505
+ "notMatches",
539
1506
  ];
540
1507
  const semverOperators = [
541
1508
  "semverEquals",
@@ -546,24 +1513,537 @@ const semverOperators = [
546
1513
  "semverLessThanOrEquals",
547
1514
  ];
548
1515
  const dateOperators = ["before", "after"];
549
- const arrayOperators = ["in", "notIn"];
550
- const regexOperators = ["matches", "notMatches"];
1516
+ const arrayMembershipOperators = ["in", "notIn"];
1517
+ const arrayOperators = ["includes", "notIncludes"];
551
1518
  const operatorsWithoutValue = ["exists", "notExists"];
552
1519
  &nbsp;
553
1520
  const isoDateRegex = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|([+\-]\d{2}:\d{2})))?$/;
554
1521
  &nbsp;
1522
+ type SchemaNode = Attribute | AttributeProperty | Schema;
1523
+ type ResolvedLeaf =
1524
+ | { kind: "schema"; schema: SchemaNode }
1525
+ | { kind: "flat-object-property" }
1526
+ | { kind: "flat-array-item" };
1527
+ &nbsp;
555
1528
  function isIsoDateString(value: string): boolean {
556
1529
  return isoDateRegex.test(value);
557
1530
  }
558
1531
  &nbsp;
1532
+ function isPrimitiveAttributeValue(value: unknown): boolean {
1533
+ return (
1534
+ value === null ||
1535
+ typeof value === "string" ||
1536
+ <span class="branch-2 cbranch-no" title="branch not covered" > typeof value === "number" </span>||
1537
+ <span class="branch-3 cbranch-no" title="branch not covered" > typeof value === "boolean"</span>
1538
+ );
1539
+ }
1540
+ &nbsp;
1541
+ function isStringArray(value: unknown): value is string[] {
1542
+ return Array.isArray(value) &amp;&amp; value.every((entry) =&gt; typeof entry === "string");
1543
+ }
1544
+ &nbsp;
1545
+ function valueDeepEqual(a: unknown, b: unknown): boolean {
1546
+ if (a === b) return true;
1547
+ if (typeof a !== typeof b) return false;
1548
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (a === null || b === null) <span class="cstat-no" title="statement not covered" >return a === b;</span>
1549
+ &nbsp;
1550
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (typeof a === "object" &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >typeof b === "object")</span> {
1551
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (Array.isArray(a) !== Array.isArray(b)) <span class="cstat-no" title="statement not covered" >return false;</span></span>
1552
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (Array.isArray(a) &amp;&amp; Array.isArray(b)) {</span>
1553
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (a.length !== b.length) <span class="cstat-no" title="statement not covered" >return false;</span></span>
1554
+ <span class="cstat-no" title="statement not covered" > return a.every(<span class="fstat-no" title="function not covered" >(v</span>alue, index) =&gt; <span class="cstat-no" title="statement not covered" >valueDeepEqual(value, b[index]))</span>;</span>
1555
+ }
1556
+ &nbsp;
1557
+ const keysA = <span class="cstat-no" title="statement not covered" >Object.keys(a as object).sort();</span>
1558
+ const keysB = <span class="cstat-no" title="statement not covered" >Object.keys(b as object).sort();</span>
1559
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (keysA.length !== keysB.length || keysA.some(<span class="fstat-no" title="function not covered" >(k</span>ey, index) =&gt; <span class="cstat-no" title="statement not covered" >key !== keysB[index])</span>) {</span>
1560
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1561
+ }
1562
+ &nbsp;
1563
+ <span class="cstat-no" title="statement not covered" > return keysA.every(<span class="fstat-no" title="function not covered" >(k</span>ey) =&gt;</span>
1564
+ <span class="cstat-no" title="statement not covered" > valueDeepEqual((a as Record&lt;string, unknown&gt;)[key], (b as Record&lt;string, unknown&gt;)[key]),</span>
1565
+ );
1566
+ }
1567
+ &nbsp;
1568
+ return false;
1569
+ }
1570
+ &nbsp;
1571
+ function resolveSchemaRefs(schema: SchemaNode, schemasByKey: Record&lt;string, Schema&gt;): SchemaNode {
1572
+ <span class="missing-if-branch" title="if path not taken" >I</span>if ("schema" in schema &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >schema.schema </span>&amp;&amp; <span class="branch-2 cbranch-no" title="branch not covered" >schemasByKey[schema.schema])</span> {
1573
+ <span class="cstat-no" title="statement not covered" > return resolveSchemaRefs(schemasByKey[schema.schema], schemasByKey);</span>
1574
+ }
1575
+ &nbsp;
1576
+ return schema;
1577
+ }
1578
+ &nbsp;
1579
+ function getLeafType(resolvedLeaf: ResolvedLeaf): string | undefined {
1580
+ if (resolvedLeaf.kind === "flat-object-property" || resolvedLeaf.kind === "flat-array-item") {
1581
+ return "primitive";
1582
+ }
1583
+ &nbsp;
1584
+ return "type" in resolvedLeaf.schema ? resolvedLeaf.schema.type : undefined;
1585
+ }
1586
+ &nbsp;
1587
+ function getLeafTypes(resolvedLeaf: ResolvedLeaf, schemasByKey: Record&lt;string, Schema&gt;): string[] {
1588
+ if (resolvedLeaf.kind === "flat-object-property" || resolvedLeaf.kind === "flat-array-item") {
1589
+ return ["primitive"];
1590
+ }
1591
+ &nbsp;
1592
+ const resolved = resolveSchemaRefs(resolvedLeaf.schema, schemasByKey) as SchemaNode &amp; {
1593
+ type?: string;
1594
+ oneOf?: unknown[];
1595
+ };
1596
+ &nbsp;
1597
+ if (resolved.oneOf &amp;&amp; Array.isArray(resolved.oneOf) &amp;&amp; resolved.oneOf.length &gt; 0) {
1598
+ return Array.from(
1599
+ new Set(
1600
+ resolved.oneOf.flatMap((branch) =&gt;
1601
+ getLeafTypes({ kind: "schema", schema: branch as SchemaNode }, schemasByKey),
1602
+ ),
1603
+ ),
1604
+ );
1605
+ }
1606
+ &nbsp;
1607
+ return resolved.type ? [resolved.type] : <span class="branch-1 cbranch-no" title="branch not covered" >[];</span>
1608
+ }
1609
+ &nbsp;
1610
+ function resolveAttributePath(
1611
+ attributePath: string,
1612
+ attributesByKey: Record&lt;string, Attribute&gt;,
1613
+ schemasByKey: Record&lt;string, Schema&gt;,
1614
+ ): ResolvedLeaf | null {
1615
+ const [rootKey, ...rest] = attributePath.split(".");
1616
+ const rootAttribute = attributesByKey[rootKey];
1617
+ &nbsp;
1618
+ if (!rootAttribute) {
1619
+ return null;
1620
+ }
1621
+ &nbsp;
1622
+ let current: SchemaNode = rootAttribute;
1623
+ &nbsp;
1624
+ if (rest.length === 0) {
1625
+ return { kind: "schema", schema: resolveSchemaRefs(current, schemasByKey) };
1626
+ }
1627
+ &nbsp;
1628
+ for (let index = 0; index &lt; rest.length; index++) {
1629
+ const segment = rest[index];
1630
+ current = resolveSchemaRefs(current, schemasByKey);
1631
+ const type = "type" in current ? current.type : <span class="branch-1 cbranch-no" title="branch not covered" >undefined;</span>
1632
+ &nbsp;
1633
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (type !== "object") {
1634
+ <span class="cstat-no" title="statement not covered" > return null;</span>
1635
+ }
1636
+ &nbsp;
1637
+ <span class="missing-if-branch" title="if path not taken" >I</span>if ("oneOf" in current &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >Array.isArray(current.oneOf) </span>&amp;&amp; <span class="branch-2 cbranch-no" title="branch not covered" >current.oneOf.length &gt; 0)</span> {
1638
+ <span class="cstat-no" title="statement not covered" > return null;</span>
1639
+ }
1640
+ &nbsp;
1641
+ const properties = "properties" in current ? current.properties : undefined;
1642
+ const additionalProperties =
1643
+ "additionalProperties" in current ? current.additionalProperties : undefined;
1644
+ &nbsp;
1645
+ if (properties &amp;&amp; typeof properties === "object" &amp;&amp; properties[segment]) {
1646
+ current = properties[segment];
1647
+ continue;
1648
+ }
1649
+ &nbsp;
1650
+ if (additionalProperties &amp;&amp; typeof additionalProperties === "object") {
1651
+ current = additionalProperties;
1652
+ continue;
1653
+ }
1654
+ &nbsp;
1655
+ if (!properties &amp;&amp; !additionalProperties) {
1656
+ return index === rest.length - 1 ? { kind: "flat-object-property" } : null;
1657
+ }
1658
+ &nbsp;
1659
+ <span class="cstat-no" title="statement not covered" > return null;</span>
1660
+ }
1661
+ &nbsp;
1662
+ return { kind: "schema", schema: resolveSchemaRefs(current, schemasByKey) };
1663
+ }
1664
+ &nbsp;
1665
+ function matchesSchemaValue(
1666
+ schema: SchemaNode,
1667
+ value: unknown,
1668
+ schemasByKey: Record&lt;string, Schema&gt;,
1669
+ ): boolean {
1670
+ const resolved = resolveSchemaRefs(schema, schemasByKey) as SchemaNode &amp; {
1671
+ type?: string;
1672
+ enum?: unknown[];
1673
+ const?: unknown;
1674
+ oneOf?: unknown[];
1675
+ properties?: Record&lt;string, unknown&gt;;
1676
+ additionalProperties?: unknown;
1677
+ required?: string[];
1678
+ items?: unknown;
1679
+ minLength?: number;
1680
+ maxLength?: number;
1681
+ pattern?: string;
1682
+ minimum?: number;
1683
+ maximum?: number;
1684
+ minItems?: number;
1685
+ maxItems?: number;
1686
+ uniqueItems?: boolean;
1687
+ };
1688
+ &nbsp;
1689
+ if (resolved.oneOf &amp;&amp; Array.isArray(resolved.oneOf) &amp;&amp; resolved.oneOf.length &gt; 0) {
1690
+ const matches = resolved.oneOf.filter((branch) =&gt;
1691
+ matchesSchemaValue(branch as SchemaNode, value, schemasByKey),
1692
+ ).length;
1693
+ return matches === 1;
1694
+ }
1695
+ &nbsp;
1696
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (resolved.const !== undefined) {
1697
+ <span class="cstat-no" title="statement not covered" > return valueDeepEqual(value, resolved.const);</span>
1698
+ }
1699
+ &nbsp;
1700
+ if (Array.isArray(resolved.enum) &amp;&amp; resolved.enum.length &gt; 0) {
1701
+ return resolved.enum.some((entry) =&gt; valueDeepEqual(entry, value));
1702
+ }
1703
+ &nbsp;
1704
+ const type = resolved.type;
1705
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!type) {
1706
+ <span class="cstat-no" title="statement not covered" > return true;</span>
1707
+ }
1708
+ &nbsp;
1709
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (type === "boolean") {
1710
+ <span class="cstat-no" title="statement not covered" > return typeof value === "boolean";</span>
1711
+ }
1712
+ &nbsp;
1713
+ if (type === "string" || type === "semver" || type === "date") {
1714
+ if (typeof value !== "string") {
1715
+ return false;
1716
+ }
1717
+ &nbsp;
1718
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (resolved.minLength !== undefined &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >value.length &lt; resolved.minLength)</span> <span class="cstat-no" title="statement not covered" >return false;</span>
1719
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (resolved.maxLength !== undefined &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >value.length &gt; resolved.maxLength)</span> <span class="cstat-no" title="statement not covered" >return false;</span>
1720
+ &nbsp;
1721
+ if (resolved.pattern !== undefined) {
1722
+ try {
1723
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!new RegExp(resolved.pattern).test(value)) <span class="cstat-no" title="statement not covered" >return false;</span>
1724
+ } catch {
1725
+ <span class="cstat-no" title="statement not covered" > return true;</span>
1726
+ }
1727
+ }
1728
+ &nbsp;
1729
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (type === "date" &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >!isIsoDateString(value))</span> {
1730
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1731
+ }
1732
+ &nbsp;
1733
+ return true;
1734
+ }
1735
+ &nbsp;
1736
+ if (type === "integer" || type === "double") {
1737
+ if (typeof value !== "number") {
1738
+ return false;
1739
+ }
1740
+ &nbsp;
1741
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (type === "integer" &amp;&amp; !Number.isInteger(value)) {
1742
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1743
+ }
1744
+ &nbsp;
1745
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (resolved.minimum !== undefined &amp;&amp; value &lt; resolved.minimum) <span class="cstat-no" title="statement not covered" >return false;</span>
1746
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (resolved.maximum !== undefined &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >value &gt; resolved.maximum)</span> <span class="cstat-no" title="statement not covered" >return false;</span>
1747
+ return true;
1748
+ }
1749
+ &nbsp;
1750
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (type === "object") {</span>
1751
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (typeof value !== "object" || value === null || Array.isArray(value)) {</span>
1752
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1753
+ }
1754
+ &nbsp;
1755
+ const objectValue = <span class="cstat-no" title="statement not covered" >value as Record&lt;string, unknown&gt;;</span>
1756
+ const properties = <span class="cstat-no" title="statement not covered" >resolved.properties;</span>
1757
+ const additionalProperties = <span class="cstat-no" title="statement not covered" >resolved.additionalProperties;</span>
1758
+ &nbsp;
1759
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if ((!properties || typeof properties !== "object") &amp;&amp; !additionalProperties) {</span>
1760
+ <span class="cstat-no" title="statement not covered" > return Object.values(objectValue).every(<span class="fstat-no" title="function not covered" >(e</span>ntry) =&gt; <span class="cstat-no" title="statement not covered" >isPrimitiveAttributeValue(entry))</span>;</span>
1761
+ }
1762
+ &nbsp;
1763
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (properties &amp;&amp; typeof properties === "object") {</span>
1764
+ const required = <span class="cstat-no" title="statement not covered" >new Set(resolved.required || []);</span>
1765
+ <span class="cstat-no" title="statement not covered" > for (const key of required) {</span>
1766
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!Object.prototype.hasOwnProperty.call(objectValue, key)) {</span>
1767
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1768
+ }
1769
+ }
1770
+ &nbsp;
1771
+ <span class="cstat-no" title="statement not covered" > for (const key of Object.keys(objectValue)) {</span>
1772
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (properties[key]) {</span>
1773
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!matchesSchemaValue(properties[key] as SchemaNode, objectValue[key], schemasByKey)) {</span>
1774
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1775
+ }
1776
+ <span class="cstat-no" title="statement not covered" > continue;</span>
1777
+ }
1778
+ &nbsp;
1779
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (additionalProperties &amp;&amp; typeof additionalProperties === "object") {</span>
1780
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (</span>
1781
+ !matchesSchemaValue(additionalProperties as SchemaNode, objectValue[key], schemasByKey)
1782
+ ) {
1783
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1784
+ }
1785
+ <span class="cstat-no" title="statement not covered" > continue;</span>
1786
+ }
1787
+ &nbsp;
1788
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1789
+ }
1790
+ &nbsp;
1791
+ <span class="cstat-no" title="statement not covered" > return true;</span>
1792
+ }
1793
+ &nbsp;
1794
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (additionalProperties &amp;&amp; typeof additionalProperties === "object") {</span>
1795
+ <span class="cstat-no" title="statement not covered" > return Object.values(objectValue).every(<span class="fstat-no" title="function not covered" >(e</span>ntry) =&gt;</span>
1796
+ <span class="cstat-no" title="statement not covered" > matchesSchemaValue(additionalProperties as SchemaNode, entry, schemasByKey),</span>
1797
+ );
1798
+ }
1799
+ &nbsp;
1800
+ <span class="cstat-no" title="statement not covered" > return true;</span>
1801
+ }
1802
+ &nbsp;
1803
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (type === "array") {</span>
1804
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!Array.isArray(value)) {</span>
1805
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1806
+ }
1807
+ &nbsp;
1808
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (resolved.minItems !== undefined &amp;&amp; value.length &lt; resolved.minItems) <span class="cstat-no" title="statement not covered" >return false;</span></span>
1809
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (resolved.maxItems !== undefined &amp;&amp; value.length &gt; resolved.maxItems) <span class="cstat-no" title="statement not covered" >return false;</span></span>
1810
+ &nbsp;
1811
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (resolved.uniqueItems) {</span>
1812
+ <span class="cstat-no" title="statement not covered" > for (let i = <span class="cstat-no" title="statement not covered" >0;</span> i &lt; value.length; i++) {</span>
1813
+ <span class="cstat-no" title="statement not covered" > for (let j = <span class="cstat-no" title="statement not covered" >i + 1;</span> j &lt; value.length; j++) {</span>
1814
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (valueDeepEqual(value[i], value[j])) <span class="cstat-no" title="statement not covered" >return false;</span></span>
1815
+ }
1816
+ }
1817
+ }
1818
+ &nbsp;
1819
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (!resolved.items || typeof resolved.items !== "object") {</span>
1820
+ <span class="cstat-no" title="statement not covered" > return value.every(<span class="fstat-no" title="function not covered" >(e</span>ntry) =&gt; <span class="cstat-no" title="statement not covered" >typeof entry === "string")</span>;</span>
1821
+ }
1822
+ &nbsp;
1823
+ <span class="cstat-no" title="statement not covered" > return value.every(<span class="fstat-no" title="function not covered" >(e</span>ntry) =&gt;</span>
1824
+ <span class="cstat-no" title="statement not covered" > matchesSchemaValue(resolved.items as SchemaNode, entry, schemasByKey),</span>
1825
+ );
1826
+ }
1827
+ &nbsp;
1828
+ <span class="cstat-no" title="statement not covered" > return true;</span>
1829
+ }
1830
+ &nbsp;
1831
+ function matchesLeafValue(
1832
+ leaf: ResolvedLeaf,
1833
+ value: unknown,
1834
+ schemasByKey: Record&lt;string, Schema&gt;,
1835
+ ): boolean {
1836
+ if (leaf.kind === "flat-object-property" || leaf.kind === "flat-array-item") {
1837
+ return leaf.kind === "flat-array-item"
1838
+ ? typeof value === "string"
1839
+ : isPrimitiveAttributeValue(value);
1840
+ }
1841
+ &nbsp;
1842
+ return matchesSchemaValue(leaf.schema, value, schemasByKey);
1843
+ }
1844
+ &nbsp;
1845
+ function getArrayItemLeaf(
1846
+ leaf: ResolvedLeaf,
1847
+ schemasByKey: Record&lt;string, Schema&gt;,
1848
+ ): ResolvedLeaf | null {
1849
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (leaf.kind !== "schema") {
1850
+ <span class="cstat-no" title="statement not covered" > return leaf.kind === "flat-array-item" ? leaf : null;</span>
1851
+ }
1852
+ &nbsp;
1853
+ const resolved = resolveSchemaRefs(leaf.schema, schemasByKey);
1854
+ <span class="missing-if-branch" title="if path not taken" >I</span>if ("oneOf" in resolved &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >Array.isArray(resolved.oneOf) </span>&amp;&amp; <span class="branch-2 cbranch-no" title="branch not covered" >resolved.oneOf.length &gt; 0)</span> {
1855
+ const itemLeaves = <span class="cstat-no" title="statement not covered" >resolved.oneOf</span>
1856
+ .map(<span class="fstat-no" title="function not covered" >(b</span>ranch) =&gt;
1857
+ <span class="cstat-no" title="statement not covered" > getArrayItemLeaf({ kind: "schema", schema: branch as SchemaNode }, schemasByKey),</span>
1858
+ )
1859
+ .filter(<span class="fstat-no" title="function not covered" >(i</span>tem): item is ResolvedLeaf =&gt; <span class="cstat-no" title="statement not covered" >item !== null)</span>;
1860
+ &nbsp;
1861
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (itemLeaves.length === 0) {</span>
1862
+ <span class="cstat-no" title="statement not covered" > return null;</span>
1863
+ }
1864
+ &nbsp;
1865
+ <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (itemLeaves.every(<span class="fstat-no" title="function not covered" >(i</span>tem) =&gt; <span class="cstat-no" title="statement not covered" >item.kind === "flat-array-item")</span>) {</span>
1866
+ <span class="cstat-no" title="statement not covered" > return { kind: "flat-array-item" };</span>
1867
+ }
1868
+ &nbsp;
1869
+ <span class="cstat-no" title="statement not covered" > return {</span>
1870
+ kind: "schema",
1871
+ schema: {
1872
+ oneOf: itemLeaves.map(<span class="fstat-no" title="function not covered" >(i</span>tem) =&gt;
1873
+ <span class="cstat-no" title="statement not covered" > item.kind === "schema" ? item.schema : ({ type: "string" } as AttributeProperty),</span>
1874
+ ),
1875
+ } as AttributeProperty,
1876
+ };
1877
+ }
1878
+ &nbsp;
1879
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!("type" in resolved) || resolved.type !== "array") {
1880
+ <span class="cstat-no" title="statement not covered" > return null;</span>
1881
+ }
1882
+ &nbsp;
1883
+ if ("items" in resolved &amp;&amp; resolved.items &amp;&amp; typeof resolved.items === "object") {
1884
+ return {
1885
+ kind: "schema",
1886
+ schema: resolveSchemaRefs(resolved.items as SchemaNode, schemasByKey),
1887
+ };
1888
+ }
1889
+ &nbsp;
1890
+ return { kind: "flat-array-item" };
1891
+ }
1892
+ &nbsp;
1893
+ function addIssue(
1894
+ context: z.RefinementCtx,
1895
+ message: string,
1896
+ path: (string | number)[] = ["value"],
1897
+ ): void {
1898
+ context.addIssue({
1899
+ code: z.ZodIssueCode.custom,
1900
+ message,
1901
+ path,
1902
+ });
1903
+ }
1904
+ &nbsp;
1905
+ function validateAttributeAwareCondition(
1906
+ data: {
1907
+ attribute: string;
1908
+ operator: string;
1909
+ value?: unknown;
1910
+ regexFlags?: string;
1911
+ },
1912
+ context: z.RefinementCtx,
1913
+ attributesByKey: Record&lt;string, Attribute&gt;,
1914
+ schemasByKey: Record&lt;string, Schema&gt;,
1915
+ ): void {
1916
+ const resolvedLeaf = resolveAttributePath(data.attribute, attributesByKey, schemasByKey);
1917
+ if (!resolvedLeaf) {
1918
+ return;
1919
+ }
1920
+ &nbsp;
1921
+ const leafType = getLeafType(resolvedLeaf);
1922
+ const leafTypes = getLeafTypes(resolvedLeaf, schemasByKey);
1923
+ &nbsp;
1924
+ if (operatorsWithoutValue.includes(data.operator)) {
1925
+ return;
1926
+ }
1927
+ &nbsp;
1928
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (resolvedLeaf.kind === "schema" &amp;&amp; leafType === "object") {
1929
+ <span class="cstat-no" title="statement not covered" > addIssue(</span>
1930
+ context,
1931
+ `Attribute "${data.attribute}" resolves to an object. Use a nested attribute path or \`exists\`/\`notExists\` instead.`,
1932
+ );
1933
+ <span class="cstat-no" title="statement not covered" > return;</span>
1934
+ }
1935
+ &nbsp;
1936
+ if (
1937
+ numericOperators.includes(data.operator) &amp;&amp;
1938
+ !leafTypes.some((type) =&gt; ["integer", "double"].includes(type))
1939
+ ) {
1940
+ addIssue(
1941
+ context,
1942
+ `Operator "${data.operator}" can only be used with integer or double attributes.`,
1943
+ );
1944
+ return;
1945
+ }
1946
+ &nbsp;
1947
+ if (
1948
+ stringOperators.includes(data.operator) &amp;&amp;
1949
+ !leafTypes.some((type) =&gt; ["string", "semver", "date"].includes(type))
1950
+ ) {
1951
+ addIssue(context, `Operator "${data.operator}" can only be used with string-like attributes.`);
1952
+ return;
1953
+ }
1954
+ &nbsp;
1955
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (
1956
+ semverOperators.includes(data.operator) &amp;&amp;
1957
+ !leafTypes.some((type) =&gt; ["string", "semver"].includes(type))
1958
+ ) {
1959
+ <span class="cstat-no" title="statement not covered" > addIssue(</span>
1960
+ context,
1961
+ `Operator "${data.operator}" can only be used with string or semver attributes.`,
1962
+ );
1963
+ <span class="cstat-no" title="statement not covered" > return;</span>
1964
+ }
1965
+ &nbsp;
1966
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (
1967
+ dateOperators.includes(data.operator) &amp;&amp;
1968
+ !leafTypes.some((type) =&gt; ["string", "date"].includes(type))
1969
+ ) {
1970
+ <span class="cstat-no" title="statement not covered" > addIssue(</span>
1971
+ context,
1972
+ `Operator "${data.operator}" can only be used with string or date attributes.`,
1973
+ );
1974
+ <span class="cstat-no" title="statement not covered" > return;</span>
1975
+ }
1976
+ &nbsp;
1977
+ if (arrayMembershipOperators.includes(data.operator)) {
1978
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (
1979
+ !["primitive", "string", "semver", "date", "integer", "double", "boolean"].includes(
1980
+ leafType || <span class="branch-1 cbranch-no" title="branch not covered" >"",</span>
1981
+ )
1982
+ ) {
1983
+ <span class="cstat-no" title="statement not covered" > addIssue(</span>
1984
+ context,
1985
+ `Operator "${data.operator}" can only be used with primitive attribute values.`,
1986
+ );
1987
+ <span class="cstat-no" title="statement not covered" > return;</span>
1988
+ }
1989
+ &nbsp;
1990
+ if (!Array.isArray(data.value)) {
1991
+ return;
1992
+ }
1993
+ &nbsp;
1994
+ data.value.forEach((entry, index) =&gt; {
1995
+ if (!matchesLeafValue(resolvedLeaf, entry, schemasByKey)) {
1996
+ addIssue(
1997
+ context,
1998
+ `Value at index ${index} does not match the schema of attribute "${data.attribute}".`,
1999
+ ["value", index],
2000
+ );
2001
+ }
2002
+ });
2003
+ &nbsp;
2004
+ return;
2005
+ }
2006
+ &nbsp;
2007
+ if (arrayOperators.includes(data.operator)) {
2008
+ const itemLeaf = getArrayItemLeaf(resolvedLeaf, schemasByKey);
2009
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!itemLeaf) {
2010
+ <span class="cstat-no" title="statement not covered" > addIssue(context, `Operator "${data.operator}" can only be used with array attributes.`);</span>
2011
+ <span class="cstat-no" title="statement not covered" > return;</span>
2012
+ }
2013
+ &nbsp;
2014
+ const itemType = getLeafType(itemLeaf);
2015
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (itemType === "object" || itemType === "array") {
2016
+ <span class="cstat-no" title="statement not covered" > addIssue(context, `Operator "${data.operator}" only supports arrays of primitive values.`);</span>
2017
+ <span class="cstat-no" title="statement not covered" > return;</span>
2018
+ }
2019
+ &nbsp;
2020
+ if (!matchesLeafValue(itemLeaf, data.value, schemasByKey)) {
2021
+ addIssue(context, `Value does not match the item schema of attribute "${data.attribute}".`);
2022
+ }
2023
+ &nbsp;
2024
+ return;
2025
+ }
2026
+ &nbsp;
2027
+ if (commonOperators.includes(data.operator)) {
2028
+ if (data.value === null) {
2029
+ return;
2030
+ }
2031
+ &nbsp;
2032
+ if (!matchesLeafValue(resolvedLeaf, data.value, schemasByKey)) {
2033
+ addIssue(context, `Value does not match the schema of attribute "${data.attribute}".`);
2034
+ }
2035
+ }
2036
+ }
2037
+ &nbsp;
559
2038
  export function getConditionsZodSchema(
560
2039
  projectConfig: ProjectConfig,
561
- availableAttributeKeys: [string, ...string[]],
2040
+ attributesByKey: Record&lt;string, Attribute&gt;,
2041
+ schemasByKey: Record&lt;string, Schema&gt; = {},
562
2042
  ) {
563
2043
  const plainConditionZodSchema = z
564
2044
  .object({
565
2045
  attribute: z.string().refine(
566
- (value) =&gt; availableAttributeKeys.includes(value),
2046
+ (value) =&gt; resolveAttributePath(value, attributesByKey, schemasByKey) !== null,
567
2047
  (value) =&gt; ({
568
2048
  message: `Unknown attribute "${value}"`,
569
2049
  }),
@@ -574,8 +2054,8 @@ export function getConditionsZodSchema(
574
2054
  ...stringOperators,
575
2055
  ...semverOperators,
576
2056
  ...dateOperators,
2057
+ ...arrayMembershipOperators,
577
2058
  ...arrayOperators,
578
- ...regexOperators,
579
2059
  ...operatorsWithoutValue,
580
2060
  ]),
581
2061
  value: z
@@ -598,7 +2078,6 @@ export function getConditionsZodSchema(
598
2078
  .optional(),
599
2079
  })
600
2080
  .superRefine((data, context) =&gt; {
601
- // common
602
2081
  if (
603
2082
  commonOperators.includes(data.operator) &amp;&amp;
604
2083
  !(
@@ -610,117 +2089,90 @@ export function getConditionsZodSchema(
610
2089
  data.value === null
611
2090
  )
612
2091
  ) {
613
- context.addIssue({
614
- code: z.ZodIssueCode.custom,
615
- message: `when operator is "${data.operator}", value has to be either a string, number, boolean, date or null`,
616
- path: ["value"],
617
- });
618
- }
619
- &nbsp;
620
- // numeric
621
- if (numericOperators.includes(data.operator) &amp;&amp; typeof data.value !== "number") {
622
- context.addIssue({
623
- code: z.ZodIssueCode.custom,
624
- message: `when operator is "${data.operator}", value must be a number`,
625
- path: ["value"],
626
- });
2092
+ addIssue(
2093
+ context,
2094
+ `when operator is "${data.operator}", value has to be either a string, number, boolean, date or null`,
2095
+ );
627
2096
  }
628
2097
  &nbsp;
629
- // string
630
- if (stringOperators.includes(data.operator) &amp;&amp; typeof data.value !== "string") {
631
- context.addIssue({
632
- code: z.ZodIssueCode.custom,
633
- message: `when operator is "${data.operator}", value must be a string`,
634
- path: ["value"],
635
- });
2098
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (numericOperators.includes(data.operator) &amp;&amp; typeof data.value !== "number") {
2099
+ <span class="cstat-no" title="statement not covered" > addIssue(context, `when operator is "${data.operator}", value must be a number`);</span>
636
2100
  }
637
2101
  &nbsp;
638
- // semver
639
- <span class="missing-if-branch" title="if path not taken" >I</span>if (semverOperators.includes(data.operator) &amp;&amp; typeof data.value !== "string") {
640
- <span class="cstat-no" title="statement not covered" > context.addIssue({</span>
641
- code: z.ZodIssueCode.custom,
642
- message: `when operator is "${data.operator}", value must be a string`,
643
- path: ["value"],
644
- });
2102
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (
2103
+ [...stringOperators, ...semverOperators].includes(data.operator) &amp;&amp;
2104
+ typeof data.value !== "string"
2105
+ ) {
2106
+ <span class="cstat-no" title="statement not covered" > addIssue(context, `when operator is "${data.operator}", value must be a string`);</span>
645
2107
  }
646
2108
  &nbsp;
647
- // date
648
2109
  if (dateOperators.includes(data.operator)) {
649
- // Value is required and must not be undefined or null
650
- if (typeof data.value === "undefined" || data.value === null || data.value === "") {
651
- context.addIssue({
652
- code: z.ZodIssueCode.custom,
653
- message: `when operator is "${data.operator}", value must be provided`,
654
- path: ["value"],
655
- });
2110
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (typeof data.value === "undefined" || data.value === null || data.value === "") {
2111
+ <span class="cstat-no" title="statement not covered" > addIssue(context, `when operator is "${data.operator}", value must be provided`);</span>
656
2112
  } else if (typeof data.value === "string") {
657
- // If it's a string, must be valid ISO 8601
658
2113
  if (!isIsoDateString(data.value)) {
659
- context.addIssue({
660
- code: z.ZodIssueCode.custom,
661
- message: `when operator is "${data.operator}", value must be a stringified date in ISO 8601 format`,
662
- path: ["value"],
663
- });
664
- } else {
665
- // valid ISO 8601 string -- no issue
2114
+ addIssue(
2115
+ context,
2116
+ `when operator is "${data.operator}", value must be a stringified date in ISO 8601 format`,
2117
+ );
666
2118
  }
667
2119
  } else <span class="cstat-no" title="statement not covered" ><span class="missing-if-branch" title="else path not taken" >E</span>if (data.value instanceof Date) {</span>
668
- // If it's a Date, must be valid
669
2120
  <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (isNaN(data.value.getTime())) {</span>
670
- <span class="cstat-no" title="statement not covered" > context.addIssue({</span>
671
- code: z.ZodIssueCode.custom,
672
- message: `when operator is "${data.operator}", value is a Date but invalid`,
673
- path: ["value"],
674
- });
2121
+ <span class="cstat-no" title="statement not covered" > addIssue(context, `when operator is "${data.operator}", value is a Date but invalid`);</span>
675
2122
  }
676
- // Valid JS Date -- no issue
677
2123
  } else {
678
- // NOT a string, NOT a Date
679
- <span class="cstat-no" title="statement not covered" > context.addIssue({</span>
680
- code: z.ZodIssueCode.custom,
681
- message: `when operator is "${data.operator}", value must be a stringified date in ISO 8601 format or a valid Date object`,
682
- path: ["value"],
683
- });
2124
+ <span class="cstat-no" title="statement not covered" > addIssue(</span>
2125
+ context,
2126
+ `when operator is "${data.operator}", value must be a stringified date in ISO 8601 format or a valid Date object`,
2127
+ );
684
2128
  }
685
2129
  }
686
2130
  &nbsp;
687
- // array
688
- if (arrayOperators.includes(data.operator) &amp;&amp; !Array.isArray(data.value)) {
689
- context.addIssue({
690
- code: z.ZodIssueCode.custom,
691
- message: `when operator is "${data.operator}", value must be an array of strings`,
692
- path: ["value"],
693
- });
2131
+ if (arrayMembershipOperators.includes(data.operator) &amp;&amp; !Array.isArray(data.value)) {
2132
+ addIssue(context, `when operator is "${data.operator}", value must be an array of strings`);
694
2133
  }
695
2134
  &nbsp;
696
- // regex
697
- if (regexOperators.includes(data.operator)) {
698
- <span class="missing-if-branch" title="if path not taken" >I</span>if (typeof data.value !== "string") {
699
- <span class="cstat-no" title="statement not covered" > context.addIssue({</span>
700
- code: z.ZodIssueCode.custom,
701
- message: `when operator is "${data.operator}", value must be a string`,
702
- path: ["value"],
703
- });
2135
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (
2136
+ arrayMembershipOperators.includes(data.operator) &amp;&amp;
2137
+ Array.isArray(data.value) &amp;&amp;
2138
+ !isStringArray(data.value)
2139
+ ) {
2140
+ <span class="cstat-no" title="statement not covered" > addIssue(context, `when operator is "${data.operator}", value must be an array of strings`);</span>
2141
+ }
2142
+ &nbsp;
2143
+ if (!arrayMembershipOperators.includes(data.operator) &amp;&amp; Array.isArray(data.value)) {
2144
+ if (!["in", "notIn"].includes(data.operator)) {
2145
+ addIssue(context, `when operator is "${data.operator}", value must not be an array`);
704
2146
  }
705
- } else {
706
- // regex flags are not needed
707
- if (data.regexFlags) {
708
- context.addIssue({
709
- code: z.ZodIssueCode.custom,
710
- message: `when operator is nether "matches" nor "notMatches", regexFlags are not needed`,
711
- path: ["regexFlags"],
712
- });
2147
+ }
2148
+ &nbsp;
2149
+ if (regexFlagsRequired(data.operator)) {
2150
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (typeof data.value !== "string") {
2151
+ <span class="cstat-no" title="statement not covered" > addIssue(context, `when operator is "${data.operator}", value must be a string`);</span>
713
2152
  }
2153
+ } else if (data.regexFlags) {
2154
+ addIssue(
2155
+ context,
2156
+ `when operator is nether "matches" nor "notMatches", regexFlags are not needed`,
2157
+ ["regexFlags"],
2158
+ );
714
2159
  }
715
2160
  &nbsp;
716
- // operators without value
717
2161
  if (operatorsWithoutValue.includes(data.operator) &amp;&amp; data.value !== undefined) {
718
- context.addIssue({
719
- code: z.ZodIssueCode.custom,
720
- message: `when operator is "${data.operator}", value is not needed`,
721
- path: ["value"],
722
- });
2162
+ addIssue(context, `when operator is "${data.operator}", value is not needed`);
723
2163
  }
2164
+ &nbsp;
2165
+ validateAttributeAwareCondition(
2166
+ data as {
2167
+ attribute: string;
2168
+ operator: string;
2169
+ value?: unknown;
2170
+ regexFlags?: string;
2171
+ },
2172
+ context,
2173
+ attributesByKey,
2174
+ schemasByKey,
2175
+ );
724
2176
  });
725
2177
  &nbsp;
726
2178
  const andOrNotConditionZodSchema = z.union([
@@ -742,16 +2194,13 @@ export function getConditionsZodSchema(
742
2194
  ]);
743
2195
  &nbsp;
744
2196
  const everyoneZodSchema = z.literal("*");
745
- &nbsp;
746
2197
  const conditionZodSchema = z.union([andOrNotConditionZodSchema, plainConditionZodSchema]);
747
2198
  &nbsp;
748
- const conditionsZodSchema = z.union([
749
- conditionZodSchema,
750
- z.array(conditionZodSchema),
751
- everyoneZodSchema,
752
- ]);
2199
+ return z.union([conditionZodSchema, z.array(conditionZodSchema), everyoneZodSchema]);
2200
+ }
753
2201
  &nbsp;
754
- return conditionsZodSchema;
2202
+ function regexFlagsRequired(operator: string): boolean {
2203
+ return operator === "matches" || operator === "notMatches";
755
2204
  }
756
2205
  &nbsp;</pre></td></tr></table></pre>
757
2206
 
@@ -760,7 +2209,7 @@ export function getConditionsZodSchema(
760
2209
  <div class='footer quiet pad2 space-top1 center small'>
761
2210
  Code coverage generated by
762
2211
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
763
- at 2026-03-01T23:08:13.696Z
2212
+ at 2026-04-08T20:42:08.360Z
764
2213
  </div>
765
2214
  <script src="../prettify.js"></script>
766
2215
  <script>